I have been spending a lot of time lately thinking about client architecture with Silverlight and to a lesser extent, WPF. I tend to subscribe to the philosophy that when you make your code testable, you get a lot of other great qualities along with it. I believe this so strongly that I go out of my way to architect my inherently untestable code in a way that I can, indeed, test it.
Since I have been writing most my code for the Silverlight platform in the past several months, and I wanted very much to write my code test-driven. I used the Model-View-Presenter pattern (MVP) to implement my view as an interface. The presenter would hand model objects over to the view and I would bind visual items in my view to the model items. The presenter would then tell the IView what to do when any real logic came to play. Over time, however, more and more logic started creeping into the code behind. I had a lot of data converters to doing my dirty work, blending the code between the model and the view. The problem is that anything within the IView implementation (aka code-behind) is not easily unit-testable.
As I started to really understand how binding worked in the context of XAML, I found myself wanting to use binding against view-agnostic objects for testability. Since the view didn’t know anything about the presenter, the only data to bind to was in the model. Sadly, view-specific data started to creep into model items. Where ThumbnailData (for instance) was only meta-information that came from my server, it began to gain properties such as Selected and Hidden. Moreover, what “Selected” means to one part of the UI is different to another part of the UI.
This was not the direction I wanted to go. In a fit of desperation, a colleague and I sat down and designed a pattern where we had a “ViewState” and a “ViewLogic” class. “ViewState” was just a set of properties (model data and view properties) that implements INotifyPropertyChanged for the view to bind against and “ViewLogic” manipulated the “ViewState” to add the UI smarts.
The benefits were immediate and obvious. We started seeing logic that was once in the code-behind move over to the “ViewLogic”. We immediately received testing benefits. We could write tests against the “ViewState” as if it were the actual UI. We even started writing our new features with TDD. Everything was great!
I was all ready to start blogging about it. My colleague and I had come up with this fantastic pattern for making testable Silverlight UIs and I wanted to tell the world. When doing some comparative reading I started seeing the “MVVM” term pop up here and there. It didn’t take long for me to realize that what we had invented in a bubble was just a subtle variant of the Model-View-ViewModel pattern. The ViewModel is really just our ViewLogic and ViewState combined into one single class. It only solidified my belief that this pattern had legs.
Although I sensed some initial skepticism from my team-mates about using the pattern throughout the product, it didn’t take long for them to recognize how important the MVVM pattern would be to our project. Since adoption our test coverage has skyrocketed with hundreds of useful tests. The proof is in the pudding. The vast majority of our bugs that come in have been one of two types of bugs: Missed features or improper binding – two things that the MVVM pattern can’t help prevent.
So, that is how I got so interested in the MVVM pattern. Because it is relatively new, the community is still working out the best practices. There is room for experimentation and that can be a lot of fun. Lets solve the new problems. Lets push the community in the right direction. We are already hearing the buzz for Silverlight 3 to contain native support for MVVM (via Prism). Lets keep this going… and lets have fun doing it!