Jul
24

Refactoring to improve maintainability and blendability using IoC part 1: View Models

By kellabyte  //  Architecture  //  8 Comments

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.

Before

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
public TViewModel ViewModel
{
get
{
TViewModel viewModel;
bool wasCreated;
bool designMode = DetectDesignMode();
 
if (designMode)
{
viewModel = new TDesignViewModel();
wasCreated = true;
}
else
{
if (shareInstances)
{
viewModel = (TViewModel)sharedInstances.CreateOrGetValue(
typeof(TViewModel),
() => new TViewModel(), out wasCreated);
}
else
{
viewModel = new TViewModel();
wasCreated = true;
}
}
 
viewModel.OnLocated(wasCreated);
return viewModel;
}
}

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.

After

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
public TViewModel ViewModel
{
get
{
TViewModel viewModel;
bool designMode = DetectDesignMode();
 
if (designMode)
{
// At design time instantiate design time version.
// This populates mock data, dependencies don't have to be real.
viewModel = new TDesignViewModel();
}
else
{
// Request IoC container to resolve view model & its deps.
viewModel =
ApplicationHost.Current.Container.Resolve<TViewModel>();
}
 
viewModel.OnLocated(wasCreated);
return viewModel;
}
}

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.

Before

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
public class MainViewModelFactory
: ViewModelFactory<MainViewModel, MainViewModelDesign>
{
}
 
/// <summary>
/// Design time version of the MainViewModel.
/// </summary>
public class MainViewModelDesign : MainViewModel
{
public override void OnLocated(bool newInstance)
{
#if DEBUG
// This gets called at design time.
this.Stories = new ObservableCollection<Story>();
this.Stories.Add(
new Story("The Windows Blog", "Upping our game..."));
this.Stories.Add(
new Story("Robot Overlords", "Nevada Passes Law..."));
this.Stories.Add(
new Story("TechCrunch", "eBay Acquired Magento..."));
this.Stories.Add(
new Story("Inside Facebook", "Facebook Testing..."));
this.Stories.Add(
new Story("FOSS Patents", "Eastman Kodak v..."));
#endif
}
}
 
public class MainViewModel : BaseViewModel
{
private Database db = null;
 
public MainViewModel()
{
}
 
public override void OnLocated(bool newInstance)
{
// This gets called at run time.
// Gah! Bad me. Wish I knew how to fix this.
// I will learn how though!
db = ApplicationHost.Current.Container.Resolve<Database>();
this.Stories = new ObservableCollection<Story>();
 
LoadDatabase();
GetFeedStories();
}
}

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).

After

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
public class MainViewModelFactory
: ViewModelFactory<MainViewModel, MainViewModelDesign>
{
}
 
public class MainViewModelDesign : MainViewModel
{
public MainViewModelDesign()
: base(new EventAggregator(), new DesignDatabase())
{
}
 
public override void OnLocated(bool newInstance)
{
#if DEBUG
this.Stories.Add(
new Story("The Windows Blog", "Upping our game..."));
this.Stories.Add(
new Story("Robot Overlords", "Nevada Passes Law..."));
this.Stories.Add(
new Story("TechCrunch", "eBay Acquired Magento..."));
this.Stories.Add(
new Story("Inside Facebook", "Facebook Testing..."));
this.Stories.Add(
new Story("FOSS Patents", "Eastman Kodak v..."));
#endif
}
}
 
public class MainViewModel : BaseViewModel
{
private IDatabase db = null;
private IEventAggregator events = null;
private Feed feed = null;
 
public MainViewModel(IEventAggregator events, IDatabase db)
{
this.events = events;
this.events.Subscribe(this);
this.db = db;
 
this.Stories = new ObservableCollection<Story>();
}
 
public override void OnLocated(bool newInstance)
{
LoadDatabase();
GetFeedStories();
}
}

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
public class DesignDatabase : IDatabase
{
public Feed GetFeed()
{
return new Feed();
}
 
public void SaveFeed(Feed feed)
{
}
 
public void Reset()
{
}
}

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
private void InitApplicationHost()
{
events = new EventAggregator();
db = new Database();
 
ApplicationHost.Current.Container.Register<EventAggregator>(events);
ApplicationHost.Current.Container.Register<Database>(db);
}

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
private void InitApplicationHost()
{
var container = ApplicationHost.Current.Container;
 
db = new Database();
 
container.Register<IEventAggregator>(new EventAggregator());
container.Register<IDatabase>(db);
 
container.Register<MainViewModel>(c => new MainViewModel(
c.Resolve<IEventAggregator>(),
c.Resolve<IDatabase>()));
 
container.Register<BrowserViewModel>(c => new BrowserViewModel());
 
container.Register<SettingsViewModel>(c => new SettingsViewModel(
c.Resolve<IDatabase>()));
 
container.Register<NavigationManager>(c => new NavigationManager(
c.Resolve<IEventAggregator>()));
}

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!

Series

  • Pingback: Windows Client Developer Roundup 076 for 7/25/2011 - Pete Brown's 10rem.net

  • Pingback: Refactoring MVVM inclusive IoC Part 1 « Pocketmobile's Blog

  • Igor

    Interesting. Looking forward for part 2.

  • Pingback: Windows Client Developer Roundup 078 for 8/15/2011 - Pete Brown's 10rem.net

  • bitbonk

    It would be really cool to see a the source code for the completely refactored application (or another stripped down example). ;)

  • Tim

    Meh. I started down this road too of Design vs. Runtime ViewModels until things just go sooo smelly I had to take a step back. Finally, we came up with a very nice and reusable pattern for things, but were able to have 1, and only 1 ViewModel to maintain. I got tired of having to update an Interface, then the “main” ViewModel, then the “design” ViewModel. Just to add one property for “design-ability”!

    Finally I came up with a Repository pattern where the ViewModels would accept and IEntityRepository (most everything revolved around EF) which itself inherited from IRepository. We were then able to pass in a “desgin” Repository vs. the “real” Repository at runtime. This left us with VERY clean code and only two different ways of constructing the SAME ViewModel in the ViewModelLocator.

  • kellabyte

    Tim,

    If you look at my design time view model you’ll see that I’m inheriting from the runtime view model. This means I don’t have to maintain 2 sets of in-sync properties. All I have to do is populate the mock design-time data.

    I have found this to be a very clean approach. Most of my time is spent in the runtime version of the view model and I only update the design time one when I need to add design-time data which you would have to do anyways in your design Repository you mention.

    I also have no ViewModelLocator to maintain. ViewModelFactory is built once and from then on the construction is fully capable of happening in Blend by the designer by a few easy picker dialogs.

    As always there are different ways to solve the same problem but I’m not sure I agree that this method becomes smelly or hard to maintain. In fact it sounds like it requires the same amount of work as your IRepository method.

  • http://www.howdoicode.net Pravin

    Hey, nice blog post.

    But it’s too hard for me to see the code. The background color of entire page and background of code section is same or something close. I am using Chrome. Could you do something about it?