Sometimes we have some business logic represented in the controller code of our applications. This is usually logic that differentiates what methods to call from the model and/or what arguments to pass them.

Another example of this is a set of utility functions that exist in the controller that may work to format or sanitize data returned from the model, according to a set of business rules.

This works, but I am wondering if its flirting with disaster. If there is business logic shared between controller and model the two layers are no longer separable, and someone inheriting the code may be confused by this unevenness in location of business logic related code.

My question is how much business logic should be allowed in the controller and in what circumstances, if any?

6 Answers
6

Ideally none

But that's not always possible. I can't give you hard numbers like 20% or 10 lines, that is subjective to the point it can't be answered. I can describe how I use design patterns and circumstances that necessitate bending them slightly.

In my mind it's entirely up to the purpose of the application. Building a simple REST api to post to? Forget about clean separation or even a pattern. You can churn out a working version in under an hour. Building something bigger? Probably best to work on it.

Building individually contained systems is the goal. If you start writing business logic that is specific to how two systems interact that is a problem. Without looking further into it I can't give an opinion.

Design patterns are molds, some like to strictly adhere to them on the basis of principal and well-written code. Strictly adhering to a pattern probably won't give you bad code, but it could take more time and cause you to write much more code.

Design patterns are flexible, adjust them to suit your needs. Bend them too much and they break though. Know what you need and pick a design pattern closest to that.

The controller should be concerned with accepting the request, asking the correct domain service to process the request, and handing off the response to the correct view.

In that process, all of the "business logic" should exist in the domain services.

If you have functionality that takes domain objects and creates viewmodels out of them, then that can reasonably coexist with the controller. But that should be code that exists only for the sake of the corresponding views. If there is a business-level rule about data sanitization, that should exist in your domain/service level (with the approriate unit tests).

Controllers should delegate tasks such as retrieving a record from the data store by way of an abstracted service/repository layer and passing data back into the data store by the same (or related) service. As for the mechanics and finer-workings between those operations, usually they belong somewhere other than the controller.

I often find myself adding small data sanitation methods to my controllers which save data back to the store and although this is an effective solution, it doesn't fit well with the intended role of the controller. Ideally, anything that will be modifying, validating, or parsing your model should occur very near to- if not within- the model itself. For example, if you need to 'clean' a model object before you store it, consider having a SanitizeInputs() method on the model or as part of the service which handles storing the model.

Like many other interesting concepts in programming, MVC is a powerful paradigm to bring structure and focus to a family of close or similar strategies to implement certain scenarios.

Like many other programming concepts, MVC simplifies reality, discards small details and provides a crude wireframe model to follow. Like many other simplifications of reality it does it job ny bringing stucture into chaos as seen by a human mind.

Still, like many other programming concepts, MVS is just a simplification of reality. It's not perfect and it's not thorough. Which is why it is not possible to fit a real world scenario into a oversimplified model. Hence arise many questions similar to this one.

How much logic should go into a controller?

Whether a view should contain any conditional logic?

Whether a model should contain any additional data not found directly in business entities?

These are all questions born in an attempt to adjust the code to fit the conceptual idea of MVC precisely and completely.

My answer to you is don't try to. MVC provides structure. Build your application around this foundation but don't expect it to fit perfectly. There will be deviations, it's normal. Just watch to keep them under control.

The term "business logic" is one that is often confusing because people have different opinions about what this means. In my view, the term "business logic" covers two areas

Domain Logic

Application Logic

Domain Logic is logic related to the core area that you business relates to, so if writing an application for accountants, then tax rules, book keeping rules, etc. are part of domain logic.

Application logic is logic related to the fact that you are running a computer program. This can be stuff such as CSV import export, wizards, etc. Could also contain stuff like creating forgotten password emails.

The kind of "business logic" that you can place in the controller layer is Application logic. Maybe not all application logic should go there. But you should never place domain logic in the controller layer. That should obviously be in the domain layer.

You were talking about logic to format or sanitize data. Formatting must definately be application logic. Sanitizing on the other hand could be domain logic, if sanitizing data is based on domain rules. That depends on the context.

From a pragmatic point of view I have found that you either end up with logic in your controller or controller behavior in your model when you are trying to do something that there is not a good pattern-compliant approach for. Doubly so if you are writing an app that does not have a big infrastructure behind it.

You can go either way, but I usually try to think if the weird bit is likely to show up in more than one controller action, if so it goes in the model. If that is unclear, I try to think if it is more "fitting" in one place than the other. Failing that I usually put it in the model just to keep it out of the controller (personal preference for smaller controllers and stronger data objects, YMMV)

A third option would be to reference the utility items as a separate utility class, but that is somewhat against pattern as well in the opinion of many.

Also, just because you aren't strictly following a pattern you are not necessarily flirting with disaster. Unless you really expect a significant amount of code re-use off this project I would worry a whole lot more about the project being consistent to itself (ie: don't flip-flop on where you put these bits once you pick a location) than a re-write that for some reason wants to save part of the middle of the project. Document/comment where & why you deviated from the common pattern and define the expected pattern for this application.