Tom Butler's programming blog

Model-View-Confusion part 2: MVC models are not domain models

Update 30/11/2012:

I have received several requests for clarification on the code examples at the bottom of this article. Because of this, I have updated the code to be far more demonstrative and complete. Feel free to send more feedback or questions you may have.

I have rewritten a lot of this article to make the code simpler and easier to follow as well changing the focus to be about the differentiation between MVC Models and Domain Models.

Abstract

Part 1 discusses MVC and explains why the view has access to the model in MVC. Taking this approach, however, is not as simple as it seems. Giving the view access to the model creates a whole new set of problems. The difference is, these problems are easily fixed. This article presents a useful way of fixing the problems while retaining high reusability and flexibility.

Flexibility vs Reusability

To completely contradict part 1, while correct, it's not the solution either. It is certainly an improvement over fat controllers. However, was it much of an improvement? Isn't reusability reduced by giving the view access to the model?

In any software design, there is always a trade off between flexibility and reusability. On one hand a very flexible system could be created where the client code has to specify pretty much everything. For example, in terms of views, passing a model object to the template and have the template do everything: query the model, process the data and generate the HTML. This is incredibly flexible: there are no limitations on what it can do. However, it's not reusable at all. The template is tightly bound to the individual model and the logic is contained within it. To make an even slightly different version everything would need to be re-coded.

On the other hand, a lot of assumptions could be made about the nature of the model in the system the view, with minimal to no configuration could take any model which meets these assumptions. Of course things break when requirements change or it needs to do something even slightly different. It encourages a 'copy, paste and modify slightly' mentality, which is of course, not a good idea.

Finding the balance is the key. It will always differ based on the requirements of the software, how large the project is, whether it's going to change often and whether it's likely to grow beyond its initial scope.

The last point here is a hard one to judge. Would it be worthwhile to deploy a template engine or full MVC stack for a 5 page brochure site? how about 10 page? What if that 5 page site grew into a 30 page site within a year then the client wanted latest news added to each page. If the system was built on a template engine or CMS to begin with it would be easier.

But is this the right answer? Should developers deploy a full MVC stack just to write to a log file? Trying to be a soothsayer and second guess what clients (who are notoriously fickle beings) will ask for in a year isn't the solution. However, spending a little extra time at the start of a project ensuring further developments are as simple as possible will undoubtedly make things easier in the long run.

Part 1 discusses views and templates. It argues that in MVC the view should have direct access to the model. It contains some basic code examples to demonstrate the benefits. The solution is for demonstration only. As such it is neither complete, nor perfect. However, the general idea of the view calling functions on the model directly presents some new problems.

Problems created by the view accessing the model

The biggest problem is also one of its biggest strengths: it creates a firm contract between the model and the view. This reduces reusability of the view because the model now needs to have a very specific interface.

Part 1 ended with a generic, reusable ListView class:

class ListView {
    private 
$model;
    private 
$template;

    public function 
__construct(Searchable $modelTemplate $template) {
        
$this->model $model;
        
$this->template $template;
    }

    public function 
output() {
        
$this->template->assign('data'$this->model->getData());
        return 
$template->output();
    }
}

Firstly, the binding logic mentioned has simply been moved into the view. Secondly, and more importantly, the view requires the model to implement the Searchable interface . The result of this is that the view is only usable by certain models. But what about other views which may need other data sets from the same model?. What if a model doesn't implement Searchable. The issue is one of Separation of Concerns. Should the model know how it is going to be used? No. The model should be dictating how it is used and the system should accommodate it.

Should arbitrary models model be modified to implement the Searchable interface? Ideally the model should be reusable without modification. Otherwise each model which can used be the view needs to be modified.

The problem arises because each view requires models to implement specific interfaces. In the real world, a model is going to be used by any number of views. The model should not be modified in order to allow each potential view to use it. It causes clutter in the model and causes harm by meaning the model cannot easily be reused by the same view in two different ways.

