Hacker News new | ask | show | jobs
The M in MVC: Why Models are Misunderstood and Unappreciated (blog.astrumfutura.com)
71 points by trucious 5439 days ago
10 comments

This is probably my nitpick with people (not all) that come from Rails and tries to 'teach' others about general concepts by the way they are done in Rails.

A good example is "In Programming, Fat Models Are Preferable To Size Zero Models". Sure, if you are in Rails, you probably don't want a 3000 lines controller, but guess what, there are also Services! By moving logic to the Model you end up with fat models that do a lot of things, instead of having specialized Services for logical parts of you application.

badclient example below is a prime example. Do we really want the model to handle authorization? What if it also needs to know about the account the user is trying to access has been suspended (then the User model needs to know about Account model suspension) or even authorization for that specific page (only managers should be able to access payroll).

By moving the logic to the model, you now have a big fat model that needs to know about everything in the application (and most likely, a lot of logic will have to be replicated throughout other models).

About the "Fat Stupid Ugly Controllers" can also be separated to View Presenters, making the code much cleaner (presentation is presentation, controller is controller, model is model) and not Fat Stupid Ugly Models.

Sorry for the rant, but I'm sick and tired Rails programmers talking about Rails ways like it is the one true way while there are a lot of Software Design Practices that are better suited for each case.

I don't use Ruby, I do use MVC (C# in my case). I honestly don't agree with your interpretation of 'MVC'.
It wasn't an interpretation of MVC per-se but more of what I think the Model in any architecture should be. The Model can be used in MVVM and MVP as well and can be part of DDD way of doing things.

And again, for me, a model should be a representation of an object/data. If it is tied to an ORM (Active Record or Entity Framework) it may come with DB access, but I still don't think models should contain application specific logic. That's what the 'Business' layer should be for. If an Invoice model knows about tax codes from 130 different countries, again I think it knows way too much about the application.

As I see it, the Model in MVC is everything that is not C or V. It encompasses the service layer, the DAOs, the data objects and what have you.

The term Model on it's own doesn't mean much, and is very overloaded with meaning. You can see it as the data objects (stuff like Person(id, firstName, lastName) for example), but that's one definition of it.

Seriously, you've got it very wrong. A model is not 'a representation of an object/data'. It's the whole business domain. MVC is about separation of the UI from the domain and the controllers' the intermediary.

Not sure which pattern you're thinking of, but it's not MVC.

a service could be modelled as a 'model'. That controllers (and other models) use.

This fits both generic 'MVC' practice, AND Rails MVC (if you think they are different...)

He still didn't clear up the conceptual understanding of "model" very well.

The Data Model. Just the data. - pure Value Objects, classes which are little more than wrappers to data, which can be assembled in more complex structures for presentation by a view.

The Domain Model. A representation of the data, the actors, and the processes. The objects are often a mix of pure value objects, object managers, actors that carry out actions on multiple data items, and facades/processes that coordinate several actors, maintain their own state (internal model/statemachine or externally in other objects).

The "Framework Supported" Model (for want of a better term). This is where the data model has some aspects of the domain model, but a number of pieces are defined outside of the "model" and in a framework. Bits that are often separated are things like: validation, keeping track of sessions (actor state), collecting multiple models together for presentation to a view (maybe typically done in a facade), dependency injection, lazy loading, etc.

Personally, if a framework has clean and clear support for things that I'd usually put in a Domain Model, I'm probably going to use it. Especially for input validation!! They usually end up in the "controller" for lack of a better place to put them. However, sometimes it makes sense to pull it into your model... especially where you may have multiple controllers/processes acting on the same data - and leaving it to the framework controller is going to be an issue.

I'm not a fan of "views" pushing data back to the models without the controller... unless you're doing your validation and access controls, etc. in the domain model then it's a slippery slope. That said... if you are tracking state in the model, then the view updating state? That sounds OK... there are no hard and fast rules!

Nice post that would be even nicer if accompanied by some pseudocode examples.

You go on and on about constantly reducing the size of your controllers. I'm sold! I just don't know where to start :(

Let's say I am verifying login. So I have the controller that looks something like this:

Function logincontroller() {

if (model->verify(user,pass)) redirect(validurl) Else Redirect(invalidurl)

}

How can I improve this? Btw my intended syntax was php but left out proper syntax due to iPhone:)

That looks pretty much correct:

* Model handles its own logic (in this case, verification of credentials)

* Controller controls what happens (calling model to verify, redirecting user)

In general, models should only be concerned about their own data, and about their relations to other models. All behavior related to users should be handled by controllers (that call models as needed).

