I’ve been thinking a lot about code separation, and it’s something that my coworkers and I spent a fair amount of time talking about recently. For a long time, my idea of a model in MVC was a bunch of fairly dumb objects that also handled their own persistence, and I was putting business logic into controllers. I’ve come to believe that this isn’t the best way to do things. What follows is my current view of optimal code separation, although it’s not complete, and it could change in five minutes.
Models are be dumb. Really dumb. If you’re domain is automobiles, a model might be a car. The car model could have basic properties (make, model, year, etc.), and the methods would be mostly mutators and accessors for those properties. Models have no idea how they’re persisted, or even if it’s persisted. They don’t know anything about other components in the system, except possibly other models. Models contain minimal business logic.
Services are where 99% of business logic resides. Services know about models and handle persistence of those models. A car service should probably be able to create new cars, and find, change, and delete existing cars. Permissions logic is located within services.
Since business logic is located in services, controllers are very light. They are just translators. Controllers receive input, convert it into something that services can understand, and send the necessary parameters to the appropriate views. In an application, you might have one controller for an HTML or web service interface and another for a command-line interface, but both use the same service.
Views are dumber than everything except models, and that’s because they only know about models. Because models are dumb and can’t do anything dangerous, it’s safe for controllers to pass them directly to views.
Most applications are probably going to need to check permissions in views (i.e., hide the “delete” button from certain users). Since this logic is located in services, controllers need to push this information into the views, or the views need to know about the services. I’m against views knowing about services, so I’d prefer the controllers to push the information down. I’m sure there are other problems with this design, so feel free to leave a comment or start a discussion on Twitter. I’d love to hear other opinions.