Live data from Hacker News

Problems with JPA/Hibernate

stemlaur.com

131–140 of 195 posts

Re: Problems with JPA/Hibernate

#131
post #51

Earlier quoted context omitted.

Things like Twitter are special. I'm talking more about a generally sensible way of doing things, which one may need to deviate from in special circumstances. Why would you want to sort by ID? Sort by something sensible, like the signup date instead. An autoincrement may stop corresponding to time if for instance at some point a database has an external dataset imported into it. IMO, using an ID for anything other th…

I like IDs I can read out over a call, or recognize when I spot them in a log file. The few times I've used UUIDs for IDs I've later regretted it.

> or recognize when I spot them in a log file

“14632” in a log file could be anything, whereas a UUID is way more explicit and searchable.

Re: Problems with JPA/Hibernate

#132

Everyone hates JPA/Hibernate, but what’s the alternative? I’ve seen this a few times. “You don’t need an ORM, write your own SQL queries directly and create a beautiful domain driven design object model” leads straight into a project only the owner will understand. Homegrown mini-ORM that’s full of pitfalls, inconsistent object model, hacks and TODOs all over the place. If you’re living in the Java ecosystem, the big…

> “You don’t need an ORM, write your own SQL queries directly and create a beautiful domain driven design object model” leads straight into a project only the owner will understand

Could you please elaborate why will this end up happening?

I've been on projects that had ~50 active contributors. All of them used plain SQL queries and used a library (don't remember which) only to map columns to Java types. Everyone understood table structure they were working on and its relationship with other tables. If they introduced a new query they were expected to run 'explain plan' first to understand the consequences and change the query if needed. I won't deny that it all needed a bit of shepherding by the senior engineers but the overhead was negligible. As an upside every developer was always up to date with the schema and precisely knew the performance consequences.

The mess you state is perhaps a byproduct of "get-big-fast" code bases?

Re: Problems with JPA/Hibernate

#133
post #72

In my extensive experience managing teams using JPA ORMs including Hibernate and EclipseLink, you not only get to learn the unavoidable details of your target database’s SQL, but also the complex, non-obvious side effects - especially caching interactions and performance edge cases - of the ORM as well. You also get to learn two distinct but similar query languages (one of which you can’t use anywhere else but Java).…

Man, you and I see eye to eye here. I'm a firm believer in leaky abstractions [1]. I often found with JPA that I would be fighting the framework to get it to produce the SQL that I wanted. I encountered (then) ibatis and it was a breath of fresh air. It took care of much of the tedious column-to-Java mapping and didn't introduce another DSL. As soon as anyone tells you "you don't need to learn X with our framework Y…

> As soon as anyone tells you "you don't need to learn X with our framework Y that sits on top of it", all that means is you have to learn X, Y and the X->Y and Y->X translations and all but the first is proprietary.

Exactly, except it's not just about language Y being proprietary. (I am using term "language" instead of "framework", because they are, in the broad sense, conceptual languages.)

It gives you a hint when the language Y is worth having in addition to language X - only if the language Y makes it significantly easier to model problem in your domain. Therefore, by definition, the language Y has to have some limitations that X doesn't. If Y is as a general language as X is (it can express same problems with similar effort), you end up doing busywork translating between X and Y.

And this problem plagues ORM frameworks of all sorts - it's not clear what is more easily expressed in the language of the ORM, which is not already expressed in the relational algebra (and SQL), and conversely, what are you giving up by using ORM. Although it happens in all sorts of DSLs.

Re: Problems with JPA/Hibernate

#134
There are lots of valid reasons to avoid JPA/Hibernate beyond those listed in the article.

- Hibernate is using blocking IO and threaded database pools. This makes it a problem if you want to use non blocking web frameworks. Like Spring's web flux. You should consider it a legacy technology for this reason alone. There's a good reason why there is no drop in reactive replacement: modern frameworks are trying to not repeat some of the design problems with hibernate (see the article for an overview of those).

- It comes with its own category of hard to diagnose and fix bugs. I've been on more than one project where I had to clean up other people's messy transactional logic. One symptom is people copy pasting @Transactional everywhere as if it was some kind of magical incantation that says "dear db gods please just make this work consistently". A second symbol is flaky tests where that clearly is not working as advertised. A lot of this relates to things like aspect oriented programming and reflection which are what hibernate uses to generate byte code at run time.

