Php – application logic, business logic, models, controllers – where to put the application’s brains

classmvcPHP

I'm trying to wrap my head around models, views, and controllers, but I feel as though the more I read, the more conflicting information I seem to encounter. I guess the general goal is–as far as I've seen–to shoot for fat models and thin controllers, but I'm still a bit baffled by where to put what. Can I give an example from something I'm working on?

This is just a personal project that I'm messing about with in PHP for fun–a mini-game of sorts. Adding timed tasks to an itinerary and collecting rewards when the task completes. So a class kind of like this exists:

class ItineraryEntry {
    public $user_id;
    public $task_id;
    public $completion_time;
}

And another class like this:

class Task {
    public $task_id;
    public $description;
    public $duration; //in seconds
}

So in the user interface, the user sees a task description and clicks something like "Add to Itinerary". Now if I'm understanding correctly, the controller needs to pick up that request and do something with it. But…how much? So for example, I need to figure out when the task will complete. Keeping it simple, that's merely time() + the duration of the task. So does the controller do that calculation and then give it to the model to validate, or does the model just handle all of it? And the controller is really just a glorified router of data?

Then the second part is what happens when an itinerary task completes. So from the user interface, a task will show as completed if the completion time is in the past, and the user will have to click something like, "Claim Rewards". Let's just say it's…I don't know…XP (i.e., experience points)–something that gets updated on the user's account. And let's say that the amount of XP is calculated in some way based upon the difficulty of the task, time required, etc.

So where would I put that calculation? Is that inside the model class for my user object, or do I have a controller that figures all of that out and then sends it to the user object? In the model for my itinerary entry model? And the reason I ask this specifically is because any kind of Claim Rewards code would have to do a couple of things at least:

  1. Actually claim the reward and update the user's account
  2. Clean up the expired task from the database (or marking it completed or something)

So it would be interacting both with the user and the itinerary entry.

A little specific guidance would be really helpful. My brain is starting to hurt from reading all of these explanations that are kind of like what I need to know, but not totally. So thanks in advance!

Best Answer

MVC can mean a lot of different things, and the right answer probably looks like, "Whatever works with my framework and whatever else I am using or doing."

This is a topic where understanding history helps you understand why people do things the way they do them, what it means, and how the idea could evolve in the future. The last is important - if you can figure out how people will do things in 5 years, in 5 years you can have 5 years more experience doing it "the modern way" than anyone else! For a full version of the history, see http://c2.com/cgi/wiki?ModelViewControllerHistory.

Here is a summary. Originally MVC appeared for interactive applications. (I know this seems like a diversion, but this will matter.) Every single interactive component - every dropdown, etc, had its own model, view and controller. The job of all three was well defined. The Controller would have a set of possible events that could happen (someone clicked a mouse, pressed a key, another controller passed a message saying do something) that it was supposed to take care of. In turn it knew about a view and a model. The view knew how to draw itself (you were told to scroll down, select item #3, etc). And the model was in charge of the data that determined what was in the view (eg list of entries for a dropdown). Very, very granular. Lots of components. Lots of dynamic interactions.

MVC is still used this way for interactive applications.


Then the web came along. One thing programmers do when they move to a new domain is try to carry along existing patterns. MVC was a proven one. In the context of the web, the only event of interest is "request page X". Suppose that is a page where a user can edit their information. There is going to be a data model associated with it. Think "User object, with these fields". There is going to be a view. Think, "Template for how to show the user." You can even have different views for the same object - if I look at your home page I am allowed to see different information than you are.

So far, so good. Where is the problem? There are many. Here is a short list.

  1. Generating a dynamic web page is usually much more complex than handling a click of a button in an interactive application. Therefore each of the three components is doing a more complex thing than they would in the application case.
  2. It is unclear to people what belongs where. The same code can go in the model, view, and controller, and it is not immediately obvious that it matters where it lives. But random things tend to be particularly easy to insert into the controller.
  3. Complex web pages include multiple things that want data models - for example a form, a sidebar, ads, and so on. How do you represent that?
  4. Over a website you generally have many views, but you want to maintain a consistent view across them. How do you structure your views to allow this, while making them make sense for designers who are not programmers?
  5. Over time we're moving towards richer and more complex interactive pages, with tricks like AJAX. How do you shoehorn this into a per-page mentality that is natural when handling http requests?

And so on.

There are a lot of possible solutions to these, with different tradeoffs. In general if you use a framework, and try to solve things the way the framework expects, things work well. If not, well, then things get challenging. Hence my advice above to do whatever works with your framework.


But there are general principles.

Since controllers have a complex job to do, and are easy to insert additional logic into, the natural progression of code over time is that everything winds up in the all-knowing controller. Single large interacting blocks of code tend to not scale well. So you want to keep everything that can be kept out of the controller, out of the controller. (Some frameworks make things even simpler by splitting up controllers recursively!)

Business logic almost always belongs in the model. If you've got a database and an Object Relational Mapper, it is easy to structure models for simple applications as fairly straightforward layers over database tables. This is a popular design.

The view usually winds up being some sort of template system. How to handle commonalities is up to your template system. Understand the system you use, try to work within it.


You're a self-admitted beginner. I would highly recommend picking a framework, following advised best practices for said framework (even if you later decide they are not best, organizing code like your framework expects tends to be a path of least unexpected surprises), and getting practice with simple applications before tackling anything more complex. I highly, highly, highly recommend this - before trying to run, make sure that you're good at walking.

But as you walk, come back to this post, look at the list of pain points I gave above, think about your did or didn't hit them, and how you could handle them within what you built. This type of deliberate "how would I?" self-reflection is a critical part of improving. As I say, those are known pain points that come up across many different frameworks and I don't think that we've found the best way to handle them yet.


If I had to guess where we'll go, what do I think?

My belief is that as web pages get more interactive, they are becoming more like existing interactive applications. (Have you used gmail with keyboard shortcuts recently?) The more that they become interactive applications, the more that it makes sense to use MVC in JavaScript in the way that it is used in interactive applications. The more complex your front end becomes, the more it makes sense to have the html that delivers that being delivered by code which is structured the same way that the code you are generating is being delivered.

If so, then we should (indeed I believe already are) see front end web pages that have many controllers, many models, and many views which can interact. These will eventually be pushed back to the server which will be expected to generate those parts of the page with similar granularity (albeit with the ability to pass information around so that the JavaScript library that enables X is actually loaded in the appropriate part of the page for that).

I think this in part because I have worked with a proprietary system that was structured this way. It was interesting. There were many controllers, views and models. However the controllers turned into data structures with some data inheritance to handle commonalities, the views into simple templates, and the models were parametrized by information from the controller. The concerns were so well separated that we were able to put the three into three different languages (Perl models, YAML controllers, TT templates). We were able to do things like completely rewrite the back end to the website (literally different pages, accessed in a different order, that were hitting different services) while managing to reuse, unchanged, most of the front end.

It was clear to me that that implementation was not exactly the right way to do it. But I think those ideas will be rediscovered multiple times, and over the next decade I think that is the direction that a lot of people will head.


If this sounds likely to you, and you like front end work, then after getting some simple sites working in whatever server language you want (from the sounds of it PHP, though I personally would prefer anything else), I'd suggest learning JavaScript, picking up a popular MVC framework like http://angularjs.org/, and trying to write interactive applications using it. Pay close attention to what works and doesn't, make your own theories, experiment, get feedback, and you'll be likely to be ahead of the future when the future arrives.


(How did this answer get so long? Oh well, it is written, might as well post it.)