The M in MVC

In the last few weeks I’ve been thinking about models allot. Models, as in Model-View-Controller modules, are the most abstract and hard to frame-out part of this holy trinity (one might say Models are the “Holy Spirit” of MVC). So what’s the best practice here, if there is even one?

Models represent data and provide the means to preform data-specific actions. In a sense this is exactly what objects are (as in OOP objects) - so one might say that simple container objects are in a sense what the model should be. But in the real world, you almost always need data persistence, which means having some kind of storage mechanism to read from or write to. In the PHP world that’s almost always a database (and almost always MySQL) but it doesn’t have to be: Models could be based on RSS feeds, XML or other serialized data formats, web services, and more. In fact, $_SESSION could (and should?) be a part of your model. So data-layer abstraction could be a nice thing!

It gets even further - think about a model class which uses several data layers, mixing RSS feeds with locally stored meta-data for example; Or a Transaction class, that when saved, will both save local information in the DB and send an API call to PayPal, executing the transaction or fetching information from PayPal’s logs.

Well - getting back to my point, I was thinking about the best way to “frame-out” models and I have to say I didn’t come up with a good, practical solution. One of the conclusions I did made however, is that we are thinking completely wrong when designing our models. We (or at least I) have a tendency to design the model layer by starting from the storage and data access layers (the DB schema usually) and then going to the application layer. If you ever used Propel, it does exactly the same (as all ORM attempts probably do) - you design a database schema, and then build your model classes around it. Then, whenever your application requires some complex relations or data access, it becomes hell and you need to hack things together to make it work (try things like efficient batch updates, or efficient JOINs).

This is obviously wrong. We should be building or at least designing our application first - designing the logic, planning what sort data and what data related actions each action will need to perform, and then design model classes accordingly. These classes in turn will be used to design the data storage layer. The end result will probably be a set of classes for each DB table (or pseudo JOINed tables for that matter) but in run time, will be much more efficient and easy to use.

I am not sure how this can be done and even if this is possible - consider it to be a theoretical idea. But think of the possibilities when you start from the application layer and go down - instead of being limited by your data access layer.

You’re more than welcome to share any thoughts (or objections).

