Friday, May 23, 2008

ActiveRecord does not suck

I've been reading a few blog postings such as Kore Nordmann's ActiveRecord sucks and Mike Seth's ActiveRecord sucks, but Kore Nordmann is wrong.

ActiveRecord is fine.  It is a tool that does just what it's designed to do.  What sucks is when developers try to make it do other things than what it's intended to do.

I worked for Zend, managing the Zend Framework project through its 1.0 release.  I also completed the implementation and documentation of Zend_Db and its related components. To set the record straight, Zend_Db does not implement the ActiveRecord pattern. It implements the Table Data Gateway and Row Data Gateway patterns, which taken together offer similar value as the ActiveRecord pattern.

I totally agree with Mike Seth that MVC should not be taken as "ActiveRecord-View-Controller." I tried to make this point in documentation, screencasts, conference presentations, and in many mailing list messages, but I met with little success.

Unfortunately, the Ruby on Rails drumbeat that Models are simply database table wrappers has established momentum.  The term "Model" has (incorrectly) become synonymous in many developers' minds with "ActiveRecord."  Since Models by this definition are tied to database access and largely implementing various query techniques, Ruby on Rails development forces you to write a large amount of code in the controller classes that should properly be written in Model classes.

This has a few consequences. Unit-testing controller classes becomes very complex, since that's where the majority of your application code resides.  To test a controller class you need to mock HTTP requests, and sift through HTML output.  This is fine, but it results in more work since testing the controller class is so important and complex.  If the application code were separated into a true Model, then unit-testing the controller would simply be testing whether the HTTP request had been communicated to the Model correctly.  Testing the behavior of the Model would be much more straightforward unit-testing of a class API in isolation, requiring no mock HTTP requests or scraping HTML output.

Also, unit-testing Rails-style Model classes is difficult, since the Model is coupled with the database.  We start to see unfortunate things like database fixtures as being necessary before you can execute the simplest tests against your Model class.  This makes testing Models time-consuming, error-prone, and run slowly.

If developers were to separate Models and Controllers properly, and separate data access components from Models, unit-testing all of these classes could be done more simply, and with greater isolation from other classes.  This makes it easier to diagnose defects, when they occur.  Isn't this the point of unit tests?

A Model is a class that provides a logical component of your application domain.  Models are products of OO design, which is a development activity I see get very little attention in the developer blogosphere or the developer tools market.  Developers seem more enchanted by evangelizing their favorite code editor or debugger, or by squeezing more performance out of their database, than by mental analysis to make sure their OO architecture is modeling its application requirements well.

A single Model class may be backed by a database table, or multiple database tables, or perhaps even no database tables.  Data persistence should be an internal implementation detail within a Model; the external API of the Model class should reflect its logical OO requirements, not the physical database structure.

(update) What I often tell people is that the relationship between a Model and an ORM class should be "HAS-A" rather than "IS-A."  The latter is the assumption of Rails and other frameworks who are enticed by ActiveRecord.  If the Model uses ORM objects instead of inheriting from ORM classes, then you can design the Model to contain all data and code for the domain it's supposed to model -- even if it takes multiple database tables to represent it.

Many developers have complained that Zend Framework provides no base Model class. Of course it doesn't provide a base Model class! That's your job. This complaint is like saying that Microsoft Word sucks because it doesn't provide finished documents for you.

So I wouldn't say ActiveRecord sucks.  I would say that people are expecting ActiveRecord to magically solve their OO design for them, in a false quest to avoid doing the design themselves.

58 comments:

mweierophinney said...

Bill, excellent post. In my various talks and webinars for Zend Framework, I've been repeating the same mantra we discussed so many times: Model !== Database. Particularly in today's Web 2.0 paradigms, the Model could just as easily consume a web service. Or the file system. Or socket input.

ActiveRecord is a fantastic tool, but, in the end, just that -- and just one tool of many that may be utilized as a Model -- or consumed by one.

ivo said...

I agree to most of your post. Except the "It's your job" part. In essence you're right. I was glad that Cal mentioned models in his book because in essence it's the developer's job to implement the model.

