On the paper, ORMs look great. Over the years, I came to believe that often they cause more harm than good. In this short article, I will try to convince you why. I may refer to Django ORM, but my complaints about ORMs are not Django-specific.
If you think about it, ORM is a database gateway. The database is a persistence layer for the application's state. The state is a value, coupled with time. If we take the time aspect of state aside, all we have is a value.
Values are good. They are constant, easy to compare and send over the wire. In short, they are unambiguous.
What ORM does, it takes something unambiguous and converts it to an object - something which is an order of magnitude more difficult to reason about... and is ambiguous... Objects have state and methods that which are functions that manipulate that state. Do rows in SQL table have methods? No. It's an artificial addition. I think it seriously affects the way we reason about the things we try to model. I noticed that when developers model their domain in ORM, they no longer perceive the User object as a row in the Users table. Instead, they tend to perceive it as an object, which leads us to the second point.
As soon as you have an object as opposed to data, it's just so tempting to bake some business logic into the object. I have wasted hours on end trying to solve bugs only because somebody has put two or three additional lines on .save() method. Sometimes I would be confused with the behaviour of the code for a long time because somebody has scattered business logic between view, model and a serializer. Frequently the "somebody" was me...
I have seen seemingly innocent properties on Django models which resulted in the execution of hundreds of DB queries, which leads us to the third point.
When you write SQL query, you are (or at least you should be) perfectly aware of what is going on. As ORM take this layer away from you, it's easy to forget what is the essence of what you are trying to achieve. That leads to excessive or inefficient queries. I have noticed that over the years, my SQL skills started to deteriorate, and the primary scapegoat for that was ORM.
Often ORM delivers only a fraction of what the database can do. That is particularly true for plugins like PostGIS. In reality, you end up writing raw SQL queries because ORM is not able to satisfy your requirements.
ORM generated queries are not always the best way to go. ORM generated queries may give you a false impression that your database is not fast enough. A well-designed and well-indexed table can be extraordinarily performant. To see this performance, however, you may have to put the ORM to the side.
Sometimes ORM will deliver something that is far from your expectations. I have been there many times. If you want to avoid hours wasted on de-bugging, please always unit test your ORM generated queries.
I don't hate ORMs. They are great for beginners; they set the barrier to entry low. They allow you to get some result quickly. My experience shows, however, that the moment project goes beyond a simple to-do app, problems occur.
These problems are not always the ORM's fault. Instead, they arise from how developers use or abuse them. Using ORM solely to fetch the data is a good starting point. As soon as you try to integrate some business logic into the object, you introduce a coupling that will be a source of pain as your project grows.
Please be aware that performance problems may come from the ORM. Add a few indexes, two or three raw SQL queries, and you may find that the cache that you were so desperate to add is not necessary.