I always thought that the business logic has to be in the controller and that the controller, since it is the ‘middle’ part, stays static and that the model/view have to be capsuled via interfaces. That way you could change the business logic without affecting anything else, program multiple Models (one for each database/type of storage) and a dozens of views (for different platforms for example).
Now I read in this question that you should always put the business logic into the model and that the controller is deeply connected with the view.
To me, that doesn’t really make sense and implies that each time I want to have the means of supporting another database/type of storage I’ve to rewrite my whole model including the business logic.
And if I want another view, I’ve to rewrite both the view and the controller.
May someone explain why that is or if I went wrong somewhere?
ElYusubov’s answer mostly nails it, domain logic should go into the model and application logic into the controller.
Two clarifications:
- The term business logic is rather useless here, because it is ambiguous. Business logic is an umbrella term for all logic that business-people care about, separating it from mere technicalities like how to store stuff in a database or how to render it on a screen. Both domain logic (“a valid email address looks like…”) and workflows/business processes (“when a user signs up, ask for his/her email address”) are considered business logic, with the former clearly belonging in the model and the latter being application logic that goes in the controller.
- MVC is a pattern for putting stuff on a screen and allowing the user to interact with it, it does not specify storage at all. Most MVC-frameworks are full stack frameworks that go beyond mere MVC and do help you with storing your data, and because the data that should be stored are usually to be found in the model, these frameworks give you convenient ways of storing your model-data in a database, but that has nothing to do with MVC. Ideally, models should be persistence-agnostic and switching to a different type of storage should not affect model-code at all. Full fledged architectures have a persistence layer to handle this.
11
You and large parts of the programming world seem to misunderstand what the roles of the MVC parts are. In short, they are:
Model = domain logic
View = output logic
Controller = input logic
This means that the model is responsible for the entire business logic: anything that is related to drawing widgets on a screen, driving a printer, outputting data as HTML, parsing HTTP requests, etc. etc. doesn’t belong in the model.
However, many of the modern so-called “MVC” frameworks don’t really do MVC at all, or they mis-label their parts. Quite often, what is called “model” is the persistence layer of the model, while the business logic sits in what they call the “controller”; the actual controller is usually just a central entry point with a routing table and a bit of code in the individual “controller”s to dispatch the input they receive to the correct business processes. What these frameworks call “view” is really a bit of everything: some presentation logic (View), a bit of input handling and validation (Controller), and some more business logic (Model). The lion’s share of the actual view is usually called “templates”.
You might also want to read about the Multi-Tier Architecture; where MVC is kind of one-way (the flow is Controller -> Model -> View), Multi-Tier is a two-way thing (Presentation -> Logic -> Data -> Logic -> Presentation), and quite a few frameworks that pretend to do MVC actually do Three-Tier, relabeling Presentation to View, Logic to Controller, and Data to Model.
3
To truly isolate business logic and make it separate from the presentation layer infrastructure, it should be encapsulated by application services. The MVC architecture is a way to implement the presentation layer and it should remain at that scope, delegating all business logic to these application services. Think of view models as adapters between the view and the data that needs to be displayed on and or read. The controller mediates the interaction between view models, views and application services which host the business logic.
Application services implement business use cases and are decoupled from the presentation layer, whether it be MVC or something else. In turn, application services can host transaction scripts or a domain-driven design.
For storage, the application service can reference a repository or any abstraction of a persistence mechanism. Different implementations can be supported by abstracting the data access into an interface. Typically, these abstractions are leaky and are only partially portable across implementations and it is often a futile attempt to attain full portability.
UPDATE
My suggestion is based on the Hexagonal architecture. In a hexagonal architecture, your domain model (business logic) is at the core. This core is encapsulated by application services which act as a facade. Application services are simple classes which have methods corresponding to use cases in your domain. For an in-depth discussion on application services take a look at Services in Domain-Driven Design. The code sample contains a PurchaseOrderService
which is an application service for a purchasing domain. (Note that an application service does not imply the use of domain-driven design.)
In a hexagonal architecture, an MVC presentation layer is an adapter between your domain model (business logic) and a GUI. The domain model isn’t aware of the presentation layer, but the presentation layer is aware of the domain model.
This solution certainly has moving parts than a solution which places business logic in the controller and you should weigh the drawbacks and benefits. The reason I suggest it is because I prefer to keep business logic decoupled from the presentation layer in order to combat complexity. This becomes more important as the application grows.
3
Depends on what you mean by business logic. Any “logic” that gives meaning to contents of the model should be in the model. In the linked question, the highest voted answer seems to define “business logic” as anything relating to data; this makes sense from the point of view that a business’ data is its business!
I once saw an example by the creator of Rails (I think) who was going on about exactly this – not putting “business logic” in the model. His example was a controller class and method for app registration and login – a supplied password in plaintext was encrypted before being inserted into or queried against the model (a database.)
I can’t think of a better example of something that is not controller logic and that belongs directly in the model.
The model could be an interface to myriad data stores, alleviating portability concerns. It’s here one could find confusion over wether or not the model interface is actually the “controller.”
Generally speaking, the controller links the model and view (which are the meat-and-potatoes of the app.) In Cocoa development it can be simplistic to the point where the controller is handled via the XCode GUI (controller objects and bindings.)
The GoF’s “Design Patterns” section on MVC, loosely quoted:
The MVC triad of classes is used to build user interfaces in Smalltalk-80. The Model
is the application object, the View is its screen presentation, and the Controller defines
the way the UI reacts to user input. MVC decouples views and models by establishing a
subscribe/notify protocol between them. The following diagram shows a model and three
views. We’ve left out the controllers for simplicity.
MVC is all about UIs. The focus is on the model and view – defining and displaying data. Note the “subscribe/notify protocol” – this is where your controller comes in. You can build all the views you want; so long as they adhere to the protocol you’ll never have to touch the model or controller.
If you’re talking web development specifically, IMHO many popular web frameworks are fast and loose with the term MVC and its component definitions.
1
Why don’t you introduce a service layer?
Then your controller will be lean and more readable, then your all controller functions will be pure actions.
You can decompose business logic as much as you need within the service layer. Code reusability is better and there is no impact on models and repositories.