Why you should not not use ORM

Yesterday I read a blog post by Kenneth Downs entitled “Why I Do Not Use ORM” on his The Database Programmer blog. It wasn’t the first blog post with gripes about Object Relational Mapping, and it certainly won’t be the last. For me, this particular article highlighted a few misconceptions about why and how ORM should be used, and I thought I might chime in with my own perspective.

ORM is not a way to avoid SQL
The first thing that stood out for me was this quote:

“The language SQL is the most widely supported, implemented, and used way to connect to databases. But since most of us have long lists of complaints about the language, we end up writing abstraction layers that make it easier for us to avoid coding SQL directly.”

To his credit, the author wasn’t actually addressing ORM in this paragraph. However, anyone writing business logic which interacts with a database, who is unable to write some basic SQL, is like a bull in a china shop; nothing good will come of it regardless of the tools and abstraction layers employed.

The Simple Example
The next example in the post shows how one would write a row to a database in only four lines of PHP code – it looks something like this (I removed the comments):

$row = getPostStartingWith("inp_");
$table_id = myGetPostVarFunction('table_id');
if (!SQLX_Insert($table_id,$row)) {
 myFrameworkErrorReporting();
}

I don’t know PHP, but I think the code is reading every field in a posted form that starts with inp_, generates an insert statement straight from the ID’s on the form fields, and writes an insert statement with the results.

Perhaps it’s unfair to criticize this code because “it’s just a simple example,” but if this code is being held up as an example of how short and simple non-ORM code can be, one does have to wonder

  • When the database schema changes, does the HTML need to be updated so that the form fields match the database schema?
  • Where are the transactions? What if I need to insert into several tables and roll back the transaction if one fails?
  • Does the handy SQLX_insert method prevent SQL injection attacks?

He goes on to say that this task is made even easier by using a data dictionary to generate the SQL. After reading the “Using a Data Dictionary” article, one has to wonder whether or not the author realizes that it is a very crude form of ORM.

What about Business Logic?
Kenneth Downs tries to head-off any arguments about business logic before they come up, knowing that ORM evangelists will argue that the domain objects can encapsulate essential business logic for the application. His response?

“The SQLX_Insert() routine can call out to functions (fast) or objects (much slower) that massage data before and after the insert operation. I will be demonstrating some of these techniques in future essays, but of course the best permforming and safest method is to use triggers.”

For me, this sounds alarm bells. Triggers slow down transactions. Triggers are in your database, which is often your system’s biggest bottleneck. Triggers silently do things behind your back without telling you. Triggers change databases from vast, efficient places to store relational data, into a lumbering behemoth interpreting procedural code inside big iron.

Conversely, business logic that can be easily distributed across many smaller web servers scales horizontally. The domain layer is a fantastic place to embed simple data massaging – sadly, I often see a pile of persistent entities with getters and setters that don’t do anything.

Counter Example: The Disaster Scenario
Lastly, Ken (can I call him that? What is the ettiquite for this sort of thing, anyway?) shows an example of a piece of code that is likely to cause hundreds of unneeded reads to the database in an untuned ORM-based system. I don’t dispute this; in fact, I posted about an almost identical nightmare scenario myself a while ago.

For this, I go back to my “bull in a china shop” analogy. Programmers can write horrible code in any language, with any tool. Layers of abstraction are a double-edged sword, because you need to understand what they are doing for you. But it’s not the tool’s fault; it’s the person misusing it.

Computer Science’s Vietnam
In 2004, Ted Neward famously called ORM Computer Science’s Vietnam. Encouraged by early successes, we got sucked into the quagmire. There are plenty of reasons to be frustrated with ORM, but I’m not sure I agree with Ken’s. I try to hit the 80/20 rule with ORM, and use it where it makes sense. When I get into a convoluted transaction or need to do a large batch of operations, I’m not afraid to dive into SQL and do the work in a stored procedure. I think it’s a good mix. How about you?

Photo Credit: Ryan Dickey