The cause of confusion is the term "Model". When people refer to Models they generally mean "Domain models". That is, the model which encompasses the problem domain, dealing with real-world concepts. Blogs, users, products, etc. In MVC, while the Model does contain these things, the domain model is not the Model referred to in MVC.

Is the following code the solution?

class ListView {
    private 
$model;
    private 
$template;
    <
b>public $filter;</b>

    public function 
__construct(Searchable $modelTemplate $template) {
        
$this->model $model;
        
$this->template $template;
    }

    public function 
output() {
        
$this->template->assign('data'$this->model->getData($filter));
        return 
$template->output();
    }
}
}

//controller code
$this->view->filter 'firstname = "' $name "';

Here, the state has been moved into the view. The view contains the search criteria rather than the model. Is this the answer?

No, For a start, Display logic has been reintroduced into the controller. More importantly though, now any model which uses the view requires a very specific "getData" implementation. This severely reduces reusability to only models which follow this specification.

Extending this idea into more complex views means more specific calls to a model, which means its less reusable views. To use a totally different model would be programmatically trying to put a square plug in a round hole.

Consider this: developer A develops a model and a view to work together:

class ModelA {
    public function 
getData($order$limit$filter) {
        
//...
    
}
}

class 
ViewA {
    
//...
    
public function output() {
        
$result $this->model->getData($this->order$this->limit$this->filter);
        
//...
    
}
}

Meanwhile, developer B develops a model and a view which work together:

class ModelB {
    public function 
getData($firstname) {
        
//...
    
}
}

class 
ViewB {
    
//...
    
public function output() {
        
$result $this->model->getData('foo');
        
//...
    
}
}

Now there's a situation where ModelB cannot be used with ViewA and ModelA cannot be used with ViewB even though the logic in each view may be relevant to the display of both models.

One solution is to add the relevant methods to the models but this is both messy and dangerous. This potentially introduces unrelated concepts into models (e.g. ModelA may not be anything to do with users).

Alternatively, the views could be modified, but again, there's no clean way to do it. Either they need to extended and have the entire output() method re-written, or have some hacky logic in the view deciding which method to call in the model.

The ideal scenario is that both the model and view can be reused without modification. This allows for ultimate reusability and a very large amount of flexibility

The answer? Abstract the problem away.

Terminology: ViewModels View Helpers, Models...

Padraic Brady wrote about this in his fantastic article "The M in MVC: Why Models are Misunderstood and Unappreciated". Although he accurately points out the misunderstanding of Models, the problem is peoples preconceptions of model's. He re-enforces this by discussing domain models in terms of MVC Models. They are not the same thing. The MVC Model does encapsulate domain models, but for the purpose of MVC, although you can write a MVC Model which does the job of a domain model, it's impossible to use a domain model as an MVC Model.

One idea presented by Brady is to create a "View Helper" which contains all the interaction between the model and the view. This is actually what MVC refers to as "The model" and not a separate component. However, because the term "Model" has evolved to have a specific meaning I can see why he needed to coin a fresh term for the MVCs model.

What is a view helper?

Encapsulating business logic in a helper instead of a view makes our application more modular and facilitates component reuse. Multiple clients, such as controllers and views, may leverage the same helper to retrieve and adapt similar model state for presentation in multiple ways.

Essentially the view-model interaction is abstracted away, creating much greater reusability. The basic premise is that the view only communicates with the helper (not the domain model directly) and that the view helper communicates with the model (not the view). This creates a simple one way data flow. Model<-View Helper<View.

The issue here is that what's being discussed are what MVC itself refers to as models. That "helper" isn't a helper at all it is the MVC Model.

The term "View Helper" is far too generic and has been applied to entirely unrelated components in several of the larger frameworks. As such, I will use the term "ViewModel" as this is both more descriptive and less prone to cause confusion. However please keep in mind that ViewModels, View Helpers as defined by Sun Microsystems (above) and the "Model" in MVC are all the same thing, just with different terms. I want to make a firm distinction between Domain Models and MVC Models to avoid confusion. I will be calling MVC Models "ViewModels" for this purpose and reserving the term "Model" entirely for domain models because that's what most people reading this will think of as a "model" and I want to avoid any bias or preconceptions people have when they hear the term and enforce a firm distinction between the two.

