Archive for January, 2009

MVC: A brief history of Models, Views and Controllers

Saturday, January 31st, 2009

Any web-developer Rubyist knows about models, views and controllers. The MVC paradigm is embedded in the structure of Rails and Merb and encouraged by Ramaze and Sinatra. If you’re a Mac developer or an iPhone bod then MVC is common practice there as well. Same goes for Sproutcore and even Microsoft is getting in on the act.

But where does MVC come from?

Well, like most things I enjoy in the world of software development, MVC has its roots in Smalltalk. However, things used to look slightly different to the MVC we know and love. In Smalltalk, the basic Object has a feature known as “dependencies” built-in; nowadays, we would call this the observer pattern. Basically, any object can register an interest in any other object and will be notified whenever the target changes.


target addDependent: listener.

Later, when something changes within target, it can decide to notify all its dependents (observers):


self changed: #SomeArbitraryMessage.

and the listener has its update: aSymbol method called.

Building this notification mechanism right into the core of the system means that it can be used everywhere – especially when designing user-interfaces (remember, Smalltalk was the GUI for the Xerox Star, which his Steveness bought and adapted for the Lisa). Models were the system components, the pieces of the system that actually do the work. Views represented portions of the screen and controllers represented the keyboard and the mouse. These parts were arranged as follows:

MVC in Smalltalk

MVC in Smalltalk

The view would add itself as a dependent to the model and display the relevant aspects of the model on-screen. The user would see this, manipulate it via the mouse and keyboard, which triggers the controller. The controller sends messages to the model, which triggers its notifications, prompting the dependent view to redraw itself. In other words, the controller and view are independent objects that know nothing about each other – the only tie between them is the controller’s knowledge of the model and the dependency mechanism.

Contrast this to the MVC we know today:

MVC in Rails

MVC in Rails

Here the user pokes the controller, which in turn sends messages to the model. The model does its thing and then the controller extracts the relevant information and passes it to the view, which is then rendered to the user. In this manner, the controller lives up to its name, orchestrating the entire cycle – and is the centre of all the coupling (as it knows about the view and the model).

So why did things change (first in Smalltalk and then the following MVC frameworks)?

The first problem is that the controller takes input and the view handles output – as separate objects. Which, especially for desktop applications, doesn’t really work; if you click on a text-field you expect different behaviour to clicking on a scrollbar.

Secondly, imagine an array of models being shown in a list box. The list box has the concept of a current selection. So your array model (a model of models) needs to have a current selection, so that the view knows which is which. But what if the same list is rendered in two places at the same time. If you point both views at the same array model, they would both share the same selection properties. So you actually end up with something more like:

Getting Complicated

Getting Complicated

As you can see it gets nasty pretty quickly. And actually the controller is simply passing its messages directly through to the array model which is actually doing the routing of the other messages – the controller is pretty much redundant.

So if you swap things around, merge the controller and array model (into some sort of array controller) and then add multiple array controllers – one per view – to deal with the selection issue, suddenly you have the newer style object layout. Requests go into one of the controllers, it routes it to the model, then parcels up the results and invokes the view.

Evolution in action.

Cucumber and WATIR: kick-starting your testing

Friday, January 16th, 2009

I think Cucumber is fast becoming indispensable for my testing. The point of it is that you can write documentation that your client understands and then prove that the application does what it says. When coupled with WATIR you can show that it really works in an actual browser – you can even show it in Internet Explorer, Firefox and Safari.

There are a number of issues with using WATIR – the main one being speed – as WATIR scripts the browser, an extensive test suite will take a long time to run.

But my first hurdle was actually getting the code running. Unlike using Cucumber with Webrat, where your Cucumber steps have access to your Rails code (so you can play around with the response object), with WATIR you run the application in a separate process and then poke the browser in the same way a real user would. Of course, unlike Webrat, you get to test your Javascript too.

However, I didn’t want to have to remember to start my application before running the tests (and probably forgetting to put it into the test environment or running on the wrong port) – so I came up with the following for your features/support/env.rb.


system 'rake db:test:clone'
system 'rm log/test.log'
system 'ruby script/server -p 3001 -e test -d'

at_exit do
  system "kill `ps aux | grep mongrel_rails | grep -e '-p 3001' | grep -v grep | awk '{ print $2 }'`"
end

Before do
  @browser = Watir::Safari.new
  @browser.set_fast_speed
  @base_url = 'http://localhost:3001'
end

This clones your development database, gets rid of the test log (as we’ll need to look through that to track down any errors, so we want to keep it small) and then starts your app in test mode on port 3001 (so it doesn’t clash with the version you’ve already got open in development). The Before clause sets up WATIR and configures a base url that my steps use elsewhere. And the at_exit hook looks for the server we started and kills it.

Next step is to add a platform instruction – so you can choose to test with Safari, Firefox (if I can ever get the Firewatir plugin installed) and Internet Explorer (where I guess the kill statement will need a bit of alteration).

An alternative is to tell mongrel to start and write a pidfile to a known place, and then replace the ps/grep line with:


  pid = File.read(File.expand_path(RAILS_ROOT + "/log/mongrel.pid")).chomp
  `kill #{pid}`

Thanks to Caius for that version.