Mon 24 Oct 2011
ORM is like WYSIWYG……… OMGWTFROFLCOPTER Part 2 of 2
In my last post I described my slow realization that ORM, much like my old HTML editor, is very helpful until you realize it has auto-generated a code mess all over your project. I’ve categorized what I see as the four biggest issues, in order of increasing PITA:
Caching
The ORM that we use at Rally handles our caching strategy. This in and of itself is not really so much of an issue. It is generally pretty seamless and gives us good performance despite some inefficiencies. The problem is that because the caching strategy generally works we generally don’t think about it, and this can really throw us off when the ORM cache does something stupid.
These problems don’t usually manifest themselves until my code makes it to a clustered test environment where the cache must sync across multiple VMs. Not thinking about caching strategy because the ORM is handling it causes us to catch bugs late. These bugs are not typically easy to fix.
Bugs
Throughout my time at Rally there have been multiple occasions in which we have identified bugs in our ORM and had to work around them. One such time I was working on making our Test Case editor stateless. Test Case has a one to many relationship with another domain object called a “Step”. Test Case Steps are order dependent; should this order not be preserved the steps will lose their meaning.
During development time we noticed that our ORM was refusing to return the collection of steps in the correct order. To further complicate the matter this would only occur once the result of an earlier request for the steps had been cached. This turned to be an ORM bug that took us a week to work around. It was difficult to uncover the issue in the first place and our fix was neither pretty nor simple.
Inefficiencies
It is not a matter of if, but a matter of when the ORM begins to hinder the scaling of an application. This is a battle that we regularly fight here at Rally. ORM is great to kick-start a new project but for an application the size, scope and maturity of Rally it really begins to show its limitations. The specific situations in which ORM has caused us performance issues as a result of its choice of queries are too numerous to list in detail here. There is however a common thread that links all of these cases together: the object model.
Java operations that seem completely normal and are “good style” can be converted into an incredibly inefficient set of database queries. We often see this when traversing relationships and/or hierarchies. Depending on what data is in scope this can bring the system to its knees.
Issues of this sort are either caught late or not caught until we identify production performance issues.
No way out
Probably the worst thing about ORM is its pervasiveness. As I wrote earlier an ORM does make sense in the early stages of a project. But then the team continues to build the project around the ORM. Well, after so many years of continually adding to the system…
ORM is everywhere.
There is no escape.
The engineering team at Rally has made significant effort towards converting our ORM specific code to JPA. But we are still married to our ORM. We have so much technology specific code that the mere suggestion of removing it from our system is typically met with a laugh.
Were it not for this last point maybe the other issues with ORM would be more forgivable. But I have seen firsthand the difficulties that having a system you cannot change and cannot remove has on the agility of a project. Anything that hinders your ability to change directions or implementations should be approached with extreme caution. This is especially dangerous because ORM is really most attractive to those whom are not coding with caution, but rather with the need to create as much “stuff” in as little time as possible. The ORM that helped you along early in the project will slowly become your enemy. Expect it.
TL;DR
This isn’t normal……but on ORM it is.
ORM, not even once.

Eric,
Do you feel that the issues you have run into with ORM are reflective of poor tooling, or is there perhaps a different underlying cause rooted in application design?
Learning from Domain Driven Design, we would expect to see rich object graphs in places where we are solving business problems with significant complexity and likelihood of change. Querying a database does not necessarily fit that description.
When working with our domain model, we would expect actions to take a path that reflects fetching the aggregate by it’s root (usually by id), executing an operation, and saving the aggregate back to the database. In this scenario, most of the advanced properties of an ORM are superfluous. We don’t need second level caching or query languages operating over our object graph.
The advanced properties of ORM which appear to be the root cause of most of your pain are a reflection of loading an object graph which really represents a persistence model, for the purpose of query. With that in mind, does it make sense to use an object graph for this purpose? Or do we do it because it makes the ORM work? If we decide to use an object model, should we use the same one we use for executing actions?
Suppose we kept ORM for hydrating the domain models which supplied our application behavior, but used sql directly for querying state. Would this be a better alignment of tool to purpose? How would this change your application design?
Justin,
The tooling could be better in my opinion, but this obviously varies depending on your ORM of choice. That being said my point was not that ORM could not be used to great benefit, but rather that it makes it easy to fall into certain pitfalls. ORM can reinforce the idea that everything can be done in Java, because it works…..until it doesn’t.
The engineering team has gone to great effort to identify the areas in which the object model is the poorest fit for querying. Replacing these sections with sql has netted us significant performance gains. This absolutely is a better alignment of tool to purpose and changes our design by separating the models by which we read and write.
If we had built our system from the ground up with DDD and CQRS(Command and Query Responsibility Segregation), I don’t think we would be feeling any pain from the ORM at all. However that isn’t really a realistic situation. We are however moving in that direction, with an emphasis on smoothing out the outliers in the short term. I think it probably is possible to get to a point where ORM is not painful at all, but until then I’m going to complain.