Thursday 15 January 2009

ViewModel - the missing link?

With ASP.NET MVC getting all the press now-a-days (well, in my tiny part of the web anyway), it's difficult to (a) not feel jealous if you're still stuck on .Net 2.0, and (b) wonder who's employer let's them used stuff that's still in beta for live websites.

However, whilst ASP.NET MVC/FubuMVC/MyMumsMVC provides a framework, and gives you more opportunity to get things right, there's still a missing piece of the puzzle that makes it all fit together.

Consider the lilly of the field.

If you modelled this, it would probably have a Field property.
Your view can probably handle a FieldId, but it shouldn't really know about a Field property. (Having the View access lilly.Field.Id breaks the Law Of Demeter (or, "Two Dots And You're Out"), and your whole SOLID Principals may as well be thrown out with the trash).

In one project we did, we got around this problem by having our Domain Model classes expose this kind of thing. It get messy really quickly, and really quickly pollutes your Domain Model classes with lots of methods and properties that are only ever used for display. Then they start getting used for business decisions, and pretty soon the project is one big code smell.

So, how else might we go about this?

Two patterns that might give us clues are the Facade Pattern and the Adapter Pattern. Go look 'em up. And, whilst you're at it, go look up the Data Transfer Object in your copy of Patterns of Enterprise Application Architecture. (Yeah, get it out from propping up your monitor, wipe off the dust off (a damp cloth is ok on the coated cover) DTO ison page 401).

So, you get the grasp of taking a bunch of objects (it's called an Object Graph if you're Martin Fowler) and converting it into something else for another purpose. When it's used in the context of aiding and abetting the communications between the Controller and the View (The C and the V in MVC), it's called a ViewModel (people how come up with these clever names are too busy to type a space it seems).

And it's great. Your ViewModel may include a LillyDescription class, which has properties like FieldId and FieldName, but, and here's the important thing, it doesn't have any non-primitive members (i.e. you're limited to strings, numbers and dates). Also, keep any logic out of them. If it wouldn't be universally frown upon, I'd say just use plain old Fields on the ViewModel classes (but that's heresy, so forget I ever said that) .

So now, you've got your controller converting between your Domain Model (used by your Business Logic) and your View Model (used my your view). STOP. Your controllers are not meant to do this. Your controllers are meant to control, not convert. Your SOLID Principals are under attack - your "too cool for school" badge will be ripped off your programmer's blazer, and you'll be asked to hand in your gun and your badge. The ALT.NET gang will ex-communicate you, and you'll loose all your profile points on StackOverflow.com.

So we need something else to assemble the ViewModel objects from the Domain Model objects. Go create another class (or even a Service!) to do this. Unit test the hell out of it - it's a purely programmatical problem, so Unit Testing is easy. Ensure that the ViewModel object has the right set of stuff from the Domain Model, and that it doesn't/does break stuff.

There - wire up your IoC container with the IViewModelLillyConverterService and it's implementation, and you're good to go. (i.e. expect the Yellow Screen of Death a few times).

There's a lot of stuff here. I'm still not entirely sure where the line is between all the parts. Although it seems like it'll create an explosion of classes, it really does simplify things. More code is normally worse, but I'd argue that this is more of a Refactoring (yeah, dubious I know).

Go and play with this idea. See if you can make your view utterly independant of your Domain Model. Go on. Go completely over the top. Then, maybe, you'll get a feel for it.

kick it on DotNetKicks.com