However, it's also the developers job to create the controllers and views, still, this is greatly aided by providing base view and controller classes that implement the common demoninator of these concepts.

Similarly, it would be nice if ZF provided a very thin basic model implementation that can be implemented/extended by the developer. Heck, it may even be a simple empty Model abstract base class. But it will make it easier for developers that are new to MVC to grasp the concept and to implement it properly.

P.S. I'm unable to comment to your blog without having a google or blogger account. I have, but it would be nice if you would allow general comments as well.

Bill Karwin said...

@ivo: I've heard many people ask for a base Model class, but why? I have yet to hear a single specific proposal for the base functionality of such a Model class. What do you have in mind?

The Model class is where the guts of your application are implemented. There's no way a framework can guess what is the common interface of these classes. It's not always a data-access layer, no matter what "opinionated software" like Rails has decided.

Matthew gave a few other examples of Model data-sources like SOA, filesystem, socket, etc. But a Model could also just be a class that provides composition of other objects (Zend_Db_Table_Rowset may be a good example of this). Or even no data-set at all, but the Model may just perform some calculations on its function arguments.

Another purpose for a base abstract Model class might be object typing. In other words, the Zend_View object might accept only objects that extend type "Zend_Model" as a kind of strict typing. But the base Zend_Model class itself would define no interface and no properties. Is that what you need?

If there is some base functionality you have in mind for a Model, can I ask what it is? What would you propose a base Model class do?

PS: I have now enabled OpenID-authenticated users to post comments in my blog. I'm not going to authorize anonymous comments.

Bill Karwin said...

@ivo: I should be more clear about one thing: I think it would be a mistake to implement an empty Zend_Model class solely for the purpose of helping people understand MVC architecture. Doing that would cause more confusion than it would solve.

OO inheritance has a specific purpose, and telling people that to use MVC they have to write code extending this empty class would be very confusing. I know that it wouldn't be true that it's necessary, but that's the message that newbies would take away from such an example.

Nate said...

"Ruby on Rails development forces you to write a large amount of code in the controller classes that should properly be written in Model classes."

I wouldn't agree with that statement at all. When I develop Rails apps all of my model logic stays in the model. Just because many Rails tutorials out there show bad practices doesn't mean that Rails forces you to write this way. For instance, I never do a .find() in any controller. I create class methods that underneath handle the necessary details. This makes it more portable, and it keeps all of the logic in the models. My controllers simply handle the requests being made (list, show, new/create, edit/update, and delete).

And, I have many models that have no DB backing, I simply don't extend from AR::Base. I also have models that implement STI. I also have models that are more simplistic. Not all of my models rely on a database. I have several models that handle filesystem information for me - none of which are connected to a DB.

So, while I understand what you are saying - and I agree that developers often times try to do things that AR simply wasn't made to do, I disagree with you saying Rails forces you to do something. That just isn't correct.

Jonathan L said...

Bill,
Thanks for the great post. I wasn't sure which patterns Zend_Db was implementing specifically (although I knew it wasn't pure AR, and for that I'm grateful). It's really refreshing to read people like yourself talking about patterns in PHP.

A note about Unit Testing models... doesn't it just seem like you're testing the base classes, or at best, doing Integration testing? I found myself testing the ORM capabilities of Zend_Db and making sure it did basic CRUD.

akrabat said...

I would say that Zend Framework has been more successful than most in separating the model from the database table.

Rob...

MichaƂ Minicki said...

@ivo Framework base class (or even intetrface) for models would couple your model to the framework code so it wouldn't run outside of it. And that's what your model should be able to do by design - you should be able to use it in every framework imaginable or even without one. Or at least in a framework that does it's job well.

Secondly, when you extend your class from a framework base class you're closing a way to actually subclass from any other class. So basically you're limiting your own domain design this way.

@Bill - great post, Bill. But your text tells exactly that - why Active Record does in fact suck.

Bill Karwin said...

