38

Yesterday I had some discussion with one of our developers regarding MVC, more precisely about the role of the model component in MVC.

In my opinion, a model should just contain properties and almost no functionality so there are as few methods in model classes as possible.

My colleague though believes that models could and should have more than that and offer a lot more functionality.

Here is an example we argued about.

Example 1

Let's say we wanted to create a blog. A blog has articles and tags. Each article can have multiple tags and each tag can belong to multiple articles. So we have a m:n relation here.

In pseudocode it'd probably look something like this:

class Article{
    public int id;
    public String title;
    public String content;
    public Tag[] tags;
    
    // Constructor
    public void Article(id, title, content, tags){
        this.id = id;
        this.title = title;
        this.content = content;
        this.tags = tags;
    }
}

class Tag{
    public int id;
    public String name;

    // Constructor
    public Tag(id, name){
        this.id = id;
        this.name = name;
    }
}

Now, assume that we're working loose coupled here which means that it could happen that we have an instance of Article which has no Tags yet so we'll use an Ajax call (to our backend which has a database containing all the information) to get the tags that belong to our article.

Here comes the tricky part. I believe that getting the backend data via Ajax+JSON should be the controller's job using a dedicated class which deals with the ajax request using a parser:

class MyController{
    private void whatever(articleID){
        Article article = (Article) ContentParser.get(articleID, ContentType.ARTICLE);
        doSomethingWith(article);
    }
}

public abstract class ContentParser{
    public static Object get(int id, ContentType type){
        String json = AjaxUtil.getContent(id, type.toString()); // Asks the backend to get the article via JSON
        Article article = json2Article(json);
        
        // Just in case
        Tag[] tags = article.tags;
        if (tags == null || tags.length <= 0){
            json = AjaxUtil.getContent(article.id, ContentType.TAGS); // Gets all tags for this article from backend via ajax
            tags = json2Tags(json);
            article.tags = tags;
        }
        
        return article;
    }

    // Does funky magic and parses the JSON string. Then creates a new instance of Article
    public static Article json2Article(String json){
        /*
         ...
        */
        return new Article(id, title, content, tags);
    }

    // Does funky magic and parses the JSON string. Then creates a new instance of Tag
    public static Tag[] json2Tags(String json){
        /*
         ...
        */
        return tags;
    }

}

Example 2

My collegue believes that this breaks with the idea of MVC, he suggests that the model should take care about this:

class Blog{
    public int id;
    public String title;
    public Article[] articles;
    
    // Constructor
    public Blog(id, title, articles){
        this.id = id;
        this.title = title;
        this.articles = articles;
    }
    
    public void getArticles(){
        if (articles == null || articles.length <= 0){
            String json = AjaxUtil.getContent(id, ContentType.ARTICLE); // Gets all articles for this blog from backend via ajax
            articles = json2Articles(json);
        }
        return articles;
    }

    private Article[] json2Articles(String json){
        /*
         ...
        */
        return articles;
    }

}

class Article{
    public int id;
    public String title;
    public String content;
    public Tag[] tags;
    
    // Constructor
    public Article(id, title, content, tags){
        this.title = title;
        this.content = content;
        this.tags = tags;
    }
    
    public Tag[] getTags(){
        if (tags == null || tags.length <= 0){
            String json = AjaxUtil.getContent(id, ContentType.TAGS); // Gets all tags for this article from backend via ajax
            tags = json2Tags;
        }
        return tags;
    }

    // Does funky magic and parses the JSON string. Then creates a new instance of Tag
    private Tag[] json2Tags(String json){
        /*
         ...
        */
        return tags;
    }
}

And outside of the model you'd do: blog.getArticles(); or article.getTags(); to get the tags without bothering with the ajax call.

However, as handy as this might be I believe that this approach breaks with MVC because at the end of the day all models will be full of methods that do various funky stuff and the controller and helper classes do almost nothing.

In my understanding of MVC, models should only contain properties and a minimum of "helper methods" inside. For example a model "Article" could offer a method getNumOfTags() but it shouldn't do any Ajax calls on its own.

So, which approach is correct?

3
  • 6
    I know this is an old question, but just putting my two cents out there. Models should not contain data persistence or retrieval logic. Thats what we have repository layers for. They should not have business logic. Thats what the business layer is for. They should probably not have helper methods too, since helper methods are generally used across the application and not specific to a particular model. Validation logic is on the front end for a better user experience and replicated on the business layer to meet business logic requirements. So what do we have left now to put in the models? :)
    – user20358
    Commented Oct 30, 2017 at 17:03
  • Someone better answer this man (@user20358)! As a MVC newbie, I'm curious :)
    – akinuri
    Commented Oct 31, 2019 at 14:47
  • The topic to focus and answers are really good. I would like to thanks to all of you. Also, i would like to give a small tips. To be able to maintain existing source code local consequences are critical; hence, on that point placing data and logic together is essential. If you enough time you might read Kent Beck’s Implementation Patterns book. He mentions those behaivors a lot. Additionally, Martin Fowler has some great blog post about GUI architecture patterns.
    – nurisezgin
    Commented Nov 23, 2019 at 11:53

