After years spent chasing the latest waves in web technologies, the software development industry has come curiously full circle. Today’s web client technologies are homeing in around the ideal of the [tag]Rich Internet Application[/tag]. The [tag]architecture[/tag] being employed in the pursuit of this ideal is familar: Component-Based and Event-Driven. This is the same approach that underpinned desktop rich client frameworks like AWT, [tag]Swing[/tag] and SWT.
In the case of at least one RIA implementation, [tag]GWT[/tag], this return to a familiar architecture is touted as a great advantage – a good reason to switch. I subscribe to the Component/Event approach, but with one major caveat. While writing desktop clients might seem relatively straightforward compared to dealing with JSPs, servlets and http session management, the passage of time has blurred our memory of some of the truely terrible code that we have all found ourselves dealing with thanks to some of the limitations of exactly those rich client architectures that we are now once more looking at. Unfortuntely, despite that same passage of time, these architectures have not been improved upon – we’ve all been too busy writing web applications.
The difficulties in architecture that I’m referring to have nothing to do with the pencil-snapping vageries of the gridbag layout, or slow startup times. These are just minor skirmishes on the fringes of a bigger war: the war on coupling.
Swing and SWT give more or less the same answer when asked “How do you minimize inter-component coupling?” In unison they reply “We don’t understand the question”. Both systems are predicated on MVC patterns – that same design that the Model 2 web architectures have tried to approximate for the last 7 years and are now approaching with solutions like GWT. MVC is a solid dependable way of making ‘model’ code independent of ‘view’ code within one component. But it doesn’t do a damn thing to keep a healthy distance between two MVC components. The events that Swing components (JavaBeans) pass to each other are the same low-level widget events that are normally passed between model and view inside the component. This is a flagrant breaking of encapsulation which has the inexorable consequence of tightly coupling two components, and by extension, reducing complex clients into Big Balls of Mud. Even JavaBeans that encapsulate widget events and publish component-specific events instead, reduce coupling, but don’t eliminate it. Reduced coupling is what we should aim for between cooperating classes. Between ‘components’ we should be aiming for zero coupling.
So this is the fate awaiting the next generation of eager RIA developers: a forgotten landmine lying just under the surface of yesterday’s battlefield.
There have been attempts to avoid this coupling. The most recent I can recall was [tag]hMVC[/tag], which was actually an unintentional variation of an older approach called PAC ([tag]Presentation-Abstraction-Control[/tag]). The idea in both cases was to connect multiple MVC components, called Triads, to each other, by means of a hierarchy (the ‘h’ in hMVC). This is the very successful design used by window-based operating systems such as the one you are using now to run your browser. Events that are not handled in a given Triad automatically fall up the tree until they encounter a Triad that can handle them. This works very well for a system that ‘trades’ on the same level of event (in this case a low-level event like a ‘Mouse Right-Click’).
But in rich clients, the kind of communication required between components is of a higher ‘business’ level. Let’s say Component A knows all about how to manage and display lists of products. Component B knows how to display a piechart of the shipping state of orders that include a given product. If you want the selection of a Product in Component A to cause the display of that product’s piechart in Component B, the last thing you want to do is to trigger that with a low-level list selection event that the piechart Component has to capture and interpret. This would be the equivalent of declaring a throws clause for a persistence-specific exception on a service method. Just try selling Component B without selling Component A alongside it. If you can’t sell it on its own, it’s not really a component, is it?
Applications are not Components
I think the attraction of Swing-like architectures for a lot of people is the mature GUI building software that exists in this arena. GWT was barely off the boat when some vendors were shipping pretty good compatible GUI builders. I can understand the enthusiam – visual front ends are one of those rare situations where it makes sense to generate code visually!! The problem is that while GUI builders are great for putting together component views, but they are terrible for building entire applications. I remember back in the day when VisualAge for Java came out. It revolutionized Swing programming (while producing some truely sick generated code in the background – but that’s another matter). But the assumption behind this kind of JavaBeans programming was that applications should be assembled from components in the same way that bigger components should be composed of smaller ones. The assumption was made, to be fair, in the absense of any other choice. It was built in to the JavaBeans spec. The result of trying to put together GUIs of any level of sophistication on a visual GUI Builder workbench was very appropriate: it looked like spaghetti.
I’m droning on a bit here, so let me cut to the chase. I think there is a better way to combine components into an application, one which I will share in a followup posting in the next couple of days. It’s disappointingly straightforward, but it aims for zero-coupling between components by dividing the architectural presentation layer into two: The Component Layer and the Application Layer (if you think that these are very unoriginal names for them, it gets worse: I’ve called the architecture itself AMVC – Application MVC).
I would appreciate any feedback either what I’ve said here, or what I will (soon) propose by way of a solution.