MVC as a pattern has many interpretations, but an interpretation I think is common goes as follows:
- Model - database abstraction/persistence
- View - templates
- Controller - all the code that interprets the request, interacts with models, and sets up and renders a template
There is a distinct problem with this, and it's that the controller is bloated with all manner of code - things which don't seem bottom-up enough to be part of the model, or code to pre-chew model data for the benefit of dumb templates. This leads to controllers dozens of lines long that are difficult to read as a whole.
In my code (Django code, where controllers are called views) I have been try to avoid this, for a long while now. Since controllers constitute the glue between request, model interaction and setting up of the view, I read these frequently to determine how the application is glued together. Therefore I've found them to benefit from being as short and transparent as possible.
These facts should be immediately visible on reading the code of a controller:
- What are the input parameters from the request (GET/POST/Cookies/Headers/Session Vars)
- How those parameters are interpreted/validated (their domain)
- What operation the request performs
- What variables are passed to the template system
I think it's worth formularising this. My take would be something like this:
A controller should contain no code other than these distinct phases:
- Unpacking the request parameters/validating the request.
- Invoking an operation, defined elsewhere.
- Setting up the context for template rendering.
These can even be labelled as such.
I've conflated unpacking/validating because these can generally be stated succinctly together, using trivial code. For example, in Django, you'd see code like this:
def category(request, category_id): category = get_object_or_404(Category, id=category_id)
which I think succinctly comprises these facts:
- The controller named category receives a parameter category_id
- The valid domain of category_id is the set of all Category ids
- If category_id is outside that domain, Http404 is raised
When identifying the business logic of a view, I've found that when the code enacting this grows to more than a couple of lines it's best either to be put into a form's .save() method (thus a form basically defines one operation on a mixed bag of unvalidated input), or into model methods (usually for simple model manipulation), or into a separate class that defines more complicated business logic.
When reading the template context setup, I want to know, when writing templates, what variables I have. Thus this should be explicit in the code of the controller I'm looking at.