Thanks for the reply!

Let's say I add a few more things to that controller: namely ability to check if account is disabled(and to disable after x attempts and notify user) or if a captcha needs to be shown or was shown etc.

I feel before you know it the controller can get fairly complicated with all the asserts in real-life scenarios. May be the orig author is ok with it but reading the post I started getting ideas about simple 5-10 line controllers.

Many of those real-life scenario assertions can be implemented as before/after/around filters, since they apply to many routes.

In Rails, :except and :only are super useful on filters.

Also, another possibility is to noun-ify some verbs. (Some may prefer to call it resource-ification, or REST-ification)

For example, you could create a PasswordResetRequest model, which handles all of the logic for checking the old password, the password confirmation, the new password's complexity, etc. Then it would be responsible for executing the actual password change as well.

As a bonus, noun-ification enables easy logging because you'll already have a data structure to store.

Usually with Node.js/Express we handle stuff like authentication on middleware, so controllers don't need to bother. The route just includes the authentication/authorization middleware if one is needed.

Here is a simple example for hooking in route-specific middlewares: https://gist.github.com/978411#file_express_middlewares.coff...

Disabled accounts should be checked in the model. But instead of returning a boolean, it could throw appropriate exceptions (WrongPasswordException, AccountDisabledException) that you can then handle in the controller.
This would be my preferred approach, you can even just key translations based on the name of the exception, then handle them all with a generic flash message / template.
Really? Throwing exceptions on known states of your model... hardly exceptional.
How else would you achieve it - throwing exceptions for program flow is quite common in Python for example; Iterator.next() throws StopIteration when it reaches the end of the iterable.
To be honest, these problems are probably more endemic in the Zend Framework world than most other frameworks, since ZF was specifically designed to be a toolbox, not an opinionated framework, and therefor doesn't come with a standard way of implementing models.

Personally I like this because it make ZF usable in a wide range of projects, but I've seen a lot of developers struggle with the concept of having to design the model themselves instead of filling in the blanks in the framework. Nine out of ten times they end up stuffing the business logic inside the controllers because "there's nowhere else to put it".

That's actually not a bad way of thinking about what frameworks are: a structure of places to put things.
He had me up until the part about models talking directly to views. I was nodding along until then.

While I agree that the application business logic should be in models, but the controller needs to be that traffic cop, only asking for what the view needs and then handing it to the view. Having the view get this giant dump of things from models, skipping the controller entirely makes for confusing code as views can (and should) be reused for multiple data sets on different pages. The controller doesn't have to have much in it, but it's the traffic cop for the page (like a boss).

The trouble with this article, and indeed many of the posts in this HN discussion, is that what certain web frameworks have decided to call MVC has only a tenuous relationship to real MVC.

The point of MVC, as originally practised in Smalltalk and used by numerous GUI libraries ever since, is the three-way separation of concerns between the underlying data, the presentation of that data, and interactions that change that data. It's an elegant way to reduce dependencies, in particular eliminating dependencies from the model onto any part of the UI, by having some parts of the system push information and others pull it. It remains a useful basic architecture for interactive GUI applications to this day.

In the modern corruption used by various web frameworks, three subsystems have the same names, and that is about where the similarity ends. The three components are typically arranged in a linear stack, with linear dependencies. The responsibilities for the "controller" are very different.

This leads to comments like the parent post:

    He had me up until the part about models talking directly to views.
    I was nodding along until then. While I agree that the application
    business logic should be in models, but the controller needs to be
    that traffic cop, only asking for what the view needs and then
    handing it to the view.
If your view can't present data from your model without going via a controller, then you simply aren't using MVC. Your design might be perfectly reasonable and do its job well, but please call it something else.
What you're suggesting is more like MVP (Model View Presenter). Making the view "dumb" in MVC simply results in a lot of overhead and duplicate logic inside the controller, that constantly has to "translate" stuff for the view.

Having the view talk directly to the model actually makes the code a lot simpler (and a lot less of it).

If all your view can get from the model is "a giant dump of things", there is probably something missing from the model. Because in that case, all the controller can get is also "a giant dump", which means you will need to add business logic to the controller to process this giant dump for the convenience of the view. Which puts us right back where we started: bloated controllers that contain business logic that should be in the model.

Ok, fair enough on the "giant dump" statement. That wasn't phrased particularly well. What I was trying to say is that view should be 100% a reusable display, and as such it is given a chunk of data to display, instead of asking for it directly. Not every use case needs the same data, but the display code (say HTML structure for the web) should be able to be reused. Like a list that could be "top users" or could also be used on "top comments" (rough example).

