Saturday, April 25, 2009

Models inc

Recently I have noticed there seems to be a confusion over what the term model means. I am happy to admit I am not the guru on all things code, but i am happy enough to put it out there that there is not necessarily one model per system. I have a feeling that a lot of this confusion has come from the MVC, MVP and DDD wave currently sweeping the world. A multitude of examples showing the possible way of creating an MVC application will use just the one model, i.e. the controller will talk directly to the repositories and the objects retrieved are passed to the view. This scenario is fine for web applications that have little need to scale and are effective bound to a 1-2 tier architecture. The new ASP.Net MVC + Linq - SQL is a fantastic candidate for this and allows you to get a testable solution up and running in no time.

But what if you are using WPF, with a application server  using an ORM for persistence and WCF to get the info to the client. Reusing the ORM specific objects is asking for a messy solution. To me this is where it become very important to define your models. In this common three tier type application architecture I immediately can see 3 types of "models". First and foremost the Domain model. These are the business classes that make up the model that reflect the "business truths". This is where the business rule are enforced at the up most. You ORM will interact with these domain entities and value types and map them appropriately to your persistence layer, which is most likely your Relational Database. This closely follows the core concepts of DDD. This is all well and good but it is often where people will stop in terms of models. These objects will be items such as Customer and OrderLine in my mind belong in the bounds of the domain. I have been hit, as have many, by trying to reuse these object and send them to the client to be "reused". This is a bad idea.

Lets play devils advocate and say that we will distribute these domain objects. Lets say we are also using and ORM that allows attribute defined mapping. Lets also say we wish to mark up the object using the old school way, defining the object as data and member contracts for WCF. Lets also say we are using WPF and want or binding support. Straight away the class is going to be bloated with infrastructural concerns. It is going to look like a mess. What if this object is sent to the client and a property that is marked as lazy loaded is referenced? How is this object going to get that information? Is it going to jump back across the wire and get the data... just for a lazy load operation?

I am obviously pushing for something here: separate your concerns. The domain object should remain as domain objects. The objects that get passed across the wire should be DTOs. These are incredibly simple and are just data holders. The service layer will convert the domain object to the DTO depending on the operation. For example when returning a list of objects it may not be important to send all the object information; perhaps just the Id, Name and Description would suffice, however if you are return a single item then it would be likely that more detailed information is required. This conversion scares people off. It sounds like too much hard work. It is not. It is trivial and easily tested. Please do not use the excuse of "it is too much overhead" as this is the easiest code you will write. Further to this you may find yourself using Specific DTO for specific service interactions. This is a good thing. Intention revealing interface are good. Creating these will most likely save you a lot of maintenance time later on down the track. For example you may have a CustomerDto for lists and CustomerDetailedDto for single instances etc (possibly not the best names used here, sorry)

Once the DTOs are passed over to the application tier they can then be used as-is, or if there is more application specific needs than a simple DTO can provide, then create an Application Model. This application model is, as the name suggests, specific to this application. A web application model will most likely be subtlety different to a WPF application model with infrastructural additional being the most prominent (i.e. data binding concerns).

This certainly appears to be a fair bit of extra work, however you will end up with a design that is incredibly simple at each layer and very simple to maintain. Each concern now only has one reason to change and you can easily facilitate multiple people work on vertical and horizontal aspects of the stack. To me the ease of working with a stack like this and the significantly reduced maintenance costs will push me to consider this approach very early on if  the application is moving towards a 3+tier design. I would strong recommend it if you are doing the same.

1 comment:

Lee Campbell said...

Good post.
It is amazing how lazy we can get isn't it. The thought of having to write some code regardless of how trival it is just scares people off. So we fall in to the area of Coincidental reuse. This is where "models" are the DTOs and are also used on the client (WPF). So we have mega classes that exhibit multiple personality disorder as the implement interfaces for WPF, WCF and possibly ORM. As Rico Mariani ( puts it "Reusable? ...but it was never useable. How can it be RE-useable?"

Sure there is a pain in the butt part of writing some translators that almost always just look like
target.Id = source.Id;
target.Name = source.Name;...etc
but how much easier is it for everyone else to work with WPF objects that are specifi to their cause and dont have wierd and wonderfull properties that you are not sure if you can/should set them.

They only people you will get argueing against your post are the guys who have to write the translators (eh G.Fox) or permies who "know the code base inside & out". Obvisouly they dont care that no-one else can read the garbage code or that changing something for WPF may break something in the WCF or ORM layer.

While im commenting, my favoured naming convention is
CustomerSummaryand then just plain old
Customerfor the detailed version. I also prefer it if the CustomerSummary is immutable if it will only be displayed in lists.