- For the same reason, hibernate is also a problem if you want to natively compile your code via e.g. Graal. Reflection and byte code generation are problematic for that. The less you have of that, the better.

- For the same reason, hibernate is also inappropriate if you need fast startup times (which would be why you'd consider native compilation). For example because you are doing server-less designs or edge computing. Having 10-15 seconds of startup overhead is not great. Warming strategies can mitigate this somewhat. But honestly, there's no good reason for Java servers to take much longer to start than it takes the JVM to start (which is still around a second or so). As soon as you get rid of hibernate, Spring Boot startup times become a lot more reasonable. If you then switch to using it's bean DSL (as opposed to scanning packages for annotations), it gets better still. Most of what Spring does at startup is millions (literally) of calls into various reflective methods. That's why it takes so long.

- Object impedance mismatch. Designs that need an ORM layer might not be that optimal. I've been on multiple teams where people got carried away a little too much with e.g. overusing inheritance and coming up with complex solutions to make the database mirror the class hierarchy. The result is dozens of tables and dozens of joins on read. I've seen GET operations that had 1500ms response times because of this. It's stupid. It's stupid even after you fix all the silly joins, missing database indices, etc. You can do good database design with hibernate of course. If you understand how to do that, hibernate is just another tool and not a particularly critical or important one. I've removed it on a few projects to simplify the design.

- These days it is valid to treat databases as document stores. Once you refactor a 15 table database to be the 3 tables that you really needed all along, most of Hibernate is just not needed. My golden rule is that if I don't query on it, I don't need (or want) separate tables or columns for it. Nothing wrong with storing some json blobs. I love using databases because they are fast, transactional, and come with some strong consistency guarantees. Hibernate is not a great fit for document databases. It assumes your domain consists of columns and tables and it wants to do clever things with joins to make that seem like an object tree. The best join is the one you don't need. That's why document stores can be so nice.

If I had to do a green field project, I'd probably go for R2DBC with Spring or maybe one of several other Kotlin reactive database frameworks in combination with ktor, http4k or one of the other emerging Kotlin server frameworks. All my recent projects are using spring web flux and Kotlin co-routines in any case. So, using something non blocking is a hard requirement for me.

But if I had to use hibernate, using Kotlin is the way to do it. It shovels most of the ugliness under the carpet via compiler plugins. So you can use nice immutable data classes and let the kotlin compiler worry about adding default constructors, opening the class and adding getter and setter cruft just so hibernate can do its runtime magic. Also it removes all of the need for hacky things like Lombok and its gazillions of additional annotations. Hibernate can be a lot less painful if you just do it properly. But not using it is better still.

Re: Problems with JPA/Hibernate

#135

Everyone hates JPA/Hibernate, but what’s the alternative? I’ve seen this a few times. “You don’t need an ORM, write your own SQL queries directly and create a beautiful domain driven design object model” leads straight into a project only the owner will understand. Homegrown mini-ORM that’s full of pitfalls, inconsistent object model, hacks and TODOs all over the place. If you’re living in the Java ecosystem, the big…

> “You don’t need an ORM, write your own SQL queries directly and create a beautiful domain driven design object model” leads straight into a project only the owner will understand Could you please elaborate why will this end up happening? I've been on projects that had ~50 active contributors. All of them used plain SQL queries and used a library (don't remember which) only to map columns to Java types. Everyone und…

How do you deal in such a project with similar queries that fetch not all the same data?

E.g. Query A retrieves an Author and a count of all the boks he has written. Query B retrieves an author and the title of the most recent book he has written. I see following options: - make two models, one for each query -> leads to a lot of similar models and code-bloat - make a base query and fetch additional data with an additional query -> leads to a lot of small queries that would sometimes be more performant as a single query

Re: Problems with JPA/Hibernate

#136

I disagree with this bit: A User can be considered unique in one context by its email address, or by its social security number Personally, I'm a fan of giving everything a random UUID, because it's more flexible. It's random and impossible to guess, it scales well because there's no central bottleneck like with an autoincrement, and it's future proof and flexible. What happens when the user changes the email address…

If you don't use natural keys, how do you know if you have duplicate records in your database? How do you UPSERT? A UUID won't help you here (unless created as a hash of natural data).

> Then you may end up having to restructure the entire database, which will be a very annoying thing to do.

Well, you might call it annoying, I may call it a good upfront design requirement. Yes, you have sometimes spend time on stuff that doesn't immediately pay off, but it will pay in the longer run.

