Over on the ASP.NET MVC (Part 1) thread on ScottGu's blog, there's a little discussion between myself and a couple of others about whether or not a controller should have any logic in it.

Doug Ramirez stated:

Each 'thing' in the model should include it's own business rules, validation rules, security, and persistance [sic] rules.

Doug was stating that Microsoft should publish best practices and guidelines for how to build MVC applications, and he was dictating that controllers should not have any logic--all logic should be housed within your business objects.

I've found that sometimes the rules belong on the model, and sometimes they don't. The pattern that I've liked using with my MVP pattern is to have a Business Manager class for each Data Model. Keep the Data Model classes as simply that -- data model/container. Then implement a Business Manager for the data model entity to perform all actions against the model. Then, when you have multiple controllers that work against a particular data model entity, they all go through the same manager.

As for data entry validation and security and whatnot though, I still put the responsibility for this on the controller, as this is presentation logic, not business logic. You can easily find a scenario where the same data entity field can be shown on 2 screens, and on one screen the field is required, but on another, it's not. With field validation on the data model, this scenario would be difficult to support.

Something I didn't expect was for a couple of folks to respond to my comment, saying that this was a bad idea. Brian posted:

So you mean to tell me that each application in an enterprise has 'to know' that product managers are the only one that have the ability to modify products? So you're going to all the way across multiple network hops just to have 'My custom description of this sku' truncated unknowingly by the database (because it's only VARCHAR(20) instead of telling the user on one hop to the web server that the description is to long...or were you going to catch a SqlException to do that?

And why would a controller, a mechanism that just decides what to render, have any logic? A controller should be nothing more than a piece of code that does navigation based upon arguments...'X requested, go to Y'; this may come from the view or the model; the view display, the model contains business rules (hopefully using some sort of business logic framework). A controller should be no smarter than your mouse driver.

As Doug pointed out, this is the perfect reason why guidance needs to be given. I have a feeling only 1/10th of the people out there using MVC have ever actually looked at the origins of MVC (SmallTalk) and find out how and why it came about. I have a feeling 9/10ths of people would realize they didn't need MVC if they had.

And then Doug also responded, with the following lengthy comment:

I'm really glad Jeff Handley responded to my comment. It's a perfect example of what I meant when I referred to Microsoft introducing technology without proper guidance.

Jeff describes a very typical mistake made in the "I must have a DAL" world of applications usually designed from an ER model and not requirements. I won't belabor this point. There are some resources available to describe why separating state management out of your business object is rarely ever needed, or used. Rocky Lhotka has blogged about this at length.

Jeff’s solution is indicative of a common approach by overzealous architects who seem to be getting “paid by the tier”. In Jeff’s solution the controllers have to know about business managers who then have to know about the data models. If you simply put the business rules, validation rules, security, and data access into an object in the model, then you wouldn’t need a bunch of managers, and the controller would simply interact with the appropriate ‘thing’ in the model. If there were more than one controller that needed to interact with a single ‘thing’ in the model, so be it. The ‘thing’ is smart. It knows its own rules, how to validate itself, and to get and save itself. This minimizes the moving parts in the framework and simplifies the development and maintainability of the application through the very simple concept of (drumroll…) encapsulation!

Data validation and security absolutely do not belong in the controller! Code reuse flies out the window when that happens, and can’t certainly support logical use cases. If a property of an entity is required, in one scenario and not in another, then 1 of 2 things is probably going on. One, the field is either required on both, or not at all and the use case is incorrect. Or, the property belongs to a different entity. But for arguments sake, let’s say you have a property of an entity that is required sometimes and sometimes it is not. Well if you’ve managed to spread you code across controllers, and managers, and data models, and even into the view, then how will your code support a system interface instead of a user interface? And, when the different sets of code required to deal with the sometimes, some not requirement it’s very likely that you will need to persist evidence of where the field came from so that the data store and other parts of the application that use the data know which of the views allowed it or didn’t in order to instantiate an object in the model appropriately from that state.

If all this sounds overly complex, it’s because it is. The tendency to take these wonderful tools from Microsoft, that are intended to make our jobs easier and our products cheaper, in an unguided direction that results in over-architected solutions that become brittle from lack of proper design happens all to often. This is precisely why I urge caution, and request that Microsoft is very careful about introducing this technology to the community.

Thanks Jeff for posting a response. It provided the opportunity to elaborate more on the problems of unguided technology introduction.

I posted another comment in response, but it hasn't shown up on the blog. It wasn't rude; I didn't jab back at Doug or anything; I thought it was a well-written and polite retort, so I'm not sure why it didn't show up. I'll follow up here with a post.