Understanding MVC: Whats the Concept of "Fat" on Models, "Skinny" on Controllers

Understanding MVC: Whats the concept of Fat on models, Skinny on controllers?

Your application is the M. It should be able to stand independent from V and C. V and C form the User Interface to your application. Whether this is a web interface or a command line interface shouldn't matter for the core business logic of your application to run. You want the model to be fat with business logic.

If you have a fat controller instead, e.g. full with business logic, you are not adhering to the purpose of MVC. A controller's sole responsibility is handling and delegating UI requests to the Model. That's why it should be skinny. It should only contain code necessary for what it's responsible for.

Simplified Example

public function fooAction()
{
if(isset($_POST['bar'])) {
$bar = Sanitizer::sanitize($_POST['bar']);
$rows = $this->database->query('SELECT * from table');
try {
foreach($rows as $row) {
$row->foo = $bar;
$row->save();
}
} catch (Exception $e) {
$this->render('errorPage');
exit;
}
$this->render('successPage');
} else {
$this->render('fooPage');
}
}

When it should be

public function fooAction()
{
if(isset($_POST['bar'])) {
$success = $this->tableGateway->updateFoo($_GET['bar']);
$page = $success ? 'successPage' : 'errorPage';
$this->render($page);
} else {
$this->render('fooPage');
}
}

because that's all the controller needs to know. It should not update the rows. It should just tell the model that someone requested this change. Updating is the responsibility of the class managing the rows. Also, the controller does not necessarily have to sanitize the value.

As for Q2 and Q3, please see my answer to Can I call a Model from the View.

Fat models and skinny controllers sounds like creating God models

It might not be the best idea to look at Rails as a staple of MVC design pattern. Said framework was made with some inherent shortcomings (I kinda elaborated on it in a different post) and the community only just now has begun addressing the fallout. You could look at DataMapper2 development as the first major step.

Some theory

People giving that advice seem to be afflicted by a quite common misconception. So let me begin by clearing it up: Model, in modern MVC design pattern, is NOT a class or object. Model is a layer.

The core idea behind MVC pattern is Separation of Concerns and the first step in it is the division between presentation layer and model layers. Just like the presentation layer breaks down into controllers (instances, responsible for dealing with user input), views (instances, responsible for UI logic) and templates/layouts, so does the model layer.

The major parts that the model layer consists of are:

  • Domain Objects

    Also known as domain entities, business objects, or model objects (I dislike that latter name because it just adds to the confusion). These structures are what people usually mistakenly call "models". They are responsible for containing business rules (all the math and validation for specific unit of domain logic).

  • Storage Abstractions:

    Usually implemented using data mapper pattern (do not confuse with ORMs, which have abused this name). These instances usually are tasked with information storage-from and retrieval-into the domain objects. Each domain object can have several mappers, just like there are several forms of storage (DB, cache, session, cookies, /dev/null).

  • Services:

    Structures responsible for application logic (that is, interaction between domain objects and interaction between domain objects and storage abstractions). They should act like the "interface" through which the presentation layer interacts with the model layer. This is usually what in Rails-like code ends up in the controllers.

There are also several structures that might be in the spaces between these groups: DAOs, units of work and repositories.

Oh ... and when we talk (in context of web) about a user that interacts with MVC application, it is not a human being. The "user" is actually your web browser.

So what about deities?

Instead of having some scary and monolithic model to work with, controllers should interact with services. You pass data from user input to a specific service (for example MailService or RecognitionService). This way the controller changes the state of model layer, but it is done by using a clear API and without messing with internal structures (which would cause a leaky abstraction).

Such changes can either cause some immediate reaction, or only affect the data that the view instance requests from model layer, or both.