An implementation

The main goal is that views can be as generic (and therefore reusable) as possible, while the ViewModel defines only how a model interacts with a specific view. This fixes the problem of either coding a view around a model, or coding a model to fit a view. It is considered part of the view layer, but the ViewModel can access any domain model.

The view layer now consists of several parts:

The Template. This contains the HTML. This has a contract with domain models (user objects, order objects, etc). A basic template system is used in code examples on this page for the purpsoe of demonstration. How this works is not relevant and is far beyond the scope of this article. Often the template itself will not be reused: It is tied directly to the domain model. For example, it knows what fields a "User" object has. It has direct access to its ViewModel, this allows it to read what it needs, eliminating the need for binding logic in the view.

In this case the HTML is just another variable that the view uses. The fact that it's more complex than most is irrelevant. The template has a dependency on the ViewModel. Each template will be used with a single ViewModel (Though can potentially be reused by other ViewModels which share the same interface).

The View This contains all the display logic for interacting with the template and is the only place the template is interacted with directly. Most of the time it will simply assign the helper to the template. When a View is defined it should also define an interface for the helper which it is going to use. It does not interact with models directly. It uses a ViewModel to get any data it needs from the model.

The ViewModel. This implements the specific interface defined alongside the view. E.g. FormView will require a ViewModel which implements the interface FormViewModel. The ViewModel's job is to link the model layer to the view layer and store the state of the application. For instance it will store things like sort options selected by the user and the ID of the record being edited/viewed.

This means that any part of the view layer can be substituted (and thus, the others reused). With the same model and view, the logic in the helper could be changed. The template could be changed.

In part 1 I ended with a reusable ListView.

The view itself remains unchanged:

class ListView {
    private 
$model;
    private 
$template;

    public function 
__construct(Searchable $modelTemplate $template) {
        
$this->model $model;
        
$this->template $template;
    }

    public function 
output() {
        
$this->template->assign('data'$this->model->getData());
        return 
$template->output();
    }
}

It requires a ViewModel as the first argument. In this case, the ViewModel must implement the Searchable interface as before. The also controller remains identical to what it was previously:

class SearchController {
    private 
$model;

    public function 
__construct(Searchable $model) {
        
$this->model $model;
    }

    public function 
search($criteria) {
        
$this->model->setCritera($criteria);
    }
}

The important changes happen at the model layer. The old UserModel looked like this:

class UserModel implements ListableSearchable {
    private 
$searchName;
    private 
$db;

    public function 
__construct(Db $db) {
        
$this->db $db;
    }

    public function 
setCriteria($criteria) {
        
$this->searchName $name;
    }

    public function 
getData() {
        
//Find the selected users.
        
return $this->db->query('SELECT * FROM users WHERE name like :name', array(':name'$this->searchName);
    }

}

The problem with this is that the domain model and ViewModel have been merged into one. This violates the Single Responsibility Principle and causes domain models to contain methods which exist for the sole purpose of specific views accessing data. However this can be resolved:

class UserListViewModel implements ListableSearchable {
    private 
$searchName;
    private 
$model;

    public function 
__construct(UserModel $model) {
        
$this->model $model;
    }

    public function 
setCriteria($criteria) {
        
$this->searchName $name;
    }