@nate: it's great to hear that you have broken out of the box presented by Rails documentation and examples. It sounds like you're doing it right.

Yes, I acknowledge that the language doesn't "force" you into that box. But the term "Model" is used commonly to mean simply a data access object. It seems like developers like you are the exception.

Bill Karwin said...

@martel: good point about coupling to the framework! Ideally, the Controller should serve as a thin layer to pass application inputs to the Model classes, and then pass the Models to the Views.

If the Models encapsulate their own behavior adequately, they should be able to be repurposed easily in another application.

Imagine if you had to make your web app into a console app or GTK app, and you had less than a day to do it. If you have too much logic in Controller actions, it would be too much work. If your Models encapsulate their behavior, it would be much easier.

I'm not saying it's impossible to do things right in frameworks like Rails, just that developers who don't employ OO encapsulation are doomed to write spaghetti code that is only slightly better than old school PHP4 apps.

Bill Karwin said...

@jonathan: are you aware that Zend Framework includes pretty thorough unit tests for the base classes? You can run these tests yourself to verify that your basic CRUD operations are working.

Then you should focus your own unit tests on verifying the functionality of any custom code you have in your extended classes.

But anyway, yes you do have a point that what we often call unit testing isn't strictly so. Unit testing should be able to isolate a single class from all others in the application.

But that's part of my point -- if your Model is decoupled from the database access object, then you can create a mock database access object for purposes of unit testing your Model. Ideally, you should be able to test your Model without touching the database.

Rich said...

(update) What I often tell people is that the relationship between a Model and an ORM class should be "HAS-A" rather than "IS-A."

Amen to that, Bill.

monkeyt@mac.com said...

For most PHP devs (having little or no OO background), Models are quasi-mystical elements. Even more recent (and successful) MVC tutorials spend little time on them because, as you point out, the implementation of Models is usually very project-specific and hard to usefully generalize. The simple discussion you've had here in your comments has helped me clarify ideas I had already formed about how Models are most successfully used. As co-organizer of a PHP user group, all I can ask is for you and others who truly understand the subject to keep this discussion going through your blog posts and (preferably) example-laden tutorials. The community can only benefit, even if contrasting opinions make for heated discussions.

Bill Karwin said...

@monkeyt: Woot! Thanks very much for your kind words!

Yes, I agree that it seems a large majority of PHP developers are self-taught and have a pretty informal background. You can see it in the tendency of the average PHP developer to write their "classes" as simply a container for a motley collection of static functions!

Hopefully we can all help to increase the OO maturity of the PHP community. I'll try to find time to write a sample app, showing the "wrong way" and the "right way".

Read Craig Larman's "Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development." That's a really good, meaty book about OO design.

Marek said...

Excellent post and I agree with pretty much everything written.

With regards to Zend_Framework components, I have to agree with the majority view that you simply can't implement a Zend_Model as it's far too general a concept.

I think a nice option though would be to implement the Data Mapper pattern somewhere in ZF along with possibly an Identity Map as those are two very useful patterns in achieving a database independant domain model.

Regards,
Marek

Bill Karwin said...

@Marek: good comment. I can see the value of Data Mapper and Identity Map in an enterprise application, where you have data objects that live over many web requests, and many Model classes that may access the same underlying database tables.

But PHP is by its nature not "enterprisey." The share-nothing architecture encourages us to load from the database only the minimal data needed to render the web page for the current request, and by the end of the request, the data evaporates. Also, typical framework-driven web apps don't create more than one Model class per Table (or set of related Tables). The benefit of Identity Map and Data Mapper aren't as great in this environment.

Moreover, it requires more education for developers to use these patterns. Keep in mind we are trying to educate the typical PHP developer on the difference between a data access class and a Domain Model class. In fact, we're still trying to educate many PHP developers that they should actually instantiate objects, instead of writing all their code in static class functions.

I think it's important to make the distinction that the Domain Model should be separate from the physical database structure, but in most cases, data mapping can probably be done in a straightforward manner in a Model class, without adding more layers of abstraction.