6 Answers 6

34

Generally I try to keep controllers simple in terms of logic too. If business logic is required, it will go up to 'service layer' classes to handle it. This also saves repeating any code/logic too, which ultimately makes the whole project more maintainable if business logic was to change. I just keep models purely as entity objects.

I think the answer above sums it up nicely though, it is easy to over engineer a project based on design patterns: Go with whatever works for you and is most maintainable/efficient.

3
  • Well, over-engineering can easily happen in smaller projects but the bigger the project becomes, the better it needs to be planned. In an older Java project I had lots of business logic inside the models which lead to huge model class files. Now I am on a JavaScript project where I use models as simple "value objects" without any logic and do all the "funky coding stuff" in my controllers. That again leads to huge controller classes. Having an extra service layer between controllers and models sound like a good idea to keep both clean.
    – Timo Ernst
    Commented Dec 19, 2012 at 14:35
  • Yes having that service layer abstracted from both controllers and models is the way forward. It just makes the project more readable and easier to navigate around too as a developer. As mentioned also it avoids duplication too which is a massive benefit if you have multiple controllers, projects etc using the same methods and logic to the service layer for data retrieval and manipulation. Hope that helps anyway! Commented Dec 19, 2012 at 15:44
  • 1
    I think "the answer above sums it up nicely" no longer applies. You are now the top answer!
    – Unnawut
    Commented Jun 23, 2014 at 7:54
19

You should stop treating "model" in MVC like some class. Model is not a class or object. Model is a layer (in modern MVC, there has been some evolutions since the inception of concept). What people tend to call "models" are actually domain object (I blame Rails for this mass-stupidity).

The application logic (interaction between domain logic structures and storage abstraction) should be a part of model layer. To be more precise: it should be inside the Services.

The interaction between presentation layer (controllers, views, layouts, templates) and model layer should happen only through those services.

Application has no place in controllers. Controllers are structures of presentation layer, and they are responsible for handling user input. Please do not expoqbse deomain objects to it.

5
  • 3
    The blaming Rails thing made me laugh.
    – Griffin
    Commented Jun 30, 2015 at 14:31
  • 1
    +1 And I (think) am blaming CodeIgniter. I've just started using it and I believe it mislead me. In v3, a model seems to represent a table (insert, select, update, delete rows), a row (object properties = table fields); and it's a class. In v4, they introduced entities which represent rows. So now there's model (table) and entity (row).
    – akinuri
    Commented Oct 31, 2019 at 14:42
  • I'm not taking a dogmatic position on the topic, and while I don't strongly disagree, readers should note that even the link provided in this answer (wiki.c2.com/?DomainObject) shows 5 different people with slightly differing or disagreeing definitions of what a domain object is. But that's why this stuff is so much fun; it really is a hybrid art & science. (With a good amount of conflicting and confusing semantics thrown in.)
    – Manius
    Commented May 16, 2022 at 16:45
  • @Manius sure - there are different opinions. But those differences-in-opinion are on the "finer details" of things. And stuff like "dirty state" (referring to saving) is actually more of an implementation detail that really comes into play when you start dong advanced stuff with custom-made "Units of Work".
    – tereško
    Commented May 16, 2022 at 17:43
  • I don't really disagree... maybe "slightly" :)
    – Manius
    Commented May 17, 2022 at 22:34
7

Your suggestion about the modules (without any business logic inside) sounds more like you talk about Value Objects. The suggestion of your college sounds more like Domain Objects.