Maybe I'm off and what I'm describing is MVP rather than MVC, but the experience I described is usually the strict interpretation for MVC, whether we're talking about a PHP framework or an iOS app in Objective C.

Edit/Update: ...however, there are times or projects that really need a modification to the "strict definition". For instance, a more modular approach works well at times, and thus you'd have to break some of the MVC/P rules. I did just that at work for a internal PHP framework and it's be a complete success, so obviously I'm not arguing you "shouldn't" or that it's "bad", but the author was discussing what he thought was the traditional definition of MVC, and that's where we disagree slightly in regard to models.

I think there is confusing when you say a view shouldn't have to ask for data. Regardless of how that data is given, at some point, the view has to ask for data. It has to attach itself to some aspect of that data, or it has to print out the data, or whatever depending on the language.

Basically, there is no difference between:

    <?php echo $data['email']; ?>
And

    <?php echo $data->getEmail(); ?>
Both are asking for the email.

Take your list code in HTML example. You can easily create a view that asks for data from a model, and simply ensure that the model always uses the same interface. Now, any model that should be listed has the same interface the view can access.

Views shouldn't be running actions on the model, of course. But it makes no sense to take data from a model, compile it up, and send it over to the view, when you can simply send the model to the view.

YES! I am exhausted from a long run and cannot articulate my thoughts clearly but just as an example, I try and overload my Django models with as much logic as I possibly can. Add tons of functions for fetching attributes, use @property(s) and make use of custom managers or queryset subclassing when you can. If you spend the time to "fatten" (as this article mentions) up your models, your views and the actual nitty-gritty glue holding your app together will be MUCH simpler and easier to follow. Let your models do the heavy lifting!
Interesting reading but I don't get the rant about the controllers being so ugly containing the model logic? I mean it's essentially a matter where you place the logic. The logic itself whether in the controller or model will/could be very similar.
Slightly OT extreme noob question: what is the core idea behind controllers? I've read some introductory Rails stuff but I never really got a good grasp of what the point of the controller is, most explanations seemingly reducing to "the thing that goes between the thinky bit and the user interface". I know I'm missing a lot, can anyone point me in the direction of some good reading material? My background isn't webdev so there's probably some missing assumed knowledge.
The point of controllers would be to glue together front-end protocol (HTTP in case of web apps) code and hide this from back-end (model) code. Models should be written so that they could be reused in a desktop or mobile app for example without issue. A model would know to check auth or authorization, but would not know that the username and password were coming in through HTTP forms. The controller is the thin layer that hides that.

IMO, the controller is not reusable between frontends. A web user controller would need to be rewritten for a mobile app. The view and templates too, of course. Current technology makes it so that this is mostly a non-issue, as webapps (think: Rails, Django) are written in different languages and use different libraries from mobile apps (think: iOS apps, Android). But we must recognize this is an artefact of current technology that could change, and is not an ideal case.

Anyone writing mobile apps in "web" scripting languages ? AFAIK, the iOS app store forbids non-Objective C apps. I could be wrong.

My original answer was longer, but this is hopefully clearer. Small programs are often split: Input Parsing. Process. Output presentation.

We can think of MVC where the View is the output presentation. The Model does the processing. The Controller does the initial input parsing, determining which part of the process to pass control to.

The Controller as "dispatcher" or coordinator.

Thanks, this helps! Can you recommend any further reading? Or is it simpler than I'm thinking?
Fat Stupid Ugly Controller instead of the succint (decidedly more literate) Fat Controller - sadly an opportunity lost.
I am concerned by the tendancy to throw everything into one in-process model. (by in-process I mean that we are calling a ruby function calculatePrice in the same model / whatever instead of calling out to a web api and getting back a price)   

It's usually cleaner to think about web service calls - not  put everything into same model

even though you can cleanly seperate functions within a single model the tendancy to make an inprocess call not an api call is always high.    So removethe tempation.

Have a thin model, a thin view and a thin controller all doing just one (rest-ful) thing and call between them

the overhead in creating objects from passed in Json is far lower the trying to unstitch logins, transactions, funny bits of business logic from one monolithic model 

(not that I am saying you would end up with a monolithic piece of spagetti but I have seen some indark corners of the enterprise world, even in projects which have all the right buzzwords)

I struggled to comprehend what you are trying to say.

It sounds like you're saying "Make everything a service and that will solve all your problems". But in doing so, you abstract the complexity from the core of the problem, to some other layer. Sort of like SOA, meaning you end up with some orchestration language (BPEL?). You've ended up with a kitchen full of self-replicating spaghetti.