On the other hand, if you think it would be beneficial, go ahead and submit a proposal here:
http://framework.zend.com/wiki/display/ZFPROP/

Jani said...

Excellent post. I've personally noticed the same trends regarding model == DB == ORM...

While I have to admit that most of my models reflect the database in most cases, the database is also modeled after the domain.

So while what said here is true in some cases, using a one-to-one model-database relationship is often a factor that can speed up development greatly without actually being a "bad thing".


What comes to having a base Zend_Model thing... I think it would be helpful for beginners to have something to help them understand models - be it links to pages explaining MVC, or even a full article written just for ZF.

Jason said...

I have to take note here that your statement about being forced to write code in your controllers is blatantly wrong. A Rails Model is nothing but a Ruby class that extends ActiveRecord::Base. You can add whatever you want to your class, and are highly encouraged to do so to keep your controller code clean, for many of the reasons you outlined here.

Please see: http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model

Bill Karwin said...

@Jason: You're making my point for me. The jamisbuck blog you point to addresses the same issue I'm talking about. Code clutter in the Controller or in the View should probably be in the Model instead. The author sees the same widespread bad practices, and he's trying to educate developers to a better practice, just like I am.

I admit Rails does not "force" you to write clutter in the Controller, but what does one do when a Domain Model is logically comprises of multiple ActiveRecord objects? Put methods in one ActiveRecord Foo to retrieve data from ActiveRecord Bar? And vice-versa? That doesn't really match the OO relationship between those objects. Which is it, Foo HAS-A Bar, or Bar HAS-A Foo?

What I'm calling for is to think of Domain Model as distinct from ActiveRecord. In utterly simple cases, you might treat them as coincident, but in general they are not.

Bill Karwin said...

@Jani: That's a great idea to add a section to the ZF documentation called "Zend_Model", even if there is no code with that name. It would be a place that developers would naturally look. This documentation section would explain that Models are to encapsulate your application domain objects, both data and code. Plus examples, of course.

bucky said...

yeah great post. i really think the whole ActiveRecord religion has been bad for the development community. Not because it is a bad pattern per se, but its been evangelized in the wrong way.

Nima said...

I'm agree, ActiveRecord should be utilized as a backend layer for the Models that need database access. However I use stored procedures on my applications and do not use ActiveRecord because of performance issues.

musher said...

Great post, makes me feel better about reading the other two rants, I mean posts ;)

philip said...

I prefer Doctrine with Zend Framework.

http://www.orsa-studio.com/phptaco/

Chuck said...

Horde's ORM layer chose to implement Data Mapper from the beginning instead of Active Record - although honestly I did this at the time mostly because I found the gymnastics people were doing to get around late static binding were semantically confusing or wrong ($user = new User(); $user->find('name' => 'Bill'); ... you just asked a user object to find itself. weird).

http://horde.org/papers/bostonphp2007-06/ is a bit of an introduction to it, though the code has evolved a bunch since then.

[MuTe] said...

Hi,

Thanks for the great post, being new to MVC I have found it confusing trying to find good guidance to what a model is in the web world. I thought I had being doing models wrong by not doing them the ruby way, turns out I was right :)

I have one question I hope you could help me with. Say I have a subscription model and a registration model, is it good practice for my registration model (which creates users,subscriptions etc ) to use the subscription model?

Thanks keith

Bill Karwin said...

@keith:
"...is it good practice for my registration model (which creates users,subscriptions etc ) to use the subscription model?"

If I understand correctly, then for example, you probably have a registration form, which includes fields about the user, the subscription, and maybe other stuff too.

You could make a Registration model class that handles the form, validates it and delegates some of the fields to a User model and other fields to the Subscription model. So you could say that Registration knows about the relationship between Users and Subscriptions.

Another way to do it would be to have a registerNew() method in the User model class. This method processes the form data, and the User class is responsible for passing some fields along to the Subscription class.

I think of classes as nouns, and methods as verbs. Registering is more like a verb, applied only to a new user. So it doesn't necessarily need to be a separate class at all.

