Friday, 29 October 2010

MVVM – Is it Worth the Pain?

After finding it very easy to get MVVM working in WPF with IronPython, I thought it would be trivial to achieve the same thing in Silverlight. Unfortunately, my bindings didn’t work at all after porting a simple game to Silverlight. The problem may have something to do with the issues described in this blog post, but since I needed to demo my code for a local user group event, I abandoned MVVM and went back to just talking directly to the controls from within my ViewModel, which worked perfectly, and simplified my code considerably. It made me wonder why I was using MVVM in the first place.

The Pain of MVVM

I jumped on the bandwagon fairly early and have been writing the majority of my WPF and Silverlight code using MVVM. But to be honest, it has not been plain sailing. There is a real elegance to it that I like, and I love the testability, but there have been plenty of pain points.

For example, triggering animations and discovering when they have finished from the ViewModel has been a nightmare. I’ve tried various solutions, finding one that works with Silverlight and one with WPF but none that work with both, and have managed to crash Visual Studio dozens of times in the process.

Even simple things like setting the focus to the appropriate controls requires a rather convoluted system of “behaviours”, to do something that is a single line of code with access to the controls themselves. And every time I create a behaviour I seem to spend ages debugging my dependency properties, trying to work out why they aren’t doing what I expected.

The Purpose of MVVM

So if MVVM is so painful for non-trivial applications, why use it at all? What’s the point of MVVM? I think there are three answers.

1. Testability

The first driver for using MVVM is testability. If we put our logic in the C# “code-behind” of a XAML class, then running unit tests on that logic becomes very difficult. But with IronPython, that consideration is irrelevant. Since it is a dynamic language, and we are not using “code-behind” in any case, my non-MVVM version of my ViewModel is just as testable as the one that used data binding exclusively.

2. Data Binding

The second motivation for using MVVM is that the pattern encourages the use of data binding, and simplifies it considerably by removing the need for data converters or complicated binding expressions. But why is data-binding to a TextBox better than just getting or setting its Text property?

One of the key benefits of data-binding comes when we want to bind the same thing to more than one property. A Command object is a good example. One Command object could be bound to a drop-down menu and a toolbar button. So setting the Command’s IsEnabled state can be used to enable and disable both views. But most of the time, binding is a one-to-one relationship.

Data binding also saves a bunch of code in CRUD type applications where you are binding directly to properties on an existing model type, but I don’t tend to write applications like that anyway. I think you can use it to make magical things happen with input validation too, but again, it’s not something I’ve ever needed.

3. Designability

The third driver behind MVVM is the goal of designer / developer separation. The idea is that a designer can create a XAML file and bind it to test data, and then the developer can come along and create the real DataContext at a later date. The idea certainly sound impressive, but I can’t help but think that the designer will run into all the problems mentioned above if he actually wants to give his XAML GUI a real workout. And the truth is that I’ve never worked with a designer writing XAML and will not be doing so in the foreseeable future. The graphic designers we use send us bitmaps and Flash mockups.

A Hybrid Approach

I am now wondering whether I should think of my ViewModel more as a “Presenter”. It could still be the DataContext of the object defined in XAML to enable data-binding where required, but it would also have access directly to any properties on that XAML object. For testability in statically typed languages, you could define an interface with methods like StartAnimation or SetFocusToTextBox – a little cumbersome perhaps, but probably no more so than the hoops you have to jump through to make these things happen from your ViewModel using nothing but data binding.

Anyway, looks like I’m not alone in questioning MVVM. Here’s a good post from K Scott Allen. What do you think? Does MVVM fail a cost-benefit analysis for the types of application you work on?

Post a Comment