In my opinion the concept which will be used depends on the framework which is used (that's the practical view, the more philosophical one is bellow). If framework is used it usually sets rules about how you should implement each component. For example we can look at different MVC frameworks. In Flex's Cairngorm framework we have both. VO (Value objects) are primary used for bindings to the view, while the DO (Domain objects) hold the business logic. If we look at ASP.NET's MVC implementation there we have a model which contains at least the data (VO) but also some validation (if required). Let us look at a UI MV* framework - for example Backbone.js. Backbone's documentation says:

Models are the heart of any JavaScript application, containing the interactive data as well as a large part of the logic surrounding it: conversions, validations, computed properties, and access control.

If we look into the traditional MVC provided by Smalltalk we see that: "Model: manages the behavior and data of the application domain" so we have some behavior in it, not just plain data.

Let's think practically, if don't have any logic in the Model probably we should put all the application and business logic into the Controller.

Now let's focus on a concrete example. Imagine we have a model which is a Graph. We want to find the shortest path between two nodes in it. A good question is where to put the algorithm which finds the shortest path? It's a kind of business logic, right? If we look at the main benefits of MVC (code reuse, DRY etc.) we can see that if we want to reuse our model in the best possible way we should implement the shortest path inside it. The shortest path algorithm usually depends on the graph inner representation (or at least for best performance of the algorithm) but this representation is encapsulated into the model, unfortunately we cant reuse the full shortest path for matrix representation and list of neighbors so it's not a good idea to put it into the controller.

So as conclusion I can said that it depends on your needs (mostly). The traditional MVC purpose is to be used in the UI (inside GoF

The Model/View/Controller (MVC) triad of classes [first described by Krasner and Pope in >1988] is used to build user interfaces in Smalltalk-80.

)

now we use it in different areas - only UI, for web applications, etc. It cant be used in it's pure form because of that. But anyway, in my opinion the best separation of concerns can be achieved by isolation of the business logic into the Model and the application logic into the Controller.

4
  • 1
    With dependency injection you can inject your service into your controller which then allows your controller to act as purely something that is receiving requests and returning results. It doesnt deal with business ... your service does. So you are application consists of your View Model, Views, Controllers, Service Layer amd your Business Layer (... and whatever else you need)
    – Jonathan
    Commented Dec 19, 2012 at 12:30
  • In MVC there's no concept View Model. In the traditional MVC there's also no concept Service. ViewModel is a part of the MVVM architectural design pattern. MVC with services is usually called MVCS. As I read the question it was asked about MVC, not MVVM nor MVCS. Commented Dec 19, 2012 at 12:32
  • 1
    @MinkoGechev Why not? ViewModels are just another tool, there's no reason why you can't use them in MVC. Patterns are not single solitary constructs. Mix and match, take inspiration, do what you think works! Commented Dec 19, 2012 at 12:46
  • Of course it's good to mix the patterns. MVC architectural design pattern is also mix of Strategy, Observer and Composite. When we start mixing the architectural patterns like MVVM and MVC we loose their true nature. When we mix the patterns we don't have strict categorization. As I read the question is about MVC not MVVM or hybrid between MVC/MVVM Commented Dec 19, 2012 at 12:55
6

Correct? Either. They both compile, don't they?

Handy tricks are nice, why not use them were you can? That being said, as you've pointed out, you may get bloated models if you put all sorts of logic in them. Likewise, though, you can get bloated controllers when they do massive amounts in each action. There are ways to abstract elements out of either, if that's necessary too.

At the end of the day all design patterns are is guidelines. You shouldn't blindly follow any rule, just because someone else said it. Do what works for you, what you think gives clean, extensible code and hits whatever metrics you think make good code.

All that being said, for true idealistic MVC I would say that models should not have any external actions, they're data representations, nothing more. But feel free to disagree :-)

2
  • 3
    +1 for "At the end of the day all design patterns are is guidelines". And if you're concerned about a bloated model, extract the data access to DAOs - by definition, Data Access Objects, which are neither quite Model or Controller.
    – Zecc
    Commented Dec 19, 2012 at 11:49
  • 1
    @Zecc Yeah, DAOs, Service classes, ViewModels etc. there are many ways to abstract logic from parts of an MVC architecture. People often get far to zealous about following the word of patterns, instead of their spirit. Commented Dec 19, 2012 at 11:52
4

In short I believe the Model should just be data that will be sent to your View. It helps drive the MVC paradigm into other aspects of your application.

If you are tring not to break the MVC pattern your data should all be returned as a Business Model to your controller and unpacked into your ViewModel. Request the information server side and then send everything. If you need to make JSon requests then that should either be a Rest Service or calls to a Controller. Having these getTags and getArticles makes it very messy ... if your view is now deciding on which to call ... I cant understand why you dont have that information isnt available upfront. Using static methods is the same approach just a different angle.

I have found it best to have my controller actions call an injected service which does the magic and use the Models within the MVC web application to return the information. This makes things neater and further emphasisis the seperation of concern. Your Controller Actions then become very lean and its clear what they are doing.

I believe starting by treating the Model as completly dumb might go a long way in sorting some of these architectural problems I am seeing from this code.

2

Yes. It should. You are talking about Domain Driven Design.

https://en.wikipedia.org/wiki/Domain-driven_design

If you feel, you are not doing that then you are doing Anaemic Domain Model Design. that is an Anti Pattern.

I read through an article from Martin Flower on how bad the Anaemic Domain Design is. https://martinfowler.com/bliki/AnemicDomainModel.html

2
  • I completely agree with Fowler here. The succinct description on the Wikipedia MVC page is, IMO, correct.
    – Huliax
    Commented Mar 10, 2021 at 13:48
  • 1
    I am late to this thread. However I couldn’t disagree any more about the op’s design. He has described the Anaemic design pattern. Whereas it’s a quick way to put a project together , it’s not maintainable and impossible to read. If data changes, it could have come from anywhere within the application, with behaviours we can pin point exactly where the data was changed depending on finding the method that called it. Commented Nov 7, 2022 at 16:14

Not the answer you're looking for? Browse other questions tagged or ask your own question.