There can be more complex cases where Registration needs to be a separate class. For instance, maybe it needs to be able to register other types of objects besides Users. But in a simple case, it can probably be a method of the User class.

That's what makes Model class design harder than Controllers or Views. Controllers handle application input and Views handle application output, which are both relatively simple and well-defined tasks. Frameworks are best at helping you put these together quickly.

However, Models comprise the rest of the OO design for your application. This is where you actually need to think hard about what the entities are, and what operations exist for those entities. It's hard for a framework to help you in this task.

Nino said...

If you really want to understand what a domain, a model (the abstraction of a domain concept) and the "holy grail" of OOP is read DDD by Eric Evans.

@Bill: fine article, but even the "a model may ce connected to a database" is wrong. Persistence is not the model's (domain objects') responsibility. An object in an active state "lives forever" until it is killed (deleted), it's only a technical drawback that we need to persist it.

Bill Karwin said...

@Nino: Thanks for the reference. For the benefit of others, DDD stands for "Domain Driven Design" (ISBN 0321125215).

Yes, the idea is that a Model is an OO representation of the Domain. Persistence is an implementation detail. I think we're saying the same thing.

Nino said...

Yeah, seems so.
;-)

But for all the ORM/AR/Hibernate discussions: I've done such stuff with ORM wrappers but in the end, respecting the heterogenity of today's technolgies and data sources, it's faster and more secure by hand.

You change details of the model often when requirements change but you don't change your database often in that case.
If an requirement needs to be refactored most often the db stays the same.

So, it's just work for nothing. People should more concentrate on making a good and flexible design instead on technical gimmicks.
But i know it's an old story: most people want to do something not think and talk about something.
:-)

Bill, keep on the very good work!

Paryank Kansara said...

Thanks Bill, you have described pretty much clear concept about actual MVC vs AR-VC.

I am using Zend Framework since its 1.0 release. At the start, I read lots of tutorials about Zend Framework which were explaining the models as Zend_Db_Table subclasses. It was a misconception but may be suitable for CRUD operations only.

Then, I had gone through the code base of Magento Commerce, an open source eCommerce Package built with Zend Framework. And I came to know a perfect way of MVC implementation in enterprise applications. (Magento actually uses many ZF components but does not use Zend_Controller and Zend_View for MVC architecture. Instead, it defines its own base classes. But the implementation is quite similar to ZF way.)

I still don't understand why CakePHP and Symfony documents still define model as a database layer!!!

Paryank Kansara said...

Magento separates model classes from data access classes in very nice way. There are two base classes for it:

1) Mage_Core_Model_Abstract
2) Mage_Core_Model_Resource_Abstract

First one is a base class for models while second one is for data resource. Data resource can be database or file or any other data provider.

Mage_Core_Model_Abstract defines some common methods like save(), delete(), load() etc. which implicitly call respective methods from resource model class. The relationship between model and resource model can be defined explicitly which provides a loosely coupled and flexible architecture.

Think about the case where I am storing the data in the database and later I decide to store it in XML files. In that case I do not have to touch my business model classes. Instead I have to define another resource model class(es) which can provide or store data in XML files.

This implementation seems perfect and much flexible. What do you say about it?

As ivo asked for base class for models, can't it be implemented this way?

Bill Karwin said...

@Paryank: Thanks for your positive comment.

I like to say that software design is a process of making assumptions to simplify, and then breaking those assumptions to gain flexibility. The Rails assumption is that what they gain in simplicity by assuming a Model is coincident with a database access class justifies the lack of flexibility. I assume other frameworks are following Rails' lead.

I haven't taken a close look at the Magento code, but I'm glad to hear from you that they've separated the Model from the database access. They apparently made a choice that this step in the direction of complexity was justified by the flexibility it offered them.

Ivo suggested a base Model class, and I'd be all for it, if we could define what constitutes base Model behavior. That's tough, because no matter what assumption you make in this regard, you necessarily limit flexibility for what a Model class could be.

Bill Karwin said...

