MVP Is Not Loosely Coupled, Oh My!
Chris This is something that comes across the CAB message boards frequently. People who are new to the Component UI Application Block look at the way MVP is implemented in the reference implementations, and one of their first observations is: “But it’s not loosely coupled!”
My response: That’s not the reason to be doing MVP.
This is just my own observation, but I think there’s a general misunderstanding at times when it comes to Model-View-Presenter. Some people think it exists to promote “loosely coupled” code, but that’s not really the case. That’s not really why we do MVP.
Model-View-Presenter, and it’s cousin Model-View-Controller, exist for two very important reasons, and neither one of them has anything to do with loose coupling. Oh, don’t get me wrong: loose coupling in an object-oriented application is generally a good thing. With loose coupling we can be more agile in our development process; we can enact change at the customer’s request without breaking other systems, and that’s good for flexibility. That’s good design.
But loose coupling isn’t why we do MVP. We do MVP for two reasons: (1) Clear separation of concerns which leads to (2) easier testability.
If you think about it, it all makes perfect sense. What is a view without a presenter? What is a presenter without a view? These objects are the perfect example of a symbiotic relationship. One cannot really exist without the other (well they can, but then they’d be useless). A view is just dumb user interface code without a presenter to manipulate it. A presenter is just useless business and application logic without a view to display it to the user. And both of these objects need to know about the other in some way, because they’re going to be dealing with specific business data. Would it make any sense to attach the presenter for Ice Cream Inventory Management to the view for Oil Change Orders?
There was a time, not so long ago, when these two objects were one. We simply referred to them as a “Windows Form” or a “Web Page.” The UI code was intermingled with the application logic and business logic, and what you ended up with was a big mess of code that wasn’t easy to change and even more difficult (if not impossible) to test.
Then came MVC and MVP. Granted, these two patterns have been around since SmallTalk, and maybe in the SmallTalk world they existed to promote loose coupling. But if that was the case then, it’s not the case now.
The biggest advantage to MVP is testability. Presenters reference a view via its interface, and that’s the key to making mocks happen - to removing the real view from the testing equation. We wouldn’t need to perform this step if we simply wanted to have a clear separation of concerns; if that was the case we could just use concrete views, and as long as the view and presenter code were separated we’d be keeping a clean house. But with an interface we enable automated testing; we enable the view to be replaced with a mock object that implements the same interface. With a properly mocked view we are now free to test the presenter’s logic with a test framework like NUnit. And that’s the real goal here: testability. Testing gives us, and the customer, confidence in the code. It gives developers confidence to refactor. And that makes the MVP pattern worth its weight in gold.
What’s not to be overlooked in all of this is the separation of concerns. It’s not the same thing as loose coupling, but it is no less beneficial to a large application. Programming a large business application can require many pieces of a large puzzle. Code should be easy to navigate and refactor. Determining when and where to make changes to a system should be something that is painless and easy. Developers shouldn’t have to hunt down the location of code; they shouldn’t have to dig through large classes and intermingled logic to find the relevent lines of code they need so they can make a change. They should know, almost intuitively, where to go to find code related to the User Interface, or code related to the application logic. Separating our code and giving objects clear responsibilities makes development easier, and it makes our code better. A presenter and a view are, after all, objects. They should adhere to our basic object oriented rules on encapsulation and responsibilities.
Clear separation of concerns is just good object oriented practice. Think of objects like vendors at a football stadium. They each have their own section of the stadium that they are responsible for. The peanut vendor in section A3 shouldn’t also be responsible for selling hot dogs in section F6. Our view shouldn’t be handling business logic or application logic; it should just be handling view logic. In the long run, this makes for an easier system to develop and an easier system to maintain.
Sure, there’s a bonus to all of this: you could potentially swap one view for another using the same presenter, as long as both of those views implement the same interface. And you could do the opposite as well, if you really want to expend the effort, and make your presenter implement an interface. Then you could swap presenters on the same view. But those capabilities are a side-effect of MVP, not the reason for doing it. It’s like skipping through commercials on TiVo. It’s a neat thing to be able to do, but the real reason to own a DVR is so you can record television shows that you can’t find time to watch in real time.
In practice, swapping views/presenters doesn’t happen very often outside of testing (and just as I say “not very often” five people will raise their hand and say, “but we do it all the time!” And you would be the folks who make the “not very often” statement reality, instead of it being “never”). And it shouldn’t happen very often unless there’s some darn good business reason to do so. And if there is some darn good business reason for frequently swapping views/presenters, then you probably need more than MVP. You need a truly pluggable component model architecture. For most of us who are building business applications with a lot of specific business logic that needs testing, that’s not what we really need to do. What we’re after is providing customers with business value. Getting data to the screen in a format the customer can understand and make use of, and ensuring the quality of the code through rigorous testing.
That’s why we do MVP.
So when you see MVP in CAB and realize it’s not loosely coupled, don’t freak out. Those two objects - the view and the presenter - would normally be one object. But they’re separated for very good reasons, and it’s not for the exclusive purpose of promoting loose coupling.
There’s a method to the madness.
Posted in .NET |
No Comments »