If you have a problem with your natural keys, this is mostly due to missing or misunderstanding your requirements, or an incomplete domain design. You can of course just sweep stuff under the rug, and pretend it's not there, but it's not a maintainable strategy.

(Unless you are a consultant of course, with a fixed term assignment on a project - in which case it is an excellent strategy for yourself...)

Re: Problems with JPA/Hibernate

#137

I disagree with this bit: A User can be considered unique in one context by its email address, or by its social security number Personally, I'm a fan of giving everything a random UUID, because it's more flexible. It's random and impossible to guess, it scales well because there's no central bottleneck like with an autoincrement, and it's future proof and flexible. What happens when the user changes the email address…

> What if the social security number changes, because it was wrong or because it actually changes? What if the user doesn't have an SSN? What happens if they have one but lawfully refuse to provide it? What happens when you ask for and SSN from a US citizen who is also a European citizen? What happens when your database leaks? In general, relying only on natural keys is a nightmare. Double nightmare if it's PII. Natu…

How do you look for a person, if not based on his/her SSN?

SSN alone is not sufficient, of course. But it _is_ definitely part of the natural key that you use _implicitly_ ANYWAY, whether recognizing it or not.

> Natural keys only work if you are flawlessly omniscient about the domain

I would call that BS. Nobody is "flawlessly omniscient" about anything, not even in mathematics, yet we design and build systems that work.

On the other hand, yes, it is a very good requirement to have someone on the team during database modeling who understands the domain model thoroughly. No UUID columns will save you from that.

Re: Problems with JPA/Hibernate

#138

In my extensive experience managing teams using JPA ORMs including Hibernate and EclipseLink, you not only get to learn the unavoidable details of your target database’s SQL, but also the complex, non-obvious side effects - especially caching interactions and performance edge cases - of the ORM as well. You also get to learn two distinct but similar query languages (one of which you can’t use anywhere else but Java).…

This comment is spot on. JPA/Hibernate is a very big leaky abstraction. That's why I ditched the whole thing and started to use things like jOOQ instead. In the end you must learn SQL to make sense of all of this anyway.

Re: Problems with JPA/Hibernate

#139
post #73
post #8

The underlying problem is one of O-R impedance mismatch. Going full SQL and getting rid of the ORM is a possible answer, but it has tradeoffs and is not a silver bullet. It might mean re-creating from scratch an in-house, bug-ridden ORM, or ditching OOP idioms from your language, or both. The author of TFA seems to be going through one of the stages described in "ORM is the Vietnam of Computer Science", an article th…

I've found jOOQ to provide the right tradeoffs and flexibilities for ORM vs. SQL. First, it can generate object models of tables from the database in development and therefore doesn't rely on any specific migration tool. These model classes can be used in a conventional ORM fashion, but you also have the option to use jOOQ to build SQL queries. You can even fetch the results of arbitrary SQL expressions into a model…

jOOQ is great. It brings a lot:

* auto-complete in your IDE when writing queries in jOOQs Java DSL that maps quite naturally to SQL

* type safety. e.g.: migrate after a schema change, re-generate your jOOQ lib and see in your IDE (red underlines) all the place your queries would break using the new schema

* build queries from parts (e.g.: store/manipulate some where clauses in a local variable) w/o any string manipulation

But is has costs:

* generate the jOOQ library from your schema at build time (or everytime the schema changes): increase build time (a little) and complexity (a db needs to be around during builds)

* very small runtime overhead: queries are build at runtime

* one more thing to learn

To me the benefits outweigh the costs (unlike Hibernate, I much agree with the article) and I consider it similar to LINQ on C# while not being some language built in feature with it's own syntax.

Re: Problems with JPA/Hibernate

#140

Everyone hates JPA/Hibernate, but what’s the alternative? I’ve seen this a few times. “You don’t need an ORM, write your own SQL queries directly and create a beautiful domain driven design object model” leads straight into a project only the owner will understand. Homegrown mini-ORM that’s full of pitfalls, inconsistent object model, hacks and TODOs all over the place. If you’re living in the Java ecosystem, the big…

Both JOOQ and JDBI are superior to JPA in my book.

jOOQ is the most obvious contender. Since I use Java I like type safety, jOOQ gives me that (like Hibernate) without trying to abstract the fact that I make queries to a db (which Hibernate does).
Post reply on HN