I came across a quote that pertains to the idea of defining a base Zend_Model interface:

"To define is to limit."
- Oscar Wilde

Mmm, deep.

Koen said...

I read this in the manual:

class Bugs extends Zend_Db_Table_Abstract
{
protected $_name = 'bugs';
}

Based upon my understanding of the discussion this seems a completely wrong example. The model should not be an extension of the ORM but use it. Yet extending is what this example does. Am I missing something?

Bill Karwin said...

Hi Koen, thanks for reading my blog.

That's a perfectly good example of declaring a Table class, but my point is that a Table is not a Model.

class BugModel // extends nothing
{
public function lookUp($bugid) ...
public function enter(array $bugdata) ...
public function commentOn($bugid, $comment) ...
public function changeState($bugid, $newState) ...
}

These function correspond to operations your application might need to do with a bug, according to your Domain Model.

The class is responsible for knowing how a bug is stored. That is, in a database, in a table called 'bugs', which it can access using the Table class 'Bugs'.

It may need to access more than one table to read or write details about any given bug. For example the BugsProducts Table records the association between a bug and the Products table. So BugModel needs a HAS-A relationship to both Bugs Table and BugsProducts Table classes.

This all has to do with assigning responsibilities in object-oriented design. In the Ruby on Rails paradigm, you might handle the association table in the Bugs Table class. Is this where it belongs? What about lookup in the Products Table class, doesn't that also need to use BugsProducts?

In this case, access to BugsProducts is neither exclusive to either Bugs or Products, nor is it innate that Bugs or Products always need to access that class. This suggests the code to work with two tables at once belongs in another class -- a Domain Model class.

Koen said...

Yes that makes sense. Thanks for the post.

aarone said...

I think too many people make the mistake in thinking that the word "model" is a copyrighted trademark patented by the Xerox corporation, that they, as true disciples of the Smalltalk Lisa, are sworn to defend on pain of eternal suffering.

But the word "model" predates, and supercedes the MVC pattern, and actually has many uses. There are in fact, such varied things as a database model, a domain model, a Model T Ford, and even a supermodel.

IIya said...

Agree, with the author.
The funny thing is that the fact that ROR's "sillyfication" of an applications development took place shows that majority of them are probably very simple and similar.

Ariel Arjona said...

Excellent article! Bookmarked and forwarded. As you say in the comments the V and C are almost trivial and I've been satisfied with that side of things with the frameworks I've used. The M on the other hand has always left me with a sour taste. Being fairly new to MVC I've spent the last few months trying framework after framework and wondering if my dissatisfaction came from Doing It Wrong'. Now I know where the thorn is, thank you.

donuteric said...

Bill, thank you for the excellent explanation on the issue. I'm a self-taught programmer from C++ to Java to Perl, and now slowly learning the mindset of becoming a PHP developer. After reading various discussions on how Model classes are implemented, I have a few questions.

Imagine a situation where data can either be pulled from local databases or caches, should Model classes decide that action or should we leave that determination to Data Access Objects?

Because Model classes are not necessarily interested in knowing where the data is coming from. As long as they have the data they requested, they can do their jobs. So my initial thought is to have these decisions implemented in a superclass that DAO classes extend.

Am I on the right track?

Bill Karwin said...

@donuteric: What you're describing is basically a Proxy object for a DAO. The Proxy uses cached data if available, and queries the database if not.

In a given app, you will no doubt have a mix of queries that must be "live" and queries that may be cached. Even queries against a given table may vary in this way.

The Model _does_ need to know where the data is coming from. That's why it's good to encapsulate specific SQL queries in the Model.

For each query performed in the Model, you also need to know whether or not it's eligible to be cached. Based on this, you'd issue the query either to the plain DAO or the CachedDAO proxy. Or else you write a PerhapsCachedDAO which takes a flag. :-)

Also some caching may be custom, e.g. using a different TTL. It's hard to design a superclass for this.

Since we typically need to do this logic on a case by case basis anyway, I'd recommend putting it the cache-handling logic in the Model.

Phillip Winn said...

I think you've saved me much mental anguish here, but I do understand why people want a Model class.

I guess what I wish I had is an example of something that *properly* uses these patterns, and also deals with a form. As it is, I've got column names that are ugly, and form element names that are pretty, so my controller has to map all of that as it send the data to the model, which seems wrong.

Then again, passing the pretty names to the model also seems a little odd. Either way I've got to map between the two.

Bill Karwin said...

@Phillip Winn:

I'd recommend using the pretty names of form fields as much as possible. Use them for the form, for the attributes of the Model, and for rendering in the View.

Encapsulate the mapping of form field names to database column names deep within your Model class. That way if they ever change in the database, only the Model needs to be changed.

Phillip Winn said...

In so doing, I'm giving up a lot of the benefits of ActiveRecord, no?

Or, rather, I'm putting a layer between the model functions and the ActiveRecord to the underlying table. Back to the HAS A vs IS A, I see.

Still wrapping my brain around it all, obviously. Thanks for your help!

Bill Karwin said...

@Phillip Winn:

The mapping layer has to exist somewhere. Putting it in your app's Controller is probably not the best place. You'll have to duplicate the mapping in each Controller class that touches Models that use the respective ActiveRecord obect. This fails to support the "Don't Repeat Yourself" principle.

So you want to do the mapping in one place. Candidates for this are in the Model class, in the ActiveRecord class, or else in the database itself (think CREATE VIEW).

Basically, imagine a scenario where a column name in your database has changed. If you have to change more than one class in your app to accommodate the column name change, you're probably doing it wrong.

ActiveRecord is not an abstraction layer; it's based closely on the physical database structure. It shouldn't be the place to do column-name mapping.

A database view isn't a good choice because not all databases support views, or at least not write-through views.

So I'd choose the Model class, since this is typically the place for code that manages persistence from application state to physical database storage. E.g. joined queries, cascading operations, caching, etc.

rundmw said...

@Bill: Wow, tremendous article. Exactly what I needed.

I have been coding PHP for quite some time. Despite being fully comfortable with OO, I confess I have been hacking together crap code for too long. Time for some better patterns, a real framework, unit testing, etc.

Like Ariel above, I had a lingering dissatisfaction as I looked at various MVC frameworks. It always seemed that the model was little more than a wrapper for persistence in a single db table.

Paryank's description above of Magento make a tremendous amount of sense to me: Model and Model_Resource, loosely coupled.

[ Now struggling with which MVC framework to choose. CI? Kohana? Cake? Symfony. And which ORM, if any, to use: Propel, Doctrine, Outlet, etc. But these are obviously issues for another time/place. ]

Again, tremendous post and excellent comment responses. Thanks so much.

Ennio Wolsink said...

This blog post solved years of puzzling for me :). I always felt there was "something wrong" with the whole ORM == model idea, now I understand what this nagging feeling was about.

Thanks for enlightening me!

Bill Karwin said...

@rundmw and @Ennio: Thanks much for your comments!

By the way, as I learn more about Magento I must withdraw my approval of it. It seems they make heavy use of the EAV antipattern.

This explains why they had to decouple the logical model class from the data-access class, since each logical entity maps to many rows in the database.

Paryank Kansara said...

@Bill,

I agree that Magento has used EAV anti-pattern. It makes lot of performance degrade and lot of database constraints are enforced to be handled at application layer instead of database layer. I think only reason to use this anti-pattern is to provide extensibility.

Magento increases complexity in core part to reduce complexity for its extensions part. Well, here advantages comes with some drawbacks.

But I totally agree that framework should not put this type of limitation because it is developer's subject to use suitable pattern.

You are right, "To define is to limit."

youtube said...

I enjoy ultimate flexibility and performance using my own mix of Fusebox and MVC.

I never appreciated database abstraction.

I solved Retail many moons ago with MySQL/PHP, delivering blistering performance on an entry-level virtual host. Complexities exist for Product/Option/OptionValue versus Stock, however the solution is still simple.

