The conception, birth, and first steps of an application named Charlie

Subscribe: Atom or RSS

Think Big

by Alister Jones (SomeNewKid)

I made a mistake by thinking small. But I learned a lesson that I would like to share.

I was looking at the feature set for Charlie, and I came to the following item:

  • allow for different document types (webpage, PDF, Word, RSS, etc.)

It occurred to me that I should get this flexibility in place. Otherwise, I would flesh out Charlie’s ability to serve webpages, and then have to retrofit the flexibility to serve other types of responses. And if there is one thing I have learned so far, it is to get flexibility in place as early as possible.

The only article I have ever read on serving different response types is One Site, Many Faces. It is a great article, wherein the author details how you can have one HttpHandler for each response type that your website is to serve. So, you’d have one TextHandler, one RssHandler, and so on. But the article does have a notable limitation. The limitation is perfectly acceptable, since it kept the article to a reasonable length. But the limitation would have manifested itself in Charlie. The limitation in the article is that each handler knows exactly what business object it is to present, which is an Article. The Article business object looks roughly like this:

public class Article
{
    public String Title;
    public String Body;
    public String Writer;
}

Because each handler knows exactly what business object it is to serve, the code to do so is very simple. Here is a snippet of how the TextHandler might look:

public class TextHandler
{
    public void PrepareResponse(Article article)
    {
        String response;
        response  = article.Title + NewLine;
        response += article.Writer + NewLine;
        response += article.Body;
        SendResponse(response);
    }
}

And here is a snippet of how the RssHandler might look:

public class RssHandler
{
    public void PrepareResponse(Article article)
    {
        String response;
        response  = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>";
        response += "<rss>";
        response += "   <title>" + article.Title + "</title>";
        response += "   <author>" + article.Writer + "</author>";
        response += "   <description>" + article.Body + "</description>";
        response += "</rss>";
        SendResponse(response);
    }
}

So, by working with a single, known business object (an Article), each of the separate Handlers were kept simple, and the website is able to serve the same article in many different ways.

The problem I faced was how to overcome this limitation of a single, known business object? To illustrate the problem, we can consider just two separate business objects, an Article and a Weblog.

public class Article            public class Weblog
{                               {
    public String Title;            public String Subject;
    public String Body;             public String Entry;
    public String Writer;           public Int32  BloggerId;
}                               }

What you will see is that the two separate business objects do not share a single property. So, the above TextHandler and RssHandler could not work with a Weblog business object. In theory I could have introduced a new set of handlers for every new business object, so that I’d end up with an ArticleTextHandler and ArticleRssHandler, and a WeblogTextHandler and WeblogRssHandler. That would work, but that’s not flexibility, that’complexity. Instead, it would more flexible if I introduced an interface that defined what sort of object could be presented by the TextHandler, and what sort of object could be presented by the RssHandler. Looking just at the RssHandler, here is how that interface might look.

public interface IRssItem
{
    String Title;
    String Author;
    String Description;
}

With that interface in place, we can update the RssHandler to look like this:

public class RssHandler
{
    public void PrepareResponse(IRssItem item)
    {
        String response;
        response  = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>";
        response += "<rss>";
        response += "   <title>" + item.Title + "</title>";
        response += "   <author>" + item.Author + "</author>";
        response += "   <description>"+item.Description+"</description>";
        response += "</rss>";
        SendResponse(response);
    }
}

This interface means that the RssHandler can now work with any business object that implements the IRssItem interface. By using interfaces this way, I could give Charlie one TextHandler, one RssHandler, one AtomHandler, and so on. And these handlers could work with any business object, so long as that business object implemented the required interface. This was the sort of flexibility I was looking for.

But here is where I made a mistake in my approach to this problem. By looking at and thinking about the code I have just shown you, my thoughts were down at the “small” details. Namely, I started thinking about how I could update the business objects so that they each presented the same IRssItem interface. Here again are the business objects in question:

public class Article            public class Weblog
{                               {
    public String Title;            public String Subject;
    public String Body;             public String Entry;
    public String Writer;           public Int32  BloggerId;
}                               }

The straight forward approach would be to implement that interface directly in each business object:

public class Article            public class Weblog
    : IRssItem                      : IRssItem 
{                               {
    public String Title;            public String Subject;
    public String Body;             public String Entry;
    public String Writer;           public Int32  BloggerId;
    
    IRssItem.Title                  IRssItem.Title
      { return this.Title }           { return this.Subject }
    IRssItem.Author                 IRssItem.Author
      { return this.Writer }          { return GetName(this.BloggerId) }
    IRssItem.Description            IRssItem.Description
      { return this.Body }            { return this.Entry }
}                               }

I only had to think about that for a few seconds before I realized that that was not an option at all. Each time I introduced a new handler and interface, I’d have to go in and change every business object that wanted to be presented by that handler. That too is not flexibility, that’s complexity.

I will admit that I banged about for nearly four hours trying to think of different solutions. The reason that I struggled for so long was that I was thinking about the small details. It was only when I went for a drive (I’ve crashed my motorbike) that I started thinking big, and a solution occurred to me.

Because I was driving and could not write down the code for a business object, I visualised each business object as a box. And because the Article business object and the Weblog business object have different properties, they expose different interfaces.

I then pictured the RssHandler as being a box, which has a defined IRssItem interface for any business object that it is to display.

The problem to be solved then was how can vastly different business objects, each exposing a different interface, be made acceptable to the RssHandler which requires each business object to expose the defined IRssItem Interface? The following picture formed in my mind:

Once that picture formed in my mind, the solution became obvious. I needed an adapter from the Adapter Pattern.

By using an adapter, I never needed to change the business objects in any way whatsoever. Even better, a given business object could be made to plug into any different type of handler. Putting the Weblog business object to one side, let’s see how the Article business object can be made to work with any and every handler, including its own specialised ArticleHandler, again without having to change the business object in any way.

So, using the code examples above, what would the ArticleRssAdapter look like?

public class ArticleRssAdapter : IRssItem
{
    public ArticleRssAdapter(Article article)
    {
        this.article = article;
    }
    private Article article;
    
    public String IRssItem.Title
    {
        get 
        { 
            return article.Title; 
        }
    }

    public String IRssItem.Author
    {
        get 
        {
            return article.Writer; 
        }
    }

    public String IRssItem.Description
    {
        get 
        { 
            return article.Body; 
        }
    }
}

You will see that this code is extremely simple. But even though it is simple, the use of adapters means that any business object can be made to work with any handler object. This is infinitely flexible.

The end solution is so simple that I really should have seen it. But, I was thinking small, and looking at the code. I was not thinking big, and looking at the objects. So that’s the lesson for today kids: think big.

by Alister Jones | Next up: Charlie’s Birth

0 comments

----