The Role Of The Model in Silverlight, GWT and Javascript

Introduction

When people start developing RIA’s in environments such as Silverlight, GWT, Flex and plain JavaScript, they often write asynchronous communication callbacks in an unstructured manner, putting them wherever is convenient — often in an instance member of a user interface component (Silverlight and GWT) or in a closure or global function (JavaScript.)

Several problems almost invariably occur as applications become more complex that force the development of an architecture that decouples communication event handlers from the user interface: a straightforward solution is to create a model layer that’s responsible for notifying interested user interface components about data updates.

This article uses a simple example application to show how a first-generation approach to data updates breaks down and how introducing a model-view split makes for a reliable and maintainable application.

(This is one of a series of articles on RIA architecture: subscribe to the Gen5 RSS feed for future installments.)

Example Application: Blogging And The Category Dropdown

Imagine a blogging application that works like the WordPress blog used on this site. This application consists of a number of forms, one of which is used to write a new post:

This form lets you fill out two text fields: a title and the body of the post. It also contains a dropdown list of categories, and gives you the option of adding a new category. Categories are represented (server-side) in a table in a relational database that looks like:

[01] CREATE TABLE categoryList (
[02]     id                 integer primary key auto_increment,
[03]     name               varchar(255)
[04] );

Adding a category to the database requires a call to the server that adds a row to the database and returns the new category list, which is then used to update the dropdown list. I’ll show you samples of the app in a pseudocode in an imaginary environment which combines the best of Silverlight and GWT. First we initialize the form and set an event handler that’s called when somebody clicks on the AddCategoryButton:

