Just use this library, dude!
I’ll be honest, I was inspired to write this post due the absolute pain Hibernate is causing at work. But more on that later.
Abstractions
They’re absolutely everywhere. Every single thing, item, object, you see around you is an abstraction of something else. The car you drive is an abstraction of internal combustion power-trains, the house or apartment you live in is an abstraction of plumbing and electrical work, interior finish and design. The food you eat is (usually) an abstraction of farming, animal husbandry, transport logistics. By the way, transport logistics is an abstraction of route planning, cargo handling, and, funnily enough, cars. The very computer you’re reading this article on is an abstraction of electrical manufacturing, radio communications, transport logistics (pattern here). And I only say “computer” because phones are computers too, so unless you’ve either printed this post (why you wasting a tree, man?), or reading it on stone tablets, you’re on a computer.
Okay, yes, I did say “every single thing” above, but it’s not actually that simple. Sand could be considered a base element for the purposes of this article. Thinking sand, however, is already an abstraction. A mistake, but an abstraction nonetheless.
The abstractions I actually wanted to talk about
The abstractions I actually wanted to talk about exist in the magical realm of information technology. In a previous post I said I despised most abstractions. Not much has changed since, I still do, but I mean that in the context of software development. I very much like to choose what I tools I use for work and how I use them. This also means that I am free to choose to do the work myself, rather than let a library do it. An opportunity I often employ to retain more control over the behavior of my application: what it does, but more importantly, how and when it does.
Object-relational mapping
I mentioned Hibernate. Hibernate usually comes to mind when talking about Java ORMs (Object-relational mapping). An ORM is used to convert result sets returned by a database query into an object for easy use in the rest of your application. It abstracts away the usual boilerplate of
|
|
and turns it into
|
|
But before I get too carried away dissecting Hibernate, let it be known that I’m not all against abstractions. After all, most, if not all, of the work I do lives in a computer. The construction and 99% of operations of which have been abstracted away by Lenovo and the Manjaro folk.
Example!
Warning: This is my opinion based on a situation I have been in. I don’t care if you disagree with it.
Essentially:
Hibernate likes to do more than an ORM should do. Yes, they do say “More than an ORM” on their website, but that doesn’t mean I like it and the way it was implemented in The Project in question. Basically, Hibernate makes it very incredibly easy to do simple DB stuffs. All you have to do is chuck an annotation or two onto your Java object and you’re golden, Hibernate does everything else for you so you, the dev, can focus on writing code instead of doing your DB correctly.
Most of the performance options are hidden for you, because Hibernate has to build an abstraction layer between you and the many different database engines it wants to support, and it has to be as granular as possible while remaining as compatible as possible. As one might guess, this hides most of the engine specific stuff that enable us to optimize our communications with our DB.
And, honestly, for like 95% of the projects using Hibernate, this is absolutely fine, as those 95% never hit the traffic necessary to expose such bottlenecks.
However. Those 5% who do hit the required traffic… hoo boy. You see, The Project is a 20-year-old, 500k sloc (generated using David A. Wheeler’s “SLOCCount”) behemoth that every second converts 2.5k network requests into 85k database requests. This means that squeezing every drop of performance out of our application is crucial. I won’t get into how that 34x amplification has come to be, but now that there’s pressure from within the org to have The Project handle even more load, the sore spots become even sorer.
Two distinct issues
With such strain on the application two distinct performance issues become apparent.
Query optimization
In my experience the queries Hibernate generates for you are shit. This is possibly not even Hibernate’s own fault,
but more-so the fault of the simplicity of DB actions it enables. It’s incredibly easy to smack @Entity
onto an object
that already contains a list of entities and somehow end up with a many-to-many-to-many relationship. Or get from
car
to person
in only five hops. Yes, “wtf?” indeed. If you even a wee bit care about your DB and its
query planner, then you’ll not force it to eat through a query that full joins ten of your 100M row 50 col tables together,
testing the limits of column and churning trough TBs of
memory.
Also, what are those “indices” you speak of?
Transaction control
Another topic that is again and again rubbing me the wrong way is control of transactions. Or more specifically, control
over transaction boundaries. Its way too easy to give a method @Transactional
and let Hibernate do its thing.
The reason I’m not happy with it is that the annotation propagates down to the methods called within that annotated method, and in the 500k sloc behemoth, those methods go deep, bringing with them another easy pitfall.
Let’s say you want to extract some functionality into a separate (micro)service. You replace the local function call with a network call to the other service, easily forgetting that Hibernate is still holding a transaction open in the background. This means that you’ve tied your transaction to a network call which, in the case of The Project, is often non-essential to the logic of the transaction. Also, should the network call fail, there’s a good chance that the transaction gets rolled back.
Conclusion
To conclude: magic black boxes are evil. Necessary ones, but still evil. I personally cannot imagine a world where in order to look at goofy cat pictures on the internet I’d have to first build billions of transistors and then assemble them into a cat-picture-looking-capable computer. I’d rather have Intel or AMD do that for me. Same thing for the OS. Being a Linux user, I’ve peeked into the sorcery that takes place within and again, I’d rather leave that to the experts.
But the things I can and know how to do well, I want to do well.
I have by now said/written/thought about the word “abstractions” so much that it has lost meaning. And the post still did turn into a rant about Hibernate and The Project.
Oh well…