A recent “Weekly Feature” on DZone decries the use of Object-Relational Mapping (ORM) calling it “offensive” and an “anti-pattern”. The author then purports to show a better approach, which is, in my opinion, worse. Why? Because they essentially kept ORM, just in a different (and worse) form.
The author’s assertion is that ORM is bad because of a number of problems. First, it makes the data objects “dumb and passive data bags”. Second, it requires that SQL or HQL is “exposed to the entire application”. They also go on about how it is difficult to test.
To support these assertions, the author links to other blog posts, few of which actually support his main argument about ORM being bad. Sure, ORM isn’t viewed very highly. It does come with compromises, and I expect someday someone will come up with a “better way”. All I know is that I don’t have one, and the solution proposed by the article’s author isn’t an improvement, it is worse. It is, in some ways, a step backwards.
An ORM By A Different Name
First, the “objects that speak SQL” approach was what we did before 3rd-party ORMs came along. SQL got scattered about through the data objects. They knew how to persist and retrieve themselves. Of course, it meant that an object needed to know every way there was to retrieve itself. And then, when you changed to some other persistence technology, you had to go through every object and figure out how to deal with the new approach. But if you wanted to keep the existing implementation (because, for either technical or business reasons, you needed both) then the objects got more and more complicated.
This is still ORM, just not ORM in a single, central, abstract implementation. If you are persisting objects to a relational database, you have to map the columns to data elements in the object. Giving it a different name doesn’t change the fact that it is still ORM. I can paint black spots on a horse. That doesn’t make it a leopard.
ORM Means Passive/Active?
But what about their assertion about the data objects being passive? Sorry, but ORM has little or nothing to do with that. A data object still has a defined contract for how the data is used and manipulated, and can provide the appropriate features to make the object smart and/or active if necessary. Hibernate, as an example, doesn’t require that your objects do nothing but be a dumb container for data. ORM’s provide the tools to map the data to and from database columns. It doesn’t impose other restrictions like “objects can’t be active”.
Moving the mapping from an external component into the object doesn’t make it “smart” or “active”. It just makes it more complicated. Now a data object can’t just focus on being really good at dealing with their data, doing things like ensuring consistency and correctness, or enforcing rules around security and access. That object now has to also know about persistence, and possibly persistence with multiple different technologies and approaches. The data object can’t do “one thing well”. It now has to do a lot of things well.
The Object Knows Too Much
This “objecting speaking SQL” approach ultimately means that an object knows too much. It makes them more complicated, and it doesn’t make database migration any easier (a supposed trait from the author’s solution). An object needs to know how to persist itself, as well as which service it needs to persist itself each time it is used.
Consider a data object implementation that is used in a couple different parts of the system. In one part, the system uses MySQL. Another part of the system, re-using the object for a slightly different purpose, uses MongoDB (okay, not strictly ORM, but you can still use something like Hibernate to abstract away the persistence bits). If I use Hibernate, I can have the one system instance start up configured to use MySQL. The other instance can fire up and use MongoDB. The rules are in the Hibernate configuration files. The data objects don’t know and don’t care which is being used at the time.
A Simpler Abstraction
Again, using an ORM may not be perfect, but it is generally better than “objects know how to persist themselves” for a couple of reasons. First, it means you can centralize the mapping, and that other parts of the system can choose what type of persistence to use. It means adding a new data store, using different technology, will mean focusing on fewer places to deal with the mapping. If the database itself changes, then you are changing the mapping rules, and not the objects themselves.
Second, it keeps the objects simpler because they can focus on whatever their particular task or role is. They aren’t also burdened with figuring out the solution (or 2 or 3 or 8 different solutions) for being saved and retrieved.
Ideally, an object does “one thing well” and nothing beyond that. An ORM makes that possible. Scattering different implementations in each and every object does not.