AJAX and the Model-View-Controller Design Pattern
10/06/2006
Permlink
I was recently asked to implement a fairly good-sized AJAX web application. In concept it's simple: poll a remote device for its status, get back assorted big hunks of XML, pull the status information from the XML and display it on a web page. In practice, there are complications. There always are.
First of all, this remote device (actually a complex system of interconnected microcontroller-based devices) may be on any one of several private networks that aren't accessible from the outside. So, the first job was to write a caching proxy that can live inside of the VPNs and talk directly to the device being monitored. That part was actually pretty easy, just a few pages of Java code.
Secondly, the total state that the device can express is pretty large, but the network it's on can be dodgy, with bandwidth down in the dial-up range. Since the total state the device can express is pretty large (about 30K of XML text), it's too big to poll all of it very often (others are sharing this network, too). So, the state information has to be divided up into smaller chunks and the UI designed so that you're only looking at one chunk of state at a time.
Thirdly, I don't have control over the XML that is sent to me (done by other developers) and it has not been designed with my UI in mind. Therefore, I have to gather together facts from all over the XML document when I want to display any given chunk in the UI. Also, the order that the data is in is not necessarily the order in which I want to display it.
It's always like this in the real world. In the classroom, all of these parts would be designed from the start to work together. In the real world, things evolve and requirements emerge and you just have to cram things together.
So, my little AJAX application got fairly complicated fairly quickly. As it evolved and started to get cranky, I decided to treat the problem more like I was writing a GUI (like a Java Swing application), rather than a bunch of Javascript crammed into a web page. My first instinct with GUI designs is always the venerable old Model-View-Container design pattern, which is designed to separate the data (Model), display (View) and business logic (Controller) of an application. This turned out to be a good instinct.
There are others on the web who see the M-V-C pattern as useful with AJAX applications, but in a different way. They think of the Model part of the application as something that the server provides, then the client (the browser) provides the View and Controller using Javascript and CSS. That's fine, but not what I'm talking about.
I'm talking about implementing all three in Javascript on the browser. Why? Why have a complex data model living on the client? Well, because my application sort of demands it. I have fairly complex data coming down in XML and the data winds up being displayed in more than one place on my web page. While each chunk of status I display lives in its own tab in the UI, there is other information that gets displayed in multiple tabs. The code that renders the data out to the HTML is fairly complex, creating, for example, tables that have rows initially hidden that can open up and show details when the user clicks places. This code is much simplified if the data it is rendering is contained in a set of nice, simple Javascript Objects, rather than all over an XML document.
So, how does it work? A picture always helps:

The web page (yellow, in the diagram) includes three Javascript files. In the OnLoad handler for the page, the Model, View and Controller objects are created, plumbed together and attached to any onClick, onMouseOver or other handlers. The Controller is then told to begin polling for data.
Actually, it's considerably more complicated than that. The HTML page itself is actually generated dynamically on the server from a JSP page. This allows the server to insert all sorts of dynamic data on the page (dynamic, in the sense that it is created on the fly at the server, but static in the sense the it is not changed once the user has the page). Some values are also written into the Javascript of the page (such as the IP address of the device being monitored) to later be handed off to the Controller.
The Controller then requests data from the proxy server (blue arrow), parses this data and inserts it as Javascript objects into the Model (which is just a Javascript object used as a HashMap). It then alerts the View that new data has arrived to be displayed. The View pulls the data from the Model (in the order it is needed) and writes it onto the web page by manipulating the DOM (green arrow). For example, a series of Javascript objects in the Model might be rendered on the page as rows in a table.
Sounds complicated, large and slow, doesn't it? Well, it is, but there are advantages. I think it's less complicated than having your XML parsing code all intertwined with your DOM manipulation code. Also, the View, for example, doesn't know anything about the origin of the data, so it won't suffer if I switch from XMLHttpGet to dojo.bind. As for large and slow, it doesn't seem to be. The page is quick and responsive. This isn't so surprising. After all, the code on my page is a small fraction of what something like Google Maps or Google Mail would use.
The Model is quite simple, only a page or so of code. Basically, each chunk of data is represented by a Javascript object. Javascript objects are naturally type-free and can hold anything: Strings, Numbers, other Objects. This makes it easy. Each chunk of data in its Object is then stored within a master Object using it's key as a property name. In effect, the master Object serves as a HashMap to store all of the other named Objects. Accessing the data is as simple as
var myStateObj = model.get("myStateObj");
By accessing the property through a function, I can detect Objects that have not yet been cached and insert them dynamically when asked for. When you ask the Model for an Object to hold some data, you always get one back, even if it's empty and you never have to remember to save it back to the Model, because it was inserted there when it was created.
The View is also pretty simple. It offers some utility functions (such as a function that can be called to display status information about the state of the connection to the server and a function the formats a Date object into an hours-minutes-seconds String) and a single "render" function that pulls data from the Model and writes the currently appropriate chunk of it to the HTML DOM.
The Controller is the most complex. As the user manipulates the UI, the Controller is called and it keeps track of what content the user is trying to view (these interactions are represented by the red arrow in the diagram). Periodically, it's polling function is called (dojo.lang.setTimeout(poller, poller.poll, 6000);) and it asks the proxy server for a particular chunk of data, depending upon what the user is doing. There is a bunch of error handling code, in case the server isn't reachable or the device being monitored is offline — tedious, but conceptually simple. The XML reply is passed to a function that walks the XML, interprets what it sees and calls various functions to create Javascript objects containing the requested information and saves them to the Model. Once all of the XML has been parsed into the Model, the View is called an told what part of the UI needs to be refreshed. There are also some utility functions that hide and show particular data as the user manipulates the UI.
So, there you have it. The M-V-C design pattern rides again!
8 comments:
Lovely article mate
Really good article. I was wondering if I could use your nice colour diagram in one of my proposals to management for a similar application I'm doing for work?
Sure, anyone who wants to use that diagram is free to take it.
good one... makes a lot of sense to implement apps this way...
But lets say i change the xml structure or the way the data comes from the server change, in that case the bottleneck of javascript changes gets into modifying the "walker" who goes through this structure and converts them into model objects..
Ofcourse this is inevitable, but still works good, rather than having to change the intertwined parsing code and view elements ...
Thank you for the article. Very nicely done. Any changes or new ideas since you published this? I'm going to be doing something quite similar.
Sure, anyone who wants to use that diagram is free to take it.
Thanks for this post! But lets say i change the xml structure or the way the data comes from the server change, in that case the bottleneck of javascript changes gets into modifying the "walker" who goes through this structure and converts them into model objects.
Camarad: yes, it does. If the format of the data from the server changes, then the code in the "controller" must change to reflect that. The good news, however, is that the "model" would only need to change in a small way (perhaps to add new information that wasn't present in the earlier version) and the "view" might need no change at all.