What's the pros and cons of using a Model-View-Controller model in building your application?
Model-View-Controller Pros and Cons
design-patternsmodel-view-controller
Related Solutions
Model-View-Presenter
In MVP, the Presenter contains the UI business logic for the View. All invocations from the View delegate directly to the Presenter. The Presenter is also decoupled directly from the View and talks to it through an interface. This is to allow mocking of the View in a unit test. One common attribute of MVP is that there has to be a lot of two-way dispatching. For example, when someone clicks the "Save" button, the event handler delegates to the Presenter's "OnSave" method. Once the save is completed, the Presenter will then call back the View through its interface so that the View can display that the save has completed.
MVP tends to be a very natural pattern for achieving separated presentation in WebForms. The reason is that the View is always created first by the ASP.NET runtime. You can find out more about both variants.
Two primary variations
Passive View: The View is as dumb as possible and contains almost zero logic. A Presenter is a middle man that talks to the View and the Model. The View and Model are completely shielded from one another. The Model may raise events, but the Presenter subscribes to them for updating the View. In Passive View there is no direct data binding, instead, the View exposes setter properties that the Presenter uses to set the data. All state is managed in the Presenter and not the View.
- Pro: maximum testability surface; clean separation of the View and Model
- Con: more work (for example all the setter properties) as you are doing all the data binding yourself.
Supervising Controller: The Presenter handles user gestures. The View binds to the Model directly through data binding. In this case, it's the Presenter's job to pass off the Model to the View so that it can bind to it. The Presenter will also contain logic for gestures like pressing a button, navigation, etc.
- Pro: by leveraging data binding the amount of code is reduced.
- Con: there's a less testable surface (because of data binding), and there's less encapsulation in the View since it talks directly to the Model.
Model-View-Controller
In the MVC, the Controller is responsible for determining which View to display in response to any action including when the application loads. This differs from MVP where actions route through the View to the Presenter. In MVC, every action in the View correlates with a call to a Controller along with an action. In the web, each action involves a call to a URL on the other side of which there is a Controller who responds. Once that Controller has completed its processing, it will return the correct View. The sequence continues in that manner throughout the life of the application:
Action in the View -> Call to Controller -> Controller Logic -> Controller returns the View.
One other big difference about MVC is that the View does not directly bind to the Model. The view simply renders and is completely stateless. In implementations of MVC, the View usually will not have any logic in the code behind. This is contrary to MVP where it is absolutely necessary because, if the View does not delegate to the Presenter, it will never get called.
Presentation Model
One other pattern to look at is the Presentation Model pattern. In this pattern, there is no Presenter. Instead, the View binds directly to a Presentation Model. The Presentation Model is a Model crafted specifically for the View. This means this Model can expose properties that one would never put on a domain model as it would be a violation of separation-of-concerns. In this case, the Presentation Model binds to the domain model and may subscribe to events coming from that Model. The View then subscribes to events coming from the Presentation Model and updates itself accordingly. The Presentation Model can expose commands which the view uses for invoking actions. The advantage of this approach is that you can essentially remove the code-behind altogether as the PM completely encapsulates all of the behavior for the view. This pattern is a very strong candidate for use in WPF applications and is also called Model-View-ViewModel.
There is a MSDN article about the Presentation Model and a section in the Composite Application Guidance for WPF (former Prism) about Separated Presentation Patterns
With "Anemic Domain Model" being anti-pattern, why are there so many systems that implement this?
I think there are several reasons
1. Complexity of the system
In a simple system (which is almost all the examples and sample code you find on internet) if I want to implement:
Adding product to Order
I put this function on the Order
public void Order.AddOrderLine(Product product)
{
OrderLines.Add(new OrderLine(product));
}
Nice and super object oriented.
Now let's say that I need to make sure that I need to validate that the product exists in inventory and throw exception if it doesn't.
I can't really put it on Order any longer, since I don't want my order to be dependent on Inventory, so now it needs to go on the service
public void OrderService.AddOrderLine(Order order, Product product)
{
if (!InventoryService.Has(product)
throw new AddProductException
order.AddOrderLine(product);
}
I could also pass IInventoryService to Order.AddOrderLine, which is another option, but that still makes Order dependent on InventoryService.
There is still some functionality in Order.AddOrderLine, but usually it is limited to Order scope, while in my experience there is a lot more Business Logic out of Order scope.
When the system is more then just basic CRUD, you will end up with most of your logic in OrderService and very little in Order.
2. Developer's view of OOP
There are a lot of heated discussions on the internet about which logic should go on entities.
Something like
Order.Save
Should Order know how to save itself or not? Let's say we have repositories for that.
Now can Order add order lines? If I try to make sense of it using simple English, it doesn't really make sense either. User adds Product to Order, so should we do User.AddOrderLineToOrder()? That seems like overkill.
How about OrderService.AddOrderLine(). Now it kinda makes sense!
My understanding of OOP is that for encapsulation you put functions on classes where the function will need to access class's internal state. If I need to access Order.OrderLines collection, I put Order.AddOrderLine() on Order. This way class's internal state doesn't get exposed.
3. IoC Containers
Systems that use IoC containers are usually fully anemic.
It is because you can test your services/repositories which have interfaces, but can't test domain objects (easily), unless you put interfaces on all of them.
Since "IoC" is currently lauded as solution for all your programming problems, a lot of people blindly follow it and this way end up with Anemic Domain Models.
4. OOP is hard, procedural is easy
I have a bit of a "Curse of Knowledge" on this one, but I have discovered that for newer developers having DTOs and Services is a lot easier than Rich Domain.
Possibly it is because with Rich Domain it is more difficult to know on which classes to put the logic. When to create new classes? Which patterns to use? etc..
With stateless services you just slap it in the service with closest name.
Best Solution
Pros
Cons .. I cant think of many