Each service can interact with any number (though, it's usually only a handful) of domain object and storage abstractions. For example, the RecogitionService could not care less about storage abstractions for the articles.

Closing notes

This way you get an application that can be unit-tested at any level, has low coupling (if correctly implemented) and has clearly understandable architecture.

Though, keep in mind: MVC is not meant for small applications. If you are writing a guestbook page using MVC pattern, you are doing it wrong. This pattern is meant for enforcing law and order on large scale applications.

For people who are using PHP as primary language, this post might be relevant. It's a bit longer description of the model layer with a few snippets of code.

Fat models, skinny controllers and the MVC design pattern

It's a bit tough to give you the "right" answers, since some of them deal with the specifics of the framework (regardless of the ones you are working with).

At least in terms of CakePHP:

  1. Yes

  2. Anything that deals with data or data manipulation should be in a model. In terms of CakePHP what about a simple find() method? ... If there is a chance that it will do something "special" (i.e. recall a specific set of 'condition'), which you might need elsewhere, that's a good excuse to wrap inside a model's method.

  3. Unfortunately there is never an easy answer, and refactoring of the code is a natural process. Sometimes you just wake up an go: "holy macaroni... that should be in the model!" (well maybe you don't do that, but I have :))

fat model and skinny controller design confusion between the controller method and model method

I would have a method in my model for the deletion of products. This method would do ALL of the work required to delete a product (including deleting associated DB records, files, etc).

The method would return TRUE if the operation was successful.

In the event that an associated record or file couldn't be deleted, I'd log that error in it's operation, possibly raise an error message in the UI and continue.

The method may call other methods in other models...for instance, I may have a product_attributes model that stores attributes for all products. That model might have a method: delete_by_product_id(). In that case, my product model would call product_attributes->delete_by_product_id(), which would handle the deletion of the associated records.

How skinny should controllers, and how fat should models be?

Controllers should be directing traffic. Models are for where your business logic goes, so in general your second example would be "correct mvc".

Basically what a controller should be doing is requesting input, telling models to change state (they do the actual state change themselves), and determining which view to display (if any).

I have many controllers which simply are like so:

class Controller_Foobar extends Controller
{
public function action_index() {}
}

And if they need to process $_POST input, they grab that data, and send it off to the model, then the view.

Keeping all that logic inside your models lets you easily reuse it, and it's more maintainable and testable.

CakePHP Fat models and skinny controllers - appModel

The best FMSC way is to, as you say, write the function in the model. But!! Don't do it in the AppModel, that's bad practice. Why would you put code related to two (at most) models in the AppModel?? Every model would inherit that function, that doesn't make much sense. Let's say you have a "Menu model" or an "User model", it isn't logical that they inherit a totalExpenses function, right? I understand that you want to have the function available in every controller and view if the need rises, but that's not the way to do it.

Step by step (actually, just two steps):

1) In the ExpenseClaim model, write a new function that will calculate the total of expenses

class ExpenseClaim extends AppModel {
/* definitions and validations here*/

public function totalExpenses($id) {
return $this->Expenses->find('count', array('conditions'=>
array('expense_claim_id' => $id)));
}
}

So, in the ExpenseClaimsController you can call this function with

$total = $this->ExpenseClaims->totalExpenses($the_id);

2) Now, it's logical to have the function that counts the total in the expenses claim model, and therefore available in the respective controller, but you said you wanted to use it in pages/admin_index, and let's imagine pages has absolutely no connection with the claim model. Well, then you can either do

ClassRegistry::init("ExpenseClaims")->totalExpenses($the_id);

or

$this->loadModel("ExpenseClaims");
$this->ExpenseClaims->totalExpenses($the_id);

(both in the controller) and you'll have that value available without putting that function in the AppModel.

(Btw, the code I wrote should work, but you need to fine tune the controllers and models names or close a parenthesis here and there, I haven't tested it).

Now, that's general best practice. Works in most cases, with more complicated functions. But for your case in specific, you may want to take a look at cake's counterCache, it keeps count of stuff without you having to do much.

Fat model / thin controller vs. Service layer

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.

.NET and Skinny Controllers/Fat Models Concept

Microsoft does not (as far as I know) enforce this pattern, but I personally use it in all my ASP.NET MVC projects to provide better separation of concerns.

I guess it's more a matter of personal taste.

CodeIgniter / Fat Models / Skinny Controllers

You are kind of right in that splitting into modules does negate some of the reasons for working SC/FM. But it is still good practice for several reasons:

1) Re-usability of code As you said models are supposed to be reusable, the more code you can make reusable the better. Yes I know modules do this too, but the point of modules is more about code being isolated and portable, you still may want to extend those controllers at a later stage and working in a SC/FM way will help when that time comes.