12 Responses to “Why you should not not use ORM”

  1. Donald J Organ IV Says:

    The PHP code that Ken posts in his blog is normal code that contains functions that are in the framework he has created http://www.andromeda-project.org. SO you cant get the full effect of the PHP side of things from some of his code.

  2. david Says:

    Honestly? I don’t like OR Mappers, but I can totally understand why people use them! In fact I’m using one myself at the moment, on my current project.

    I guess the problem is to grasp what’s going under the covers of an OR Mapper. If you use the standard configuration for some these frameworks, you’ll probably get horrible performance. All sorts of unnecessary SQL statements and weird lazy loading issues.

  3. Mike Desjardins Says:

    @Donald – yeah, I kinda suspected that that insert function did a little more than a plan old insert statement under the covers, much as the “save” method in an ORM framework does a lot more than a SQL insert statement.

    @David – There’s lots to hate about ORM frameworks. It’s a tough nut to crack, and I’m not convinced that it’s been “solved” by any of the tools I’ve used. At one of my previous jobs, we created a framework which basically mapped Java POJOs to stored procedure parameters, and did all of the SQL in stored procedures. It actually worked quite well… I’ve contemplated building another framework like that for a side-project and open-sourcing it. I think iBATIS might also handle stored-procedure situations quite similarly (in the Java space), but I’ve never tried it.

  4. kasper Says:

    When debugging ORM code, especially during tests, I’ve appreciated actually being able to see the data in the database as it actually is for the current transaction (before it is comitted/rolled back). I just released a tool to assist you with such a task. It’s called Data Storm:

    http://datastorm.sourceforge.net/motivation.html

  5. Mike Desjardins Says:

    @kasper – that looks like a very cool tool! I’ll have to try that out!

  6. Anonymous Says:

    We used to use Hibernate, and now we use EJB3 and Hibernate (session = entityManager.getDelegate()). It’s great. You couldn’t match the performance any other way, and development speed is also tremendously faster. When using it with Seam, it keeps a cache of objects relative to the conversation context, which has a very high cache hit rate. It also lets me express things like navigating across objects in Expression Language, so a front-end designer can show whatever he wants without asking the developer “can you please create this join query…”

  7. gfrison Says:

    I agree with you when you need speed in critical jdbc tasks, in such a performance requirements write you low level sql code. ORM introduces overhead but this is the price of abstraction, but if you try to write your own ORM framework you would realize that existing ORMs save a lot of time and make your system more reliable. Don’t reinvent the wheel.

  8. KenDowns Says:

    Mike, I am flattered that my blog post would inspire a reply. I have posted an addendum to the OP that answers most of the compelling challenges offered by your post and by comments on the blog. Rather than rehash it here I will simply refer folks to the OP, which is linked to up in your blog.

  9. Mike Desjardins Says:

    @KenDowns – Cool! And I’m flattered you posted a response!

    I actually think we probably agree more than we disagree. As I think I said in an earlier comment response, one of the largest-scale applications I’ve worked on handled tens of thousands of transactions per day for a wireless telecommunications client, and it was implemented using almost no ORM. Instead, we used a stored procedure framework to do the “mapping” (if you could even call it that) and it was *very* effective.

    Your data dictionary approach is very similar to ORM frameworks I’ve used, even if it isn’t mapping first-order objects to entities persisted in a database, in that it has a level of indirection in the form of “mapping” client-side transient variables to columns in a table. It’s sort of an ORM without the O, and it’s actually pretty clever. In your particular example, I’m a little leery of the tight coupling between the View/UI, and the data Model (insofar as the HTML fields are directly coupled to your model map), but perhaps that hasn’t been a problem for you in practice because you still have one level of indirection there.

    I think my biggest concern about the approach outlined in your blog was the advocacy of triggers – I’ve been bitten by trigger overuse and tend to use them as an enforcer-of-last-resort… I’ve gotten a lot of mileage out of distributing that work across multiple small servers before even hitting the database. YMMV. I’m sure it depends a lot on other factors like what RDBMS you’re using, how complex your data model is, etc.

    Thanks again for commenting!

  10. James E. Ervin, IV Says:

    I think the point about ORM or to not ORM is, let your hands tell you. How?

    If you are writing the same kind of error prone code over and over again (like having to check all try(s) have finally(s) for instance) is the biggest sign. Time to think of using something. Save your hands, check out like Groovy SQL first or an ORM.

    Writing the same bland queries again and again? Are you really taking advantage of PL/SQL in a way an ORM couldn’t? If you answer yes and no, use the ORM, save your hands. They will thank you.

  11. Anonymous Says:

    Hmm. To sum up:

    It is not the gun that murders, but who wields it. It is not who wields the gun who commits murder, but who wields it unwisely.

    – A grasshopper

    Everything wants to be hyped, to get over the adoption factor. When wielded appropriately and under the right conditions, with the intelligent, knowledgeable practictioners, ORM (which I have done poorly) is of course with merit.

    Hasty implementations, with unwise and illiterate implementation, is the result of poor understanding. ORM doesn’t cause this, just as AJAX doesn’t cause the web to “break”.

    I’ll always remember the little league team that had all the studs on it, the kids who were natural athletes. They spent all their time practicing fancy throw-outs and pick-off moves. It was “expected” that they would always out-perform, so this expectation imposed an unreasonable work ethic.

    The team that won the championship, though, was a team that worked, daily, on fundamentals. Throw, catch, run out the ball. Everyone bunts, everyone gets grounders, everyone carries the gear to the truck.

    In the end, a good programmer knows the fundamentals of SQL as well as the fundamentals of programming. They’re paid for the results, not the fancy.

    If a programmer can’t construct a SQL statement, and have not been doing that at least for a good while, chances are the results will not be as useful as that programmer thought.

    Not the SQL fancy (triggers, stored procedures, data normalization, etc…) mind you, but the fundamentals: Create, insert, update, delete.

    Programmers are paid to get it right, but the reality also says they’re paid to get it back right when it goes (sometimes spectacularly) wrong.

    That always means fundamentals. Always.

  12. Mike Desjardins Says:

    @Anonymous -

    Very well said. Too bad you stayed anonymous so you can’t get the proper credit you deserve. :)

    ORM is just a tool that can be used wisely and unwisely. I try to tell people that there’s no shame in just doing straight-up JDBC calls if all you’re doing is stored procedure calls or simple SQL statement. But lots of people can’t resist using the framework du jour just because it’s popular at the time.


© 2010 Mike Desjardins. All Rights Reserved.