Tuesday, April 6, 2010

Model / ViewModel Relationship

I've become an avid believer in the MVVM design pattern for XAML-based applications but find certain aspects remain ambiguous as the pattern moves through its "toddler" years. One of these areas has to do with the relationship between the Model and the ViewModel.

In many articles and examples, I see that the Model is directly exposed as a property on the ViewModel. This seems like the easy way out to me, but does fit one approach to the pattern. In this case, the ViewModel is designed to "extend" the Model by exposing additional properties and methods used by the UI - an implementation of the Decorator pattern, if you will.  But, this approach has a couple of issues:
  1. First, there might not be a one-to-one relationship between the data contained in the Model and the way the UI wants to display it.  Perhaps we want to display a person's name as their full name but the Person object only contains FirstName and LastName properties.  Sure, we could modify the Person class to expose a FullName property, but what if we don't have access to that code - perhaps Person came from an external service?  Isn't it the role of the ViewModel to make these adaptations for us?
  2. What if we have an object graph with parent-child (or even grandchild) relationships?  Wouldn't we want the ability to manage the child objects in their own view?  At which point, we'd need all that extra stuff the ViewModel offers for the child views, too.
On the other hand, let's not discount the simplicity of exposing the Model object as a property on the ViewModel.  One property and a convenient way to swap the object under-the-hood of the ViewModel without having to worry about multiple property changed events, etc.

Another common approach I've seen is to store a reference to the Model object in a private variable and have the ViewModel delegate to the object in property setters/getters.  One advantage of this is that we can preserve any business logic that may be contained in the Model object but it does increase the code in our ViewModel significantly as we have to mimic each property we want exposed to the View.  Plus, if the Model object contains validation logic, etc. we have to include plumbing to hook that up.  And, let's not forget the need to handle property changed events from the Model so we can bubble them to the UI.

Child objects or collections are then wrapped in their own ViewModel class and exposed to the UI, thereby, supporting deep object graphs in a consistent manner.

Truthfully, I only see this as a reasonable approach if you are using rich business objects for your Model.  Simple DTO's don't contain any additional logic that provide value when delegating.  Of course, it makes it easy to swap them under-the-hood and possibly saves a step when interacting with a service to persist changes but I don't see this as good enough justification.

The other option is to use the Model as a DTO and "load" the ViewModel state from the DTO when retrieved.  The ViewModel would then manage the state internally via data-binding with the View.  For persistance, the ViewModel would create a new DTO, populate it and execute whatever method(s), presumably a service call, to save the state.

This choice suffers as the previous from the additional coding required to "re"implement the various properties for the View to consume.  However, it does provide clean separation of layers as the View knows absolutely nothing about the Model.  And, if I'm not mistaken, one of the diagrams for the MVVM pattern I've seen shows exactly that.

So, the question in my mind is what purpose should a ViewModel serve and which approach best suits that role?  While I hate recoding properties that have already been implemented in my Model object, there are some very good reasons while I think this is the right approach:
  1. Separation of layers.  The View knows nothing about the Model so changes to the Model don't affect the View.
  2. The ViewModel is there to serve a particular use-case which, following solid OO principals, should be behavior-driven while our Model object (given today's trend toward entity-base data access technologies) is most likely data-centric.
  3. The ViewModel assumes the responsibility to reformatting, repackaging, re... the data obtained from the Model into a form required by the UI.
  4. The ViewModel adds INotifyPropertyChanged support and aleviates this responsibility from the Model.  This may not be the case if dealing with rich model objects where we may want to delegate and have the ViewModel bubble the PropertyChanged event.
As the last point demonstrates, heading down one path often turns on itself and takes us right back to the original question/debate.  I'm still forming my opinion and welcome your thoughts, comments and observations to help me along this journey.

No comments:

Post a Comment