2) Code readability When reading your code most people will start from your routes config and then go to the appropriate controller. A skinny controller acts as a director and should be concise and readable. Just making calls to more complex and verbose code. Less code is easier to follow.

3) When in Rome Not to be overlooked, the fact that everyone* who uses MVC frameworks works this way means that you should work this way too, yes its nice to be different, but if you have 5 people in the same team working together who all want to be different it's just a pain in the arse.

Should you rewrite your code?

Probably not immediately, I'm sure you have better things to do. If you start trying to think in this mindset from this point forward, at some point you will look back at you old code and change it (probably when you're in there changing something anyway), but for now if it aint broke...

Further more, working in a modular way is not as straightforward as it appears, making truely reusable modular code is not easy and actually requires quite a lot of overhead compared to doing quick and dirty code for a single site. May be better to start practicing this, on fresh code until you have a good understanding of what's required to convert your existing code to something truely modular - this would be the time to sort out your fat controllers.

When writing new code for a particular site, I always bear in mind that I may want to reuse it on another site later, but if I tried to make everything re-usable with every option under the sun I would never get anything done. Far better to go and tweak it when the time comes.

Opinion on HMVC
I'll be honest, I dont really know what the HMVC bit is about, but modules are the best thing since sliced bread, since I stumbled across HMVC wiredesignz I now do much less work for a lot more website - and much more importantly I spend a lot less time doing the same thing... What you want a gallery on your site. Heres the gallery manager module, Cms you say, yes there is a cms module, products, yes theres a products module.... you get the idea. I now have lots of variations on one framework rather than hundreds of different sites.

Summary

You may be dealing with simple modules at the moment which means that code re usability and clarity is not a major issues within those modules. But start coding with good practice today. And when you are working on some mammoth CMS or products module you will be glad you did.

Check this out for a bit of a guide on what should go where How should a model be structured in MVC?

Guidance trying to make skinny controllers & fat models in CakePHP

I do not think you want to get only ONE client?

$members = $this->User->Client->find('first', array

I guess this should find all. I've improved this to use pagination in the case there are lots of users. I might be wrong with this but neither your associations nor the real goal is clear to me by looking at this code. I don't know how for example the Ticket model is associated with any other data. But I guess you're using Controller::uses, you should not do that but access related models through their associations.

Do not use horrible variable names like $a, that just sucks and nobody will ever know what that means in a larger code block or application. You also named an array containing client data $members, why not $clients? Read this: Clean Code and for CakePHP I suggest you to follow the CakePHP coding standards.

Describe the goal and this could be refactored even better I think. If you want to activate clients to have access to a ticket (thats what it looks like) why have you not done it in the ticket or client controller/model?

Also this huge amount of inline comments is just causing more mess than it helps. Write clean and readable code and the code will speak for itself. You have not done any super complex code or super complex math there. Again, I can just recomment you to read "Clean Code", it is in my opinion a "must read" for every developer.

<?php
// UsersController.php
public function activate() {
if ($this->request->is('post') || $this->request->is('put')) {
$this->User->activate($this->request->data);
$this->Session->setFlash('Activations sent.', 'default', array('class' => 'success'));
$this->redirect(array('action' => 'index'));
}

this->Paginator->settings['Client'] = array(
'conditions' => array('id' => $this->Auth->('current_id')),
'contain' => array(
'OnlyModelsYouNeedHere'));
$this->set('clients', $this->Paginator->paginate($this->User->Client));
}
?>

<?php
// User.php - the model
public function activate($data) {
$memberIds = array();
foreach($data['Members']members as $member) {
$memberIds[$member['id']] = $member['id'];
}
$usersToActivate = $this->find('all', array(
'conditions' => array(
'User.id' => $memberIds)));
return $this->Ticket->bulkActivate($usersToActivate);
}
?>

Passing the ids could be also trimmed down more, but hey, its late here now. :) Take this as a rough refactor of your code and think about what I have changed and more important why.

If you want to see proper examples of skinny controllers and fat models check our plugins out, the users plugins UsersController and Model might give you a bigger picture.



Related Topics



Leave a reply



Submit