Fat model / thin controller vs. Service layer

PeterFromCologne picture PeterFromCologne · Jan 5, 2012 · Viewed 24.3k times · Source

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.

Answer

one.beat.consumer picture one.beat.consumer · Jan 12, 2012

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.