Why ORM shouldn’t be your best bet
When I started programming, a few years back, ORM was like the life blood of software projects. The environment emphasised the tight coupling between the code base and the ORM layer. It can be said that I was trained not to think of projects without an ORM.
But as I gained experience and deeper knowledge of specific projects, I realised that most of the improvements are ultimately coming to the point where the flow was entering into ORM framework. That was when I asked myself: what if this project had no ORM?
I started thinking about the problems ORM had introduced:
- You can’t optimise your code even if you really need that extra burst of speed; ORM code lives in a land of its own.
- Visibility into what is happening is at a minimum.
- The documentation is usually massive and fragmented making it difficult to search for specifics.
These may sound like small problems but they significantly hurt productivity. Apart from these, I realised that the ORM ecosystem is detached from mainstream web development with its own brand of issues and limitations. ORMs generally bring unnecessary complexity, providing “leaky abstraction” over database interactions. They sometimes have a steep learning curve and developers tend to treat them as a blackboxes.
I have seen developers take various approaches to tackle the ORM issue. Some completely remove ORM frameworks which is often a Herculean task depending on the complexity of the project. Some accept ORM and adapt code in their project; they ready to compromise on the performance and do not care about the added complexity. Many of them choose the golden path where they continue to use the ORM but new or complex queries are excluded. Some of them actually create their own mapping layer specific to the project and according to the need.
So far, I have worked with Hibernate (Java), and Mongoose (ORM framework in Node for MongoDB). When I came to a Node project which was already using Mongoose as an ORM, I had the monumental task of refactoring almost the entire project. At first I thought about removing the ORM framework altogether. But my fellow colleagues would not be satisfied without numbers backing me up. So I benchmarked the query time with and without Mongoose. Here are the results.
They took me by surprise. I had expected a performance gain when not using Mongoose but not to this extent. With this data in hand the choice was clear: ORM was out. A few months later, a colleague asked me whether they should use Sequelize or Pg to access a Postgres database. Realising that Sequelize was an ORM, I gave my vote to Pg, but asked him to benchmark the two. I wanted to verify whether the ORM hate was justified and once the numbers came back, it turns out that it was indeed completely justified.
Guess which library he went ahead with.
A thing to remember here is when we gave up ORMs, be it Mongoose or Sequelize, we were aware of what it was that were giving up. Specifically schema checking, pre-built methods, abstractions etc. were the perks of using an ORM framework. A major concern was the lack of schema checking (when not using ORMs), something that could lead to bad data entering the DB. To get around this we used Joi, which made our task easier while keeping performance intact. For other parts we needed to write a few lines of extra code but it was worth it. Better that than lose tens of milliseconds (sometimes even seconds) on every query.
I am not trying to bash ORMs and they are really good for beginners and small scale projects. But when your project scales to a large number of queries and documents, ORMs can become a bottleneck. Think of them as Vietnam war, you need to decide when to pull out and run, or else major damage is unavoidable.