[05] class CreatePostForm {
[06]    protected TextBox Title;
[07]    protected ListBox Category;
[08]    protected TextBox AddCategoryName;
[09]    protected Button  AddCategoryButton;
[10]    protected RichTextArea Body;
[11]    protected Button  Submit;
[12]
[13]    public CreatePostForm() {
[14]        ... initialize and lay out UI elements ...
[15]
[16]        AddCategoryButton.OnClick += AddCategoryButton_OnClick;
[17]
[18]        ... finish construction ...
[19]    }

Leaving out error handling and other details, the job of the event handler is to pass the name of the new category to the server. The event handler is defined as an instance method of CreatePostForm:

[20]    protected void AddCategoryButton_OnClick {
[21]        Server.Instance.AddCategory(AddCategoryName.Text,AddCategory_Completed)
[22]    }

The AddCategory RPC call is defined on a Singleton called Server, and takes two arguments: (1) a string with the name of the new category, and (2) a reference to to the callback function that gets called when the RPC call is complete. The callback, AddCategory_Completed, is also an instance method:

[23]     protected void AddCategory_Completed(List<ListBoxItem> items) {
[24]            Category.Items = items;
[25]     }

ListBoxItem is a class that represents a single row in a ListBox, which has properties ListBox.Id and ListBox.Name. This is simple and straightforward code, and it ought to maintainable, right?

Let’s see

The Naive Implementation Adapts

Well, when we finish writing the class, we notice the first problem – a minor problem. There are two buttons on the form, so we need two event handlers and two callback functions. As a UI class gets complicated, it can accumulate quite a few callback functions, and it can get tricky keeping track of them all. Careful naming, code organization, and the use of #region in C# can help organize the code, but it’s easy to build UI controls that have tens of methods in which we can get lost.

Over time, we’ll add more forms to the app, and pretty soon we’ll add another form that has a category list: perhaps this a form used by administrators to search for posts: let’s call it AdminSearchForm. AdminSearchForm also contains a Listbox called Category. It’s a protected field of AdminSearchForm, but we need to update it when the administrator adds a new category. It seems reasonable to add a public method to AdminSearchForm

[26] public class AdminSearchForm {
[27]     ...
[28]     protected ListBox Categories;
[29]     ...
[30]     public void UpdateCategoryList(List<ListBoxItem> items) {
[31]       Categories.Items=items;
[32]     }
[33] }

Now we update the AddCategory_Completed function so it updates the AdminSearchForm:

[34] public class CreatePostForm {
[35]    ...
[36]    protected void AddCategory_Completed(List<ListBoxItems> items) {
[37]       Categories.Items=items;
[38]       App.Instance.MainTabPanel.AdminSearchForm.UpdateCategoryList(items);
[39]    }
[40] }

Not too bad, eh? just four more lines of transparent code to update AdminSearchForm, even if line [38] has a rather ugly coupling to the detailed structure of the application.

The Naive Implementation Breaks Down

Over the next few weeks, we add a few more dropdown lists to the application, we keep doing the same thing, and it’s fine for a while. Then we start running into problems:

  1. We can’t reuse CreatePostForm to make different versions of the application, because it contains a hard-coded list of all the dropdown lists in the application.
  2. We can’t update the contents of a category list that it’s a dynamically generated UI element, such as a dialog box, a draggable representation of an item, a search result listing, or an application plug-in.
  3. You need to consider how all of these dropdown lists get initialized when the application starts (something this code sample doesn’t show.)
  4. At some point you need to add a second way that a user can add a category (for instance, the “Manage Categories” screen in WordPress) — at that point you can (a) duplicate the code in AddCategory_Completed (bad idea!), (b) have the ManageCategoriesForm class call the AddCategory_Completed method of CreatePostForm (better) or (c) move CreatePostForm someplace else. (best)
  5. If UI components were responsible for communicating with the server to update themselves, performance could be destroyed by unnecessary communications, with no guarantee that UI components would be updated consistently.

I’m sorry to admit that, when I built my first GWT app, I ran into all of the above problems, plus a number of others. I tried a number of ad hoc solutions until I was forced to sit down and develop an architecture (the one below) that doesn’t run out of steam. Today, you can do better.

Separating the Model And The View

Ok, the plan is to create two classes: CategoryList and CategoryListBox that work together to solve the problem of updating CategoryList boxes. CategoryList is a singleton: it keeps track of the current state of the category list and keeps a list of clients that need to know when the list is updated.

The code for CategoryList looks like:

[41] public class CategoryList {
[42]    private static CategoryList _Instance;
[43]    public static CategoryList Instance {
[44]       get {
[45]           if (_Instance==null)
[46]              _Instance=new CategoryList();
[47]
[48]           return _Instance;
[49]       }
[50]    }
[51]
[52]    private List<ListBoxItems> Items {get; set;}
[53]    private List<ICategoryListener> Listeners;
[54]    private CategoryList() { ... construct ...};

Java programmers might notice a few C#-isms here, in particular the way the class defines a static property called Instance that other classes use. We don’t, however, use the C# event mechanism, because it doesn’t do exactly what we want to do.

We call UpdateItems when there’s a change in the category list, or when we initialize the category list when the application starts. UpdateItems as an ordinary method, although a C# stylist might probably make the Items property public and put the following logic in the setter:

[55]   public void UpdateItems(List<ListBoxItems> items) {
[56]      Items=items;
[57]      foreach(var l in Listeners) {
[58]         l.UpdateItems(Items);
[59]      }
[60]   }

CategoryListBoxes will register and unregister themselves with the CategoryList with the following methods:

[61]    public AddListener(ICategoryListener l) {
[62]       Listeners.Add(l);
[63]       l.UpdateItems(Items);
[64]    }
[65]    public RemoveListener(ICategoryListener l) {
[66]       Listeners.Remove(l);
[67]    }
[68] }

Note that we could have built all of this logic into the CategoryListBox, but by introducing the CategoryList class and the ICategoryListener interface, we’ve decoupled the model from the view, and given ourselves the option to create new visual representations of the category list. (WordPress, for instance has a distinct representation of the category list on the “Manage Category” screens and more than one way you can show a category list to your viewers.)

An interesting point is that AddListener immediately updates the listener when it registers itself. This is a pattern that handles asynchronous initialization: so long as the Items property starts out as something harmless, ICategoryListeners formed before app initialization is completed will be initialized when the application initialization code calls UpdateItems. If an ICategoryListener is created later, it gets initialized upon registration — either way you’re covered without having to think about it.

Let’s take a look at the CategoryListBox, which extends ListBox and implements ICategoryListener.

[70] public CategoryListBox: ListBox, ICategoryListener {

It implements ICategoryListener by implementing the UpdateItems method:

[71]   public UpdateItems(List<ListBoxItems> items) {
[72]      Items=items
[73]   }

We’re going to implement registration and deregistration GWT style, because GWT has particularly strict requirements for how we can access UI components. We’re only allowed to manipulate UI components that are attached to the underyling HTML document tree — by registering and deregistering when the component is attached and detached, components get updated at the proper times:

[74]   public OnAttach() {
[75]      super.OnAttach();
[76]      CategoryList.Instance.AddListener(this);
[77]   }
[78]
[79]   public OnDetach() {
[80]      CategoryList.Instance.RemoveListner(this);
[81]      super.OnDetach();
[82]   }

The GWT style is particularly nice in that it prevents long-lasting circular references between the view and the model: once you remove the view from the visual, the reference in the model goes away. Silverlight is more forgiving in where you can register the control: you can do it either the constructor or the Loaded event, but I don’t see an equivalent Unloaded event which could be used for automatic deregistration — manual deregistration may be necessary to prevent memory leaks.

So what have we got?

We’ve got a CategoryListBox control that works together with the CategoryList singleton to keep itself updated. So long as we call CategoryList.UpdateItems() during the initialization process, we can just include a CategoryListBox where we want it and never worry about initialization or updating. We can even create new ICategoryListeners if we want to make other visual controls that display the category list. This is a path to simple and scalable development.

What happened to the “Controller?”

The Model-View-Controller paradigm is a perennially popular buzzword in computing. The phrase was coined in the early 1980′s to describe a particular implementation in Smalltalk, which was one of the first implementations of a modern GUI. The Controller is a third component that mediates between the View, Controller and their environment. Although Controllers are widspread in server-based web applications, the Controller often withers away in today’s GUI environments, because it’s functions are often implemented by the event-handling mechanisms that come with the environment. In this case, “Controller”-like logic is embedded in certain methods of the CategoryList.

Note that there are two objects here that could be called a “Model”. I’m calling the CategoryList a model because it has a 1-1 relationship with an object on the server: the categoryList table. CategoryList is a relatively persistent object that lasts for the lifetime of the RIA. There’s another kind of “Model” object, the List<ListBoxItems> that is stored in the Items property of CategoryList and is passed to a ICategoryListener during initialization or update — that object represents the state of the categoryList table at a particular instance time. The generic List<> is an adequate representation of the state of categoryList, although there are many cases where we might want to define a new class to represent the momentary state of a server object.

Something else funny about CategoryList is that it doesn’t export a public Items property. It certainly could, bu I chose not to because a getter for an asynchronous model object is making an empty promise.

A getter in a synchronous application can always initialize or update itself before returning: a similar method in an asynchronous object must return to it’s caller before it can receive information from the server. As asynchronous model can return a cached value of Items if available, but it can make a much firmer promise to deliver correct updates of Items when they become available. CategoryList does, however, deliver a cached copy of Items to CategoryListeners after registration, as this is an effective and efficient mechanism for initialization.

Would it be possible to define only a temporary ‘model’ class and put a single Controller class in charge of updates? Sure. I think that would make more sense in a dynamically typed language like Javascript than it does in Java or C#, since it would be hard for such a Controller to enforce type-safety. Could we call CategoryList a Controller? Perhaps, but I think CategoryList is a logical place to locate methods that manipulate the categoryList — it really is a representation of a persistent object.

What next?

This is a good start, but we haven’t entirely solved the RIA architecture problem. Let’s talk about some of the issues we’d face if we generalized this approach:

  1. What if there was more than one type of dropdown list? We ought to have an inheritance hierarchy from which we can derive multiple types of dropdown lists. This could include mutable lists such as ContributorTypeListBox as well as immutable lists such as USStateListBox.
  2. There is just one CategoryList in the application: in some sense it’s globally scoped. What if we want to represent a BlogPost or a Contributor? Simple, use a Multiton instead of a Singleton. Rather than writing CategoryList.Instance, you might write BlogPost.Instance[25], where 25 is the primary key of the blog post. The logic behind Instance[] is responsible for maintaining one and only one instance of BlogPost per actual blog post.
  3. Isn’t the updating logic in the CategoryList and CategoryListBox repetitive? It is. A mature framework will either push this logic up into superclasses (kind of an embedded controller), or push it out into a Controller. The best approach will depend on the characteristics of the environment and the application.

I’ll be elaborating on these issues in future postings: subscribe to my RSS feed to keep up to date!

Conclusion

It’s simple to initialize and update data in the simplest RIA’s, but asynchronous communications makes it increasingly difficult as applications grow in complexity. A simple approach to data updating that is reliable and maintainable is to create a set of persistent model classes that maintain:

  1. A cache of the latest data value, and
  2. A list of dependent view objects

Model objects are responsible for updating View objects, which in turn, are responsible for registering themselves with the Model. The result of this is that View objects can be used composably in the UI: View objects can be added to the user interface without explicitly writing code to manage data updates.

Although this pattern can be applied immediately, we’ll get the most of it when it (or a similar pattern) is incorporated in client-side RIA frameworks. There are only a few client-side frameworks today (for instance, Cairngorn and PureMVC) but I think we’ll see exciting developments in the next year: subscribe to the Gen5 RSS feed to keep up with developments.

kick it on DotNetKicks.com