Fat model / thin controller vs. Service layer

25,983

Solution 1

All of this depends on the intention and requirements of your application.

That said, here's my suggestion for "mid scale" (not a local restaurant, and not Twitter/Facebook) web applications.

  1. Lean Domain Modeling

    Dry POCO style objects, preferably ignorant to the MVC architecture of your web application to remain as loosely coupled from your particular implementation as possible.perhaps even class library repack-able for use in an external application, say a REST API via a WCF Web Service).

    "Model" in MVC most accurately means the model the Controller is aware of and thus the the model intended for the View.

    In smaller (often Tutorial) applications the entity models of your "Application/Domain Model Layer" are often the same instantiated objects the controller ships off to a View.

    In larger applications developers often employ the tenets of MVVM architecture and begin using separate View Model objects. The controllers often call middle-tier services that work with the unseen entities below. In this scenario, the M in MVC most accurately means the View Model.

  2. Robust Service Layer

    This does not mean obese logic, but well-written single purpose services. While coding your business logic in services outside of the model is a bit more "procedural" than it is pure "OOP", it helps a lot with loose coupling, testing, and flexible deployment (ex. n-tier deployment).

    In my personal practice, I code services both down at the data layer, which I consider my behavioral modeling of the POCO objects (persistence mechanics, low level validation, etc.), and higher level services (business/workflow function) up closer to the MVC mechanics.

  3. Lean Controllers

    I make sure my controller is merely the coach, in that it is neither the play (services) or the player (entity model or view model), but simply decides who plays what position and what play to make. My controllers do two things:

    1. Call services that interact with the entity/domain Models

    2. Prepare a View Model for the appropriate View.

    Even authenticated/authorized controller actions are done via injected services/attributes.


EDIT 1:

Keep in mind, that this does not mean your Entity/Domain Model is or must be anemic. ORMs, repositories and factories, validation or state mechanics are welcome. It only means for applications of moderate scale, the Model in MVC represents the model meant for the controller, to hand off to your View.

Hopefully this point will calm Fowler apostles who believe the anemic data model to be an anti-pattern. At the same time, it does reflect a slightly more procedural angle than OOP where it is more pure to include behavior in the modeled classes.

There is no "ultimate truth", but using this pattern you'll find it easy to build, test, and deploy your applications - while maintaining a lot of re-usability and scalability.


EDIT 2:

That said, even for modestly sized applications, over architecting (that a word nerds made up?) a system is much too common. For instance, wrapping an ORM with a repository pattern, and then writing services to use the repository... all this is good for separation of concern and such, but if your project doesn't require (and is not very likely to soon require) such things, don't build it. There is nothing wrong with skipping the repository all together, writing thin business services (ex. query classes) against an ORM, or even having your controller talk directly to it. It all depends on scale.


EDIT 3:

I wanted to note that this explanation and advice is for the context of server-side MVC architecture like ASP.Net, not for clent-side frameworks like Knockout or Backbone.

Solution 2

You need to know some more about MVC before we go ahead and discuss where to put everything. Well, if you want to follow the pattern. Otherwise you can stop reading now.

The pattern is very loosely defined. There is nothing that says how the controller, view or model should look like or how they should be structured. The pattern simply states that you should separate the parts and how they should interact with each other. So let's look at bit more about what they are (my interpretation).

MVC

Model The model can be anything. It can be a webservice, your repositories, your service classes or simply your domain models. The Model are everything that are used to get the information that you need. Consider the "Model" as a layer instead of just an single object.

Controller The controller is a glue. It takes the information from the Model and adapts it to the view and vice versa.

View The view should only render what the user sees.

Do note that you should not confuse the Model with View Models. Microsoft should really have named the "Model" folder "ViewModels" since that's what they are. I would not use information from the "Model" directly in the views. Failure to do so would mean that you have to change the Model if the View is changed and the other way around.

The answer

The model is not a view model but a layer. Everything in the model is used to fetch the information needed for the view. The controller takes that information and puts it into a single view model.

A single controller action might use one or several calls to the "Model" to be able to assemble the information needed by the view.

That means that your second option is the most correct when if you want to get an application which is easy to maintain and extend.

Do note that a service layer might not be needed. You can call the OR/M directly from the controllers. But if you find yourself duplicating code or getting fat controllers, simply move the logic to a service layer. Nothing but the controller will be affected by that change since you are using proper view models.

Share:
25,983
PeterFromCologne
Author by

PeterFromCologne

Full Stack Web Development, Software Architect, C#, SQL, MongoDB, ASP.NET, REST services, Angular and more

Updated on October 18, 2020

