Archive for January 3rd, 2006

MVC, Smalltalk and the Web

So, I’ve been writing the MVC paradigm recently as part of the TurboGears book, and the process has been interesting. MVC has a long and illustrious history, and it seems like it now has as many definitions as there are are books/articles that discuss it. There are a million MVC based frameworks out there, from TurboGears, Rails, Struts, and WebObjects, to Cocoa. And the frustrating/interesting/enlightening thing is that each of these environments implements MVC slightly differently, and those differences reflect significantly different understandings of what is core to the MVC paradigm.

My quest for a unified explanation of MVC lead me back to the original SmallTalk implementation which was codified in Smalltalk-80. But that adds another layer of complexity to the problem of describing MVC, because Smalltalk-80 controllers did things that are now taken care of entirely outside of all of the modern MVC frameworks. For example, the controller was responsible for dealing with keypress and mouse click events — and doing something sensible with them. Now days the OS, and drivers, and window-managers take care of all of that, leaving a Smalltalk-80 controller without much to do.

And that, I think, is one of the key reasons that MVC has mutated so much over the last dozen or so years. The original architectural pattern was created to — among other things — solve the problem of where to put all the event-interpretation code that is necessary when your code is directly responsible for dealing with user input events. Now that we have mouse drivers, windows management systems, and a whole layer of GUI abstraction code between our users and the events there isn’t anywhere near as much need to keep “controller code” partitioned off in it’s own corner.

Another key component of the early version of MVC in Smalltalk that is different than what we find in “modern versions” is the observer relationship between Views and Models. In the original design views either poll, or subscribe to, models and automatically change what the user sees whenever the model is updated. But at least with web based MVC is that it is no longer feasible (well, at least until Ajax came along). So, as a sort of natural evolution, Controllers gained responsibility for sending status updates first to the model after a user event, and the also for telling the view to publish that updated data to the user.

This is natural, and sort of sensible, because much of the complexity of Smalltalk-80 style controllers had already been abstracted away, so it’s not really that painful to add a bit of “glue code” to the controller. So, anyway you can trace the history of this evolution through Objective-C, and NextStep, to Cocoa, WebObjects and Struts. With the controller being seen increasingly as “the glue that holds models and views together” in addition to its original purpose as “the code that processes user actions.”

OK, so given that this evolution has taken place, how is that reflected in all of the new “full-stack frameworks” we are seeing today.

I’m only deeply familiar with TurboGears and Rails, and both of them allow you to use model objects directly from your View code, so they are somewhat more like Smalltalk-80 than their older brother Struts. But, rails goes further by making it trivially easy to call Models from your view — everything is even magically imported s all you need to do is call the objects. TurboGears has so such magic, so if you want direct access to your model objects you have to import them (which is a single line of code). But it is often easier to just have your controller pass a dictionary of all the data you need into the view when it is called.

This is also a clear reflection of the Rails “convention over configuration” philosophy informing David’s view of MVC, while Python’s “Explicit is better than implicit” philosophy informs Kevin’s interpretation of the “same” design pattern. It’s hard to say which is better, but my experience was that it was really, really, really easy to do easy things in Rails, but then I had to figure out “how the magic works” before I felt comfortable venturing out from there. TurboGears, on the other hand took a little longer to get started, but then the learning curve was comparatively easier for moving on to more complex stuff, because everything was visible and I knew exactly where to look to find out more about how each of the pieces worked.