Friday, December 31, 2010

How I MVC

So, I'm working in a .Net company that makes applications. Weird. I've only done webapps for the last 10 years or so.

Nice thing about webapps is it forces you to at least consider separating presentation from content, behaviour from interface and so on (often that consideration is ignored and we just write crud, but one is encouraged by the CSS/HTML/Javascript/Webserver separation to at least think about it)

App side of things? No such luck. Everything just goes everywhere.

Now, thing is, I'm working on some projects that started as prototypes, so it is unfair to judge development practices on them (I hope...). They have no tests. They are not written with tests in mind. They have no 'domain model' and very poor separation of concerns.

My company just gave us some 'downtools' time to work on our own stuff, so I did a (prototype) reimplementation of much of the application I've been working on. I did this so I could see how I could write this app with tests, and in turn using the MVC approach that smalltalk encourages.

(I also tried for a tell don't ask approach, and achieved this to a degree, but didn't really push it)

By thinking in MVC terms I end up having to have a 'domain model' - it's the model bit :) This is already a boon as I start separating out the model data and behaviour from the human interface that manipulates it. This means I can use a different (eg testing) interface to manipulate it. Whamo, got some tests. Red Green Refactor Happy

Next comes the view. I hate views. The bit the user clicks on is pants to test, and hence I've always tried to keep this untestable, horrible bit of code as thin as possible. Sure I can have some happy path integration tests, but really, they suck and don't cover nearly the ground a good few unit tests will.

This also separates out the manipulation of GUI elements into one place - and I love separation.

If the view is so thin, what does the UI work? Well, the controller (that's all that's left, right?). So it ends up linking the view and the model, translating between them, maintaining any state associated with the UI (and not the domain) and invoking commands on the domain as needed.

Boy that's a lot. Too much.

So I split the Controller up into the, um, Controller and the ControllerModel (actually I called it ViewModel).

The ControllerModel maintains any state that may be needed for the particular view you are dealing with (eg list of pages in a wizard, internal representations of the GUI elements (and hence translations) etc). This makes it a nice, testable chunk of code, and simplifies the Controller.

The Controller has NO state - it only knows about the things it is linked to (view, model, controllermodel, services). While it makes behavioural decisions, these decisions are based on information drawn from elsewhere.

While still hard to test (lots of mocks/stubs!) you end up just testing that 'when event A is received, object B is called'. The tests themselves end up much better worded - explaining behaviour and interactions explicitly, not having to worry about translations and state.

So how do I MVC? I MVCVM (Model-View-Controller-ViewModel).

(A final note... the controller sits at the centre as a big fat svelte mediator sending commands to all its minions and listening for those minions events. The minions never call/know about the controller)

2 comments:

  1. Cool stuff. We should have an argument about this soon ;-).
    I am all for the Felix Style Presentation Model pattern as presented in this paper.

    ReplyDelete
  2. BTW have you dabbled into IPhone development? I quite like Apple's version of the MVC pattern. There is an online course available at Stanford, which I found quite helpful.

    ReplyDelete