77

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?

Steffen Winkler
  • 905
  • 1
  • 8
  • 11

5 Answers5

78

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.
Waquo
  • 2,541
  • 21
  • 11
  • oh my god. I feel so stupid right now. The worst? I actually taught a few people to program the way I explained above! So let me get this straight: It's, in reality, like this: {MVC-design}-{adapter for a database/storage}-{storage}? – Steffen Winkler Nov 21 '12 at 09:07
  • 4
    Most MVC-frameworks kind of mix all the storage/database stuff into the model in order to make it easy to store your models (often by making you extend the frameworks model-class). This is probably the source of confusion. Technically, the model-code you write should be the actual model (domain layer), whereas the code provided by the framework should deal with storage (persistence layer). For example, something like User.find(...) (with User being a model) works because the framework implemented the repository pattern as part of the Model. – Waquo Nov 21 '12 at 09:29
  • About the first part of your comment: unsure, could also be that I really misunderstood it when I read about it. [myframework(MVC-Design)<->(persistent data storage)] like that? (I need to visualize things like that to fully understand it) – Steffen Winkler Nov 21 '12 at 09:38
  • 3
    View-Controller-Model-Storage is the general principle (although the relationship between M, V and C should be visualized as a triangle). When your framework mixes storage into their "model", it works kind of like this: View-Controller-(Model inherits storage from framework). – Waquo Nov 21 '12 at 09:48
  • 2
    View-Controller-Model-Storage is rather crude, because it shouldn't be flat. For example, when a controller does something like User.find(...) to get a model, it asks the storage layer directly rather than going through the domain layer. – Waquo Nov 21 '12 at 09:54
  • ah great, just add more confusion. I'd have thought that the Model would do the User.find(). By implementing a static method in the User class but the way you use the word 'model' makes me think that I've something missunderstood there, too. To me, the model is a bunch of classes/structs and a singleton (runtime data storage) and an interface to the assembly that interacts with the database. – Steffen Winkler Nov 21 '12 at 10:18
  • 2
    In architectures with more careful layering, it would be something like UserRepository.find(). By "model" I meant the "model"-class provided by the framework, which you inherit from. The User-object returned by User.find() is a model of a user in the sense that somebody modeled what a user is, how a user behaves... – Waquo Nov 21 '12 at 10:34
  • I have a hard time separating application logic from business logic because (in my opinion) the vast majority of code ends up being application logic. Let's pretend the task is **accept payment via credit card**. Calculating total cost may be business logic, but sending data to a web service for CC processing and storing the response in a database and sending a purchase confirmation email all sound like application logic to me, which sounds like it would result in fat controllers. I keep wandering down this path of one "execute" action per controller, which just sounds wrong. – flipdoubt Jan 28 '18 at 14:32
  • 1
    @flipdoubt business logic is any logic that should be kept the same if you ported from mvc to say a uwp app. – Andy Oct 09 '19 at 22:53
  • @Andy I like the way you put that, as it gives me something actionable to think about. Quick example: I have a user story for saving attachments with a record. Is saving the file to disk application logic or business logic? I need to do that regardless of the platform. What about streaming file data from the request rather than buffering it all while saving? – flipdoubt Oct 13 '19 at 15:49
  • 1
    @flipdoubt The business logic is that some arbirtrary byte data needs to be saved with your record. How the byte data is loaded int your BO depends on your application; it will be different in WinForms than an MVC app how you read the binary data. Streaming of course is an HTTP concern, so that's your application logic. – Andy Oct 13 '19 at 23:01
28

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.

tdammers
  • 52,406
  • 14
  • 106
  • 154
  • 3
    I believe you misrepresent the Model ("Model = domain logic"), to my mind it is more a vessel for population with data, which is then rendered using a View, in the purest form of the MVC pattern. Sure in really simple use cases you can treat it as the "domain logic" but I'd vouch that most systems worth existing would outgrow that very quickly. Better to split "domain logic" out into a separate layer/class, e.g. a service layer. – A. Murray Oct 10 '13 at 13:41
  • @A.Murray: Of course the Model doesn't have to be one monolithic blob of code, and separating it out into persistence, data structures, and domain logic does usually make a lot of sense. Still, MVC groups these three concerns together in the Model. In any case, when your controllers and views contain domain logic, it's no longer real MVC. – tdammers Oct 11 '13 at 08:46
  • @tdammers, I like the tidiness of your answer and its focus on logic. In your view, where do application concerns like persistence and transaction processing belong? Seems like MVC should be a four letter acronym like MVCS where the S is for service. – flipdoubt Jan 28 '18 at 14:19
16

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.

eulerfx
  • 1,222
  • 7
  • 8
  • Sounds like you're describing a bastard of MVC and MVVM that has both controllers and view models. Also, I think the architecture you're describing may be a bit heavy for OP's needs. – Waquo Nov 21 '12 at 09:05
  • to be honest, I like Waquo's answer more. Mainly because I've no clue what you mean with 'application services'. Could you explain that term? My GoogleFU isn't working here as it seems. – Steffen Winkler Nov 21 '12 at 09:26
  • 1
    @Waquo I agree that the proposed architecture may be overkill, however it should be considered. I've made no mention of MVVM which is simply another way to implement a presentation layer. Application services apply regardless of whether you use MVC or MVVM and nothing I've suggested indicates any combination of the two. – eulerfx Nov 21 '12 at 17:44
1

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.

Duke
  • 171
  • 2
  • I'm a C#/Java (only a few projects there) developer. It seems that I misunderstood what the model does. Putting the 'business logic' into the controller really was only a aftereffect (my train of thought went 'okay, I've the model for data (read: database connection/storage), so my business logic needs to get in the controller because I've to apply it before storing the data in the database'. Just have to move everything one level down from the controller. Actually, that solves a problem I currently had (supporting MySQL and MSSQL in one program) – Steffen Winkler Nov 21 '12 at 09:24
0

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.

orad
  • 103
  • 3
Anil
  • 109
  • 2