11 Responses to “The M in MVC”

  1. July 9th, 2007 | 20:09

    Hi,

    I actually quite like the way Propel works (or at least how it’s integrated in Symfony). OK, with Propel, JOINs can be a hassle, but things like combining your storage with an API call is easy thanks to their split between Model and BaseModel (where the BaseModel can be overwritten by schema changes, but the Model won’t). You simply override the save() method by adding a save() method in your Model, adding the API call to that one and in that method calling parent::save(). That way, it’s not that hard to combine local and remote “storage”.

  2. July 9th, 2007 | 20:18

    Hi Stefan,

    True - Propel has some nice ideas and it’s sure is easy to use - but performance is horrible - plus this is not really what models *should be* - it’s very RDBMS centric.

    In any case my point wasn’t ranting about Propel - it was about the idea of having logic-centric models instead of storage-engine centric ones.

    Shahar.

  3. July 9th, 2007 | 21:31

    I like to think of the model as the ‘business logic container’. This is not just a database table, or not just some set of data. It’s what implements your application’s core logic.

    The example that I think gives a good explanation of th model is a ‘document’. Say you’re building a text editor; in that case the view is the window that displays the document, the controller is the application glue that ties everything together and the model is the document itself. It contains the data, and the logic that determines how to handle it.

  4. July 9th, 2007 | 21:32

    Ah right. Well, the idea of logic-centric models is very good, but with most modern web applications, I guess storage is very much the things models are about. It took me a long while to really understand the use of MVC in the first place (at least for web applications), and my understanding of Models in this is that it’s data-centered, and as such, will be aiming at storage, to which of course you can add additional logic. I’m unsure as yet if in this case I really understand your idea of logic-centric models.

  5. July 10th, 2007 | 01:56

    I think you’re getting your objects mixed up. I would not consider Propel or any other ORM to be the model of any application. It’s just a layer over some storage medium. The real model would yet another layer built on top of it.

    While I agree that we should develop our models with the needs of our applications in mind (isn’t that stating the obvious?). I can’t agree that we should leave truly complicated and critical design issues such as database abstraction until the end. The real value in using an ORM is the ability to change your datalayout (i.e. the table structures and relations) without having to change your application code. That’s a very different goal from an application’s models’ goal.

    I think with smaller applications which only perform CRUD operations it is hard to see the distinctionb between an ORM layer and the domain model. However when the model’s responsibilities extend beyond just reading and writing from the data store — i.e. they perform calculations on objects — then the two take on distinct roles.

  6. July 10th, 2007 | 05:42

    Hi Alex,

    First of all, it seems that quite allot of people use Propel as the direct basis for their model layer. If you’ve ever used Symfony, this is the way it works there.

    Propel in turn uses Creole IIRC for database abstraction - so the ORM and data access are two separate layers. You can use other tools for database abstractions, and in fact the PHP world is full of pretty good database abstractions layers today which do not implement ORM (Zend_Db and PEAR_Db comes into mind).

    I also don’t see how you can change the database layout without changing your code in ORM. Again, my experience is only with Propel - but in Propel if you change your layout you need to regenerate your OM classes - true, the code generation tools do the work for you, but you still change code.

    Now back to my original thoughts - think about a tool like Propel, in which instead of defining your database layout in a configuration file, you define your controller/action needs in a configuration file, and let it generate the code for you. Again, I am not sure this is possible, but if it was, it might work out better then going the other way.

  7. SteveJ
    July 11th, 2007 | 17:50

    The problem is thinking about solutions in terms of data. If you start with data, you will almost always fail, because you’ll over-analyze and end up with things you might need, or (even more likely) someone will add a new kind of data 2 weeks before release. If your solution starts with data, this means a lot of code churn, even using code generators.

    Start with interfaces. Think about what the solution should do. I find that lends itself to a more flexible design, where the data and types fades to the background and you can focus on the plumbing and interactions first.

  8. Simon
    July 11th, 2007 | 19:05

    This is why everyone ends up doing proper OO design. Ignore the persitance at the beginning, just assume it will happen some how and sit down and create some use cases. No need to go crazy with the diagrams just enough to find the croners of the system. The classes and lower down storage stuff will work themselves out. Classes dont have to map to DB tables. The Data Access Layer isn’t the model

  9. kevin
    July 11th, 2007 | 19:22

    In my mind, the model is an API. The user of model (the controller and view) shouldn’t need to know or care if it uses a database behind the scenes. You can create the interface for your model and start using it in your controller and view before you actually every hook it up to a database by creating dummy implementation of the interface. When you do add the real persitance layer, the controller and view shouldn’t have to change at all.

  10. shane smith
    July 12th, 2007 | 14:12

    I’m with kevin, simon && alex on this issue.
    My model in my mvc webapplications are a set of classes that my controllers can use to retreive data.
    These classes are the classes i could then reuse for a different projects or application.

    So if my controller needs a list of data, say a list of emtpy inventory items, all i need to do is write the method for the product class, in that method i write a query with an outer join, and return the data i get from in this case the database.

    This data/api/model i can then re-use for say an xml service, like an rss feed, or for a webpage, or something else.

  11. July 12th, 2007 | 16:33

    Thanks for the comments everyone!

    Those comments bring me to ask another question, which perhaps I did not put enough emphasis on in my post: Can your model classes (as Shane, Kevin and others described them) be abstracted into a framework component or even a design pattern?

    Can it be abstracted into a set of classes?

    In other words: Why is there no Zend_Model in Zend Framework, why does Symfony use Propel directly as model classes, and do you know a framework that implements model classes in a reusable and well-designed manner?