Model View Presenter - A Path Forward from WebForms
"So you read and hear about Test Driven Development, MVC Frameworks, Continuous Integration and the safety net provided by high levels of unit test coverage. But you work on a WebForms app that has been around since .NET 1.1. It has thousands of lines of code in the code behind classes and you know that isn't easy to test. How can you experience all of these wonderful things you read about? The Model View Presenter pattern is here to rescue you. We will discuss the purpose and structure of MVP as it is applied to WebForms. We will go through a demonstration of some relatively safe refactorings that allow you to start bringing your unruly code under test. We will then add tests using NUnit and Moq. We will wrap up the discussion with a road map from WebForms chaos through Model View Present into the promised land of the MVC frameworks."
Having worked on ASP.NET web sites/apps since .NET 1.0 beta 1, I have seen plenty of messy code. I have certainly added my fair share to the pile. I have seen 3,000 line code behind files, data access in the markup file and any number of things that make me cringe. If you work on a large or old ASP.NET WebForms site, I am sure you have seen it all too.
Some of the design decisions of the WebForms team have made it really easy to make a mess. That is unfortunate, but it is what it is. WebForms has accomplished its goal of getting VB6 developers into web programming, and, I for one am happy that I was able to easily make that move. The problem many of us face now is that we created web applications without truly understanding web technologies and now we feel like we are stuck in a swamp with no way out.
Software development has changed a lot in the last 10 years. Automated testing has gone from fringe to mainstream. Many development shops require unit tests and even TDD. ATDD is becoming a big deal. MVC frameworks, such as Rails, FubuMVC, OpenRasta or even ASP.NET MVC, have taken over the web. Object oriented design principles such as low coupling and high cohesion, SOLID and patterns are hot topics in the industry.
So as a developer, you want to know about and use all these cool, new things, right? But your code sucks. You can't see any way to use any of these tools or techniques without a rewrite of the system. And the short sited management still puts the business' needs ahead of your career development. Fortunately, there is hope!
Model View Presenter, specifically Passive View, provides a path from where you are to where you want to be.
thanks to Scott Denham for the image
To see an example of refactoring a WebForms application to implement the MVP pattern, walk through the commits on this github repository.
Now that you know how to refactor your code, what have you bought with all that hard work? The bad news is, you have added complexity to the code base. The good news is you are now ready to start implementing several of the patterns you wanted in the first place:
- Test Driven Development - Breaking your dependencies allows you to really test isolated units of your code. You can start to write these tests before you write the code that makes them pass.
- Inversion of Control - Speaking of breaking dependencies, injecting your dependencies makes it really easy to hand off object construction to an IoC container as well.
- MVC - You probably already noticed that HandleSomeEvent() methods look an awful lot like ASP.NET MVC actions. And the fact that you already have ViewModels makes the MVC transition that much simpler. Using DI and an IoC container take you even closer.
- Domain Driven Design - Pushing the business logic out of the UI is just the first step. Now you can start to push it out of the Application Layer and into your Domain Model where it belongs.
- Acceptance Test Driven Development - When you have a classic WebForms app, where do you hook your FitNesse fixtures? You know the UI is the wrong answer because of the problems you had with WatiN, Watir, Selenium and other UI testing tools. Presenters introduce an Application Layer (or Service Layer) into your app that make ATDD not just possible, but actually pretty easy.
That's about it. MVP isn't a destination, it is just a step on the path to something better. The best part of the pattern is that it allows you to take small, iterative steps forward.