Customization vs. Extension

Introduction

Developing ISD applications is all about customization, customization and customization. Some customizations are project specific, while others are of generic purpose, which can be used across multiple projects. Below are some examples of general purpose customizations.

This article is about how to better manage general purpose customizations.

Background

A trick for general purpose customization is to put the code in ISD’s project template folder. When ISD generates a new project, the customization is automatically available. You don’t have to manually cut and paste the customization from a previous project. An ideal example of code reuse, isn’t it? Nope. It is cut-and-paste in disguise. Although ISD does the cut-and-paste for you, you are left to deal with the consequence of having multiple copies of the same code, a maintenance headache.

Take the Roaming Alert as an example. I put it in ISD’s project template, so it became a standard feature in all of my projects. After implemented it in more than 10 projects, however, I found a bug in the original implementation. The  BaseClasses.Utils.MiscUtils.RegisterJScriptAlert() method did not handle multi-line message correctly. I had to replace it with my own method. For all the previous projects, I had to go over their life cycles (development, staging, production) all over again, because the modification was at the source code level.

Solution? Do not customize ISD projects. Extend them.

Solution

To customize, insert your code directly into ISD generated projects so that
you get customized ones. To extend, keep your code outside of ISD projects so that they are extended. The following diagram illustrates the difference between customization and extension.

Implementation

Here is a sample implementation of the extension BasePage.

using System;
using System.Collections.Generic;
using System.Web.UI;

namespace DingJing {
  public class BasePage : BaseClasses.Web.UI.BasePage {

    public BasePage() {
      PreRender +=  new EventHandler(My_PreRender);
    }

    void My_PreRender(object sender, EventArgs e) {
      Dictionary<stringstring> AlertQueue =
        Session["AlertQueue"as Dictionary<stringstring>;
      if (AlertQueue != null) {
        foreach (string key in AlertQueue.Keys)
          DisplayAlert(key, AlertQueue[key]);
        AlertQueue.Clear();
      }
    }

    private void DisplayAlert(string key, string msg) {
      msg = msg.Replace(@"\"@"\\").Replace("'"@"\'").Replace("\n"@"\n");
      string script = string.Format("alert('{0}');", msg);
      ScriptManager.RegisterStartupScript(this, GetType(), key, script, true);
    }

    public virtual void RegisterAlert(string key, string msg, bool roaming) {
      if (!roaming) {
        DisplayAlert(key, msg);
      } else {
        Dictionary<stringstring> AlertQueue =
          Session["AlertQueue"as Dictionary<stringstring>;
        if (AlertQueue == null)
          Session["AlertQueue"] = AlertQueue = new Dictionary<stringstring>();
        AlertQueue.Add(key, msg);
      }
    }

  }
}

Then, make your project's BaseApplicationPage a subclass of the extension BasePage.

namespace ProjectNamespace.UI {
  public class BaseApplicationPage : DingJing.BasePage {

You can make the class hierarchy change in generated projects, or in ISD project template. You can extend BaseApplicationTableControl and BaseApplicationRecordControl similarily.

using System.Web.UI;

namespace DingJing {
  public class BaseTableControl : System.Web.UI.Control {

    public void SetColumnVisibility(string colName, bool visible) {
      Control header = FindControl(colName + "Header");
      if (header != null)
        header.Visible = visible;

      Control[] rows = GetType().GetMethod("GetRecordControls").Invoke(thisnullas Control[];
      foreach (Control row in rows) {
        Control cell = row.FindControl(colName + "Cell");
        if (cell != null)
          cell.Visible = visible;
      }
    }

  }
}
namespace ProjectNamespace.UI {
  public class BaseApplicationTableControl : DingJing.BaseTableControl {
using System.Linq;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace DingJing {
  public class BaseRecordControl : System.Web.UI.Control {

    public void SetRowAppearance(string cssName) {
      WebControl ctrl = Controls
        .OfType<WebControl>()
        .Where(c => !(c is Literal) && c.Visible)
        .First();
      string script = string.Format(
        "$('td', $('#{0}').closest('tr')).addClass('{1}');",
        ctrl.ClientID,
        cssName);
      ScriptManager.RegisterStartupScript(this, GetType(), ClientID, script, true);
    }

  }
}
namespace ProjectNamespace.UI {
  public class BaseApplicationRecordControl : DingJing.BaseRecordControl {

Benefit

First, maintenance overhead is greatly reduced. You have only one copy of the source code to maintain. Other projects only need to update their reference if there is any changes. If they are already deployed to production, you only need to copy over one dll file.

Second, I no longer have to post my code samples in 2 languages. Even if your main ISD project is in VB, you can still reference libraries written in C#. If you are a consultant developing projects for different clients using different languages, this is also for you.

Conclusion

For general purpose customizations, refactoring them into a separate project will greatly reduce maintenance overhead.

About the Author

Jing Ding has a PhD in Computer Engineering, Bioinformatics and Computational Biology, and an M.S. in Toxicology from Iowa State University. He received his B.S. in biophysics from Fundan University in Shanghai, China. He is a self-taught programmer who "played" with assembly, C and C++ in the 1990s. He took a break from programming from 1997 to 2000. When he picked it up again in 2001, he worked with Java. Jing began working with C# and .NET in 2006.

About these ads

One Response to “Customization vs. Extension”

  1. Haakon Dahl Says:

    This is an OUTSTANDING post! The whole reason I use ISD is that I can’t be bothered to do boring things. I have scrupulously avoided learning how to customize, because it felt very cut & paste, but I couldn’t tell you why. Now I know. Your post just made it very much indeed worth my time and effort to learn how to extend via separate projects (like a template library).
    Thank you for your illuminating post!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.

%d bloggers like this: