Saturday, August 21, 2010

Symfony and MVC - a little rant about

So symfony is a MVC based framework. True. It provides all you need to build MVC applications. True. Symfony users build MVC applications. Unfortunately - usually not true. And I think it's mostly symfony's team fault. I'll explain it later in this post.

MVC stands for Model-View-Controller. Those are three layers that code consists of. But there is one more layer, which is not really a part of MVC because it isn't required. It's called DAL - Data Access Layer. We can find all those layers in symfony. The problem is people mistake the Model with DAL. And that's evil.

In symfony DAL layer is created by Doctrine/Propel. But of course it doesn't have to be an ORM. Basically DAL provides the tools to access needed data from our data source - make it database or txt file. Type of the source doesn't matter - our application should work even if we switched to another data source. What's more, the Model alone should work too! The thing is DAL classes should contain only methods related to accessing data, nothing more nothing less. And developers usually break that rule.

This situation is mostly symfony's team "fault". Why? Because they called classes generated by ORM a "models" and put them into the /model directory while not providing auto-generated REAL model classes (what i don't think would be possible but that's not the case). So new user opens the /model directory and see all those "model" classes and thinks: "cool, I don't have to create them" and starts to put business logic into the classes which are not a real Model, just a DAL. Don't get me wrong, I did the same thing in my first projects.

Usually it isn't so bad, especially if it isn't a big project. But lets look what are the consequences:
- breaking the logic of MVC
- using propel/doctrine queries in actions
- unability to upgrade/switch to other DAL/ORM
- limiting the business instances to database instances

The last point requires an explaination. It doesn't seem so bad while it is quite a big problem which can do a lot of mess in your code. Lets say we have a users database. In that database we have two tables:
- user -> basic user info
- user_detail -> user info which can change in time

ORM creates two separate classes for those tables. So we have the User and UserDetail "models". Is it ok? Of cours it is NOT! On the business logic side there should be only one model: User. System doesn't care, how the user data is stored - if it is contained in one table, two or three. Why should it?

So on data side, User instance consists of two tables. In the system I work on it consists of 5 tables which contain data related excusively to users. But system needs to access only one model - User. It doesn't matter to which table we have to make a call to check user permissions. In properly built system it should be a User model function - lets call it hasPermission($v) returning a bool value. Clean and simple.

Final conclusion: using ORM classes as models makes the business logic more scattered and dependent on the given type of data source making it less scalable and flexible.

More about this subject:
Symfony and mvc - follow up
Separating model from Data Access Layer

9 comments:

  1. It's good that you complain about this, but you should also give an example of how to do it "properly"

    ReplyDelete
  2. Ok, will try to provide an example in the next post.

    ReplyDelete
  3. Yes, nice and interresting "rant".

    I'm looking forward for the post where you give your design proposition :).

    ReplyDelete
  4. Always thought that User is the model layer while UserTable is the DAL. And that's true that it limits you to the orm, but the point of ORMs isn't the easy switch between different orms, but between different RDBMS without rewriting your logic.
    Unless you want to add another layer on top of orm which will translate your abstract queries to orm queries of your current choice, which will in turn translate them to given rdbms query.

    Anyway, I'll be waiting for your example to better understand, what you mean.

    ReplyDelete
  5. That error depends on the user, not on the framework. Just use Sf correctly. Even it the user makes these kind of errors, the pros are many more than the cons.

    ReplyDelete
  6. @John: You're right, but I've never said it was a Sf error. I just wanted to point out, that naming orm generated classes the "models" makes a wrong suggestion to new Sf developers. Looking into Sf plugins you will see that many of them use db queries and table references in actions. And I think it is wrong.

    @fizyk: You misunderstood me. The easy switch between ORMs is not the point of ORM but the point of separating the Model and ORM! If you do otherwise you're basically forced to use the ORM you initially started the project with. Lately it was popular to switch from propel to doctrine. Do you think it is easy when you have propel queries scattered all over your code? I hope you see the point.

    ReplyDelete
  7. Now I see what you meant dev. Haven't seen yet in action how Propel get's it's "model" and "DAL" classes generated in symfony. To be true, I started to work with doctrine just when I started to work with symfony (I got to symfony through doctrine, as I was looking for some orm for my code).

    I suppose you'll have more insight into this, so I'll be waiting for your next post :)

    ReplyDelete
  8. STOP MISUSING TOOLS AND BLAMING THEIR DEVELOPERS.

    ReplyDelete
  9. If I was misusing the framework I wouldn't have posted this rant. The framework is misused by others and even the Symfony documentation in examples shows that your model's place is in ORM classes. See here: http://www.symfony-project.org/jobeet/1_4/Doctrine/en/06 in "Refactoring" section. How the hell one can learn proper using of the framework if its creators show the wrong way?

    ReplyDelete