I’ve been working on a RSS reader Windows Phone 7 application as my 2nd Continuous Client example. I’m not diving into the Continuous Client work in this post so you won’t see any of that included (I will at a later time) but I decided to take this opportunity to improve on my MVVM (Model-View-ViewModel), separation of concerns and writing more maintainable and testable code.
I had a great opportunity to pair program with Glenn Block and we went through several iterations of refactoring. I’m amazed at his ability to see small parts of a code base and within a couple minutes he has a strategy for decoupling and separating the concerns.
This series of blog posts shouldn’t only be for people interested in MVVM. In general I learned a lot of of values that I’ll take with me in different problem sets and I hope I am successful in translating those into this series.
One thing I’ve struggled with for a long time is how to cut the dependency on the IoC container. I knew that Service Locator code was bad but every time I tried to reduce the coupling I would run into road blocks where I had to expose the container.
We started at the ViewModelFactory<TViewModel, TDesignViewModel> and worked our way out from there.
What is ViewModelFactory
ViewModelFactory is one of my favourite classes when implementing MVVM. Jeremiah Redekop created this bit of code and I modified it slightly. ViewModelFactory allows us to provide run time view model data and design time view model data. This enables us to have Blendability (ability to see data in Expression Blend as we design our user experiences with a visual tool).
The original version of ViewModelFactory<TViewModel> from Jeremiah provides 2 methods OnLocatedAtRunTime() and OnLocatedAtDesignTime() so that you can separate run time execution (for example querying a REST service) from populating mock data.
I slightly modified ViewModelFactory<TViewModel> to
ViewModelFactory<TViewModel, TDesignViewModel> because I liked the design time implementation to be completely separate from the run time implementation.
The DataContext of the view binds to the ViewModelFactory.ViewModel property, which returns the proper view model based on if it is executing in the designer or runtime.
What’s wrong with my view models
Now that we know what ViewModelFactory does, let’s dive into the problems with my implementation and why we started here in the refactoring.
My View models have a bunch of dependencies like Event Aggregator, access to the data store etc. I was using the Service Locator pattern to resolve these dependencies from a Funq container. The view model gets created from the ViewModelFactory which is created in XAML. I didn’t see a way that I could allow constructor injection of these dependencies so this is why I had put in place Service Locator. I knew it was a bad choice, I just didn’t know what to do about it.
To be able to solve this we had to first fix ViewModelFactory since this is where view models get created.
ViewModelFactory refactor iteration 1
The fun thing when pairing with Glenn especially with refactoring is he has a very iterative approach which avoids an “OMG the whole thing is busted!” situation. It’s also great for learning experiences because you can see step by step the evolution of the changes that are happening.
The first iteration was to introduce resolving dependencies for view models by the ViewModelFactory since it is currently responsible for creating view models.
This is what the ViewModel property looks like for ViewModelFactory before the first iteration of refactoring. As you can see we are simply serving the run time or design time version of the view model.
|1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32||
The first iteration of refactoring we introduced the IoC container in a Service Locator like fashion so that we could then refactor our view models without breaking everything.
This is how it looked after the changes.
|1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24||
This allowed us to now continue to refactor our view models so that they can support constructor injection for their dependencies. This is how a view model looked before the refactoring.
|1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49||
As you can see from this view model the Service Locator is used to resolve dependencies. As you can imagine this code is littered through various view models.
Since we moved the Service Locator code to the ViewModelFactory, now we can shed the container dependency from the view models (remember, we are taking an iterative approach, it gets better later, stick with me).
|1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50||
Interfaces were introduced because at design time we may need to mock some of these dependencies and not use the real types. We created IDatabase and in the generic parameters of the design time view model there is a design version of the database defined. Since we don’t want to be attempting to talk to isolated storage at design time we can implement a mocked version of the interface which does nothing. The mocked database is pretty simple.
|1 2 3 4 5 6 7 8 9 10 11 12 13 14 15||
The MainViewModel is far more testable now as well in this version. We don’t need to wire up an IoC container to test it’s functionality. We can inject mock dependencies in the constructor and test the view model easily.
If we wanted to we could also place the design time view models and mocks in a separate assembly.
This is what I had in the App.cs to initialize the Funq IoC container.
|1 2 3 4 5 6 7 8||
Since we are now going to be utilizing the IoC container to construct more of the object graph and inject dependencies into the constructors we need to ensure we are registering all the types we need. While we were at it we decided to reduce the amount of calls to ApplicationHost.Container to position ourselves nicely for when we nuke that sucker all together.
|1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21||
We’ve reduced coupling significantly to the IoC container from the view models and as a result as mentioned things are becoming more testable. We still have the service locator code within the ViewModelFactory but in the next part in this series I will discuss how we created ViewModelResolver and a composition root in the form of a bootstrapper to completely eliminate the ApplicationHost.Container property all together.
Things get much cleaner in part 2, stay tuned!