    public function 
getData() {
        
//Find the selected users.
        
return $this->model->findByName($this->searchName);
    }

}

class 
UserModel {
    private 
$db;

    public function 
__construct(Db $db) {
        
$this->db $db;
    }

    public function 
findByName($name) {
        
//Find the selected users.
        
return $this->db->query('SELECT * FROM users WHERE name like :name', array(':name'$name);
    }

}

Here is a very clear distinction between a domain model and a ViewModel. This ViewModel will always be incredibly minimalist. It will never contain complex logic, database access, it's a simple wrapper to enable view to access it's data. The domain model now has a generic "findByName" method which can be used by any "ViewModel". The application state (what has been searched for) remains in the ViewModel while the domain state (the data about users) is encapsulated in the domain model.

The view layer is now made up of 3 parts. For people used to "templates as views" this will likely seem daunting. However, take a look at the controller. It's entirely minimalist and reusable which is far superior to the mess of fat controllers which are required by the major frameworks. Minimal controllers are good controllers.

To test the reusability, the view could be reused with minimal configuration by another model with a totally different interface:

class ProductListViewModel implements ListableSearchable {
    private 
$searchCode;
    private 
$model;

    public function 
__construct(ProductModel $model) {
        
$this->model $model;
    }

    public function 
setCriteria($criteria) {
        
$this->searchName $name;
    }

    public function 
getData() {
        
//Find the selected users.
        
return $this->model->findByCodeNumber($this->searchCode);
    }

}

class 
ProductModel {
    private 
$db;

    public function 
__construct(Db $db) {
        
$this->db $db;
    }

    public function 
findByCodeNumber($code) {
        
//Find the selected users.
        
return $this->db->query('SELECT * FROM products WHERE code like :code', array(':name'$code);
    }

}

Neat and minimalist. All that's changed is the ViewModel. The view and controller can be reused. In this case, the template would still need to change too, of course.

How about a list which just lists all blogs?

class BlogListViewModel implements Listable {
    private 
$model;

    public function 
__construct(BlogModel $model) {
        
$this->model $model;
    }

    public function 
getData() {
        return 
$this->model->findAll();
    }

}

In this case, a controller would not even be required! The view would get it's data from the ViewModel and it wouldn't even matter that the controller didn't exist.

To quote Harry Hill "You get the idea with that". This is, of course, the tip of the iceberg. At the more complex end imagine a ViewModel that picked which fields the View uses from the model, allowing, for example, a fully reusable template and view combination for any tabular data. What if ViewModels could create views and pass them to other views?

With minimal code, a lot different fairly substantial variations are possible due to having both high flexibility and high reusability.

Here's one more example using something slightly more complex. Like part 1 pagination will be used again, it's simple and commonplace enough that everyone understands it, yet it's not-trivial enough to provide a worthwhile demonstration.

This one will be more complete, and more like a real-world application.

The view and its interface:

interface Pageable {
    
//Get the records using limit and offset
    
public function find($limit$offset);

    
//The number of records which will be shown on each page
    
public function getRecordsPerPage();

    
//The page currently being shown
    
public function getCurrentPage();

    
//The total number of records being paged through.
    //Used to calculate the total number of pages.
    
public function getTotalResults();
}


class 
PaginationView {
    private 
$model;
    private 
$template;

    public function 
__construct(Pageable $modelTemplate $template) {
        
$this->model $model;
        
$this->template $template;
    }

    public function 
output() {
        
$perPage $this->model->getRecordsPerPage();
        
$pageNo $this->model->getCurrentPage();

        if (empty(
$pageNo) || !is_numeric($pageNo) || $pageNo 1$pageNo 1;
        
$result $this->viewModel->find($perPage, ($pageNo-1)*$perPage);

        
$totalRecords $this->model->getTotalResults();
        
$totalPages ceil($totalRecords/$perPage);

        for (
$i 1$i <= $totalPages$i++) $this->template->appendSection('page', array('num' => $i'class' => $i == $pageNo $this->currentClass ''));


        foreach (
$result as $record$this->template->appendSection('record'$record);

        return 
$this->template->output();

    }
}

The PaginationView uses any ViewModel which implements Pageable. The way the template system works is irrelevant. It is included for demonstration purposes only. The ViewModel is then defined in order to supply the view with the data it needs:

class PagedUserListViewModel implements PageableSearchable {
    private 
$searchName;
    private 
$model;
    private 
$page 1;

    public function 
__construct(UserModel $model) {
        
$this->model $model;
    }

    public function 
setCriteria($criteria) {
        
$this->searchName $name;
    }

    public function 
find($limit$offset) {
        return 
$this->user->findByName($this->searchName$limit$offset);
    }

    public function 
getRecordsPerPage() {
        
//Let's show 20 users per page.
        
return 20;
    }

    public function 
getCurrentPage() {
        return 
$this->page;
    }

    public function 
getTotalResults() {
        
//Simple example, in reality the model would have a count method for performance reasons
        
return count($this->model->findByName($this->searchName));
    }

    public function 
setPage($page) {
        
$this->page $page;
    }
}

Of course the same could be done with a different model: Blogs, products, etc. The controller is simple, too:

class PagedUserListController {
    private 
$viewModel;

    public function 
__construct(PagedUserListViewModel $viewModel) {
        
$this->viewModel $viewModel;
    }

    public function 
search($criteria) {
        
$this->viewModel->setCritera($criteria);
    }

    public function 
setPage($page) {
        if (
is_numeric($page)) {
            
$this->viewModel->setPage($page);
        }
    }
}

By separating everything out, any piece of the view layer can be substituted. The way the view interacts with the model is not affected by either changes to the view or changes to the model. If there are two different user lists with different requirements (e.g. different search criteria) only the View Helper needs to be changed. The view and the template would remain the same. The view is reusable for any model by supplying it with a different ViewModel:

Conclusion

This is, of course, noting but a single implementation of the idea, however, it demonstrates the benefits of separating the view elements well and should provide a solid base for anyone wishing to develop the idea further. This is of course, all open to criticism. There is plenty of room for improvement and some of the minor implementation details included here may not be done in the best way (Should the variables being replaced in the template be put in the helper instead of the view??). However, using practical examples, I believe I've successfully argued the case for splitting views into 3 parts. It is more code to set up, but the power and reusability achieved by doing this makes it more than worthwhile.

Part 1 discussed people getting MVC wrong. People may consider the implementation of view helpers here outside the bounds of MVC. This is still MVC, however. The view layer still access the model layer, and it solves the problems discussed at the beginning of part 2. This is a good balance. It doesn't have the reusability issues of putting the binding logic in the controller and it doesn't have the reusability or flexibility issues of tying a view to a specific model and encourages an architecture where as much code as possible is reused. On the downside, it is marginally more difficult to set up initially, requires more classes and is likely slower due to doing more. But, as stated id in part 1: "code cleanliness/reusability/maintainability should not be sacrificed for performance". Benchmarking and micro-optimisations are far beyond the scope of this article.

Finally, to avoid any potential confusion: Part 1 was about how things are correctly done in MVC. This article expands on that and supplies a specific View implementation. I've tried not to give the impression that this is a standard part of, or required by, the MVC architecture. It is merely an implementation of it. However, how models, views, or controllers actually work internally is not specified by MVC, other than how the components relate and interact with each other. This is one solution to the View in MVC. As with part 1: Question it. Improve on it. Don't take anyone's implementation as 'correct'. Look at it, try it for yourself. Make up your own mind, don't take my or anyone else's word on what is "the one true solution" as there likely isn't one. The best thing we can do as programmers is examine others code/reasoning and strive to find the best solution for the task at hand, which may not be the same for everyone.

A small disclaimer

All the code presented in this article is for information only, It uses things such as "$_POST", the "new" keyword instead of factories/dependency injection, insecure code which is subject to SQL injection and things which are considered bad practice. All this is for the sake of simplicity: The article is teaching the idea of views/view helpers not other best practices. Because of this, please don't take code which is outside the scope of the article and use it without understanding the implications behind it.

References

Brady, P (2008) The M in MVC: Why Models are Misunderstood and Unappreciated (http://blog.astrumfutura.com/archives/373-The-M-in-MVC-Why-Models-are-Misunderstood-and-Unappreciated.html)

Sun Microsystems (2001) Core J2EE Patterns - View Helper (http://java.sun.com/blueprints/corej2eepatterns/Patterns/ViewHelper.html)