Comments

  • PeterFromCologne
    PeterFromCologne over 3 years

    I have been developing enterprise applications for many years using .Net My apps usually have a domain model containing entities mapping to SQL DB tables. I use a Repository pattern, Dependency injection and a service layer.

    Recently we started working on MVC 3 projects and we had a debate where to put which logic. I came accross thin Controller / FAT Model architecture and was wondering how the service layer would fit in

    Option 1 - Model talks to services

    Controller is thin, calls methods on the models. The models "know" how to load themselfs from the DB and talk to repositories or services. E.g. customerModel has a Load(id) method and loads the customer and some child objects like GetContracts().

    Option 2 - Controller talks to services

    Controller asks Services to retrieve model objects. The logic of loading / storing etc. Is in the service layer. The model is a pure entity model with data only.

    Why would option 1 be a better choice especially when we talk about enterprise applictions my experience tells me to separate concerns, keep models AND Controllers as thin as possible and have specialized services doing the Business logic (imcl. The DB interaction)

    Thanks for all advices and references to good resources.

  • Lester
    Lester over 12 years
    This is almost the exact same design pattern I use except the controller doesn't have knowledge of the repository. The controller only interacts with services who in turn interact with repositories.
  • one.beat.consumer
    one.beat.consumer over 12 years
    @Lester I edited to clear that up. 95% of the time mine don't either, the idea is that the services do. On small apps it can be overkill but its a good practice anyone and much easier to maintain with an IoC container
  • themarcuz
    themarcuz over 12 years
    +1 @one.beat.consumer: this is the same approach that I take on my projects... sometimes being too purist about the rules lead to overcomplicated solutions, and you can experience to have more benefits from a real world proven solution that doesn't perfectly follow GOF patterns
  • Hector Correa
    Hector Correa over 12 years
    I wish ASP.NET MVC had been named ASP.NET ModelView View Controller instead. It would be a horrible name but at least it would convey its true meaning :)
  • Lester
    Lester over 12 years
    It took me awhile even after using ASP.NET MVC to realize that model didn't mean view model.
  • jgauffin
    jgauffin over 12 years
    @one.beat.consumer: My point about the Model was that it can be anything. It's just a layer out there. Create it as it's fit for the application. I put it like that since so many thinks that the Model in ASP.NET MVC is the View Model or that the VM and the Model is the same.
  • jgauffin
    jgauffin over 12 years
    I do think that I address the question. My interpretion of customerModel as he talks about in the question is a view model. If he understands that it's not so the answer is more obvious.
  • one.beat.consumer
    one.beat.consumer over 12 years
    @jgauffin semantics are important here - in MVC "model" does not imply a "model layer"; it only implies a model object fit for the Controller to pass to a View. In sizable applications the MVC architecture is often not even aware of the model/data layer or whatever you choose to call it. My edited answer tries to explain this confusion... mainly when apps are small, there's often no need for the extra separation of Model and View model, so people tend to mark up their models and let the controllers use a repository, etc. In full size apps, this rarely should happen.
  • one.beat.consumer
    one.beat.consumer over 12 years
    @jgauffin think of this - what if I have no persistence and my app simply fires off an email when someone taps the action? In an OOP sense there is no "Model Layer", only a tiny DTO-like class (perhaps only a string message in ViewData/ViewBag) that that my View renders for the user. This is the "Model" in MVC... it is always present even in applications with a "model layer"
  • jgauffin
    jgauffin over 12 years
    mainly when apps are small, there's often no need for the extra separation of Model and View model. Well, yes, there is still a need for it. Without a view model, it's easy to add logic into the views to adapt the model (which leads to code duplication) or introduce security risks by using an entity model directly in the view. Also: Nothing says that the model is an object, so you are incorrect there.
  • jgauffin
    jgauffin over 12 years
    There IS a clear distinction between a view model and a model. The model is everything used to fetch information. A ViewModel is created specifically for a view. They are separate concepts. The ViewModel is borrowed from the MVVM pattern.
  • Ivo
    Ivo over 12 years
    the M of MVC is not for the view model. It's your application model (aka domain model)
  • one.beat.consumer
    one.beat.consumer over 12 years
    @ivowiblo Model in MVC is whatever data model your controller preps and passes to the View. This is why your 'application model' (domain model, model layer, whatever-you-label-it) can be completely unaware of the MVC libraries, even exist outside your solution on a separately distributed system. In MVC a request is simply routed to the controller. The controller assembles a view model (data for the presentation layer). If that model is the same instantiated object you used in your persistence mechanics, poor practice maybe, but it is allowed, meaning there is no exclusive definition.
  • jgauffin
    jgauffin over 12 years
    My reputation has nothing to do with it. My fifteen years as a developer and architect or my university degree might. If an app instantiates a Book class object, persists it somewhere, and returns it to the client in a view, the same exact reference object is performing both roles. no. It is not a view model just because you try to use it as one. A view model might transform the book list into a IEnumerable<SelectListItem> or return n/a instead of an empty string for Book.Title. A OR/M entity/model can not do that thus forcing you to put that kind of logic in the view.
  • jgauffin
    jgauffin over 12 years
    I'm not saying that it's not possible. I'm saying that it isn't a real view model (en.wikipedia.org/wiki/View_model#Viewpoint_model). And I'm saying that the Model in MVC is not a single entity but everything used to fetch the information. Hence the Layer metaphor.
  • one.beat.consumer
    one.beat.consumer over 12 years
    public ActionResult FetchApple() { return View(_groceryService.GetApple("Granny Smith")); } is pretty lean if you ask me.
  • Marvo
    Marvo about 12 years
    My reading of that FSUC article does not match Option 2 above. The example the FSUC author provides doesn't show the use of a service layer where all that ordering logic is encapsulated. Instead, it's showing that the controller has been loaded down with business logic. And the business logic's reusability, by virtue of being in a controller, is now lost.
  • Luiz Damim
    Luiz Damim over 11 years
    +1 for Keep in mind "Model" in MVC most accurately means the model the Controller is aware of and thus the the model intended for the View.
  • Rookian
    Rookian about 11 years
    Keep in mind that calling something an anti pattern needs some more context! A lot of applications don't need an domain model, because the most things they do are CRUD operations.
  • Imre L
    Imre L about 11 years
    Domain model is just a data with a "metadata", if you dont have metadata, then fine. I removed the "anti-pattern" word because you are right on that part. I really like the accepted answer and my own should have been comment instead.
  • 尤川豪
    尤川豪 about 9 years
    This answer is very practical and useful. Thanks a lot!