I'm also not impressed with the leading open-source Retail/Commerce solutions; They are either so very very slow or not the full solution.

I comment in consideration of rewriting my solution as open-source, using best practice.

Whilst I'm sold on my code style and approach, I'll need to bow to the common coder to achieve acceptance in the open-source community.

fijiaaron said...

I think you're confusing an HTML Front controller with a business object controller.

A HTML request/response cycle does happen to be an object, but it's not the only object in the system (and isn't strictly relevant in most business domains.

You should code your business objects to have rich models, but you should also code them to have controllers.

Your HTML front controller shouldn't communicate directly with your business objects' models, but with your business objects' controllers.

And while it's true that many business objects only need to be fetched, saved, updated, deleted, & created, using terms like 'save' or 'update' is just poor description. If you use active, descriptive terms, instead of passive, vague terms, you get more detail, and also allow for better workflow in your models.

For instance: a subscription is not 'updated' to status 'active', but it is 'activated' -- which may tell you that there are more actions than just flipping a bit in the database. There might be charges applied, email sent, & access granted -- all of which should be actions triggered by your Subscription's controller, not by your front controller, which is probably only interested in getting a view of the subscription to send the HTML response that says, "Thanks Aaron, your subscription to Keeping it Simple is now active through January 2011. Your credit card has been billed $19.95"

Karim said...

Here here! I never understood how anyone could code any real-world application by having 1 model = 1 table but that's what so many self-styled "experts" demonstrate in tutorials.I DO like to see SQL in the model because it is a powerful and expressive programming language in it's own right and NOT simply a way of storing and retrieving data from a DB.

Peter M. Elias said...

It's nice to finally read a well put together explanation outlining why Rails does not adhere to the MVC theory in terms of the way you are encouraged to use it.

While I acknowledge that you have the freedom in Rails to avoid packaging 100% of the database operations into ActiveRecord, the way Rails is presented and utilized certainly promotes this practice.

I just appreciate this post because it's a clear and thoughtful explanation of a concept most people miss amidst all of the chest-beating of the amateur echelons of the Rails community.

Thank you for setting the (Active)Record straight.

Maarten said...
This comment has been removed by the author.
Maarten said...

Such a great article, really! Thanks Bill.

What I still don't understand about the "right" way of MVC programming, is the strict independency of Models with the framework. When you have these models, you are mostly communicating with the database, by using the internal framework DB object. Hereby, the model already isn't independent to the framework anymore. The same thing for ACL kind of things, cache functionalities, validation functions/methods, and all the other stuff which come with the framework. The models need them, but that makes models dependent to the framework.
How would you handle this?

Bill Karwin said...

@Peter M. Elias, thanks for your comment!

@Maarten, you can certainly use framework classes within the code of your Models. You're right that that's unavoidable. But using other classes is a different form of dependency than subclassing.

I'm just recommending against inappropriate IS-A coupling: "Model extends Table".

Read about different forms or "degrees" of coupling here: http://en.wikipedia.org/wiki/Coupling_(computer_programming)

Maarten said...

Wow, didn't expect such a fast reply, haha. Anyway, so that is what you mean with the IS-A and HAS-A relation. That makes things clear!

I just was reading the comments here, and I want to quote you:

"Basically, imagine a scenario where a column name in your database has changed. If you have to change more than one class in your app to accommodate the column name change, you're probably doing it wrong."

I was thinking about this one. What if you have a model 'Car' (which represents a single type of car as an object) and a model 'UserCar' (which represents a single car, owned by a single user). When you make a 'Garage' page, then you will need to retrieve the list of cars. Normally I would have made a relation in Active Record, so this problem was solved. But now, I need to create a SQL query which selects from the 'user_car' table and JOINs the 'car' table. By this way, the columns of both tables will exist in one method called getGarageList(), inside the class UserCar. This is wrong as you say, and I totally agree. But how would you solve this in a good OO way?

Maybe I'm doing it completely wrong anyway, but I think that would be because I am still inside this Active Record mindset I was familiar with...