> Every non-trivial long-lived application will require tweaks to individual queries at the string level. The proper way to build a data layer is one query at a time, as a string, with string interpolation. The closer you are to raw JDBC the better.
This is bullshit, IME. I've been doing this for over 10 years, and there's not a single one of those "requires a tweak at the string level" queries that couldn't be handled better by actually spending 5 minutes reading the Hibernate documentation and doing what it says to do in that situation. But the same SQL fanboys who believe every developer ought to memorize tri-state truth tables and COBOL-style function names can somehow never be bothered to do that.
> there's not a single one of those "requires a tweak at the string level" queries that couldn't be handled better by actually spending 5 minutes reading the Hibernate documentation
So instead of learning and using widely applicable SQL skills you learn and use Hibernate specific skills? And that’s supposed to be a positive?
Once we're talking about this kind of detailed tuning those "widely applicable SQL skills" are usually tied to a single database vendor.
Using any tool requires a certain investment in learning the tool. If you don't want to learn an immensely popular and widely used library that's in pretty high demand career-wise, well, that's your lookout, but it's a crazy double standard to claim that Hibernate sucks compared to handwritten SQL when you spent weeks tuning your SQL but wouldn't spend hours tuning your Hibernate.
> If you don't want to learn an immensely popular and widely used library that's in pretty high demand career-wise, well, that's your lookout
You’re making the argument against yourself. Even including different dialects an in depth knowledge of SQL is far more valuable than knowledge of Hibernate.
Over a decade ago now I used NHibernate, the .NET version of Hibernate on a project. Since that project I’ve written code in JavaScript (Node), Python, Rust, played around with a little Go and Kotlin.
In all those years the only database engine I’ve used seriously is Postgres. Knowledge of Postgres has been invaluable throughout my career. I can’t remember anything about NHibernate. It’s not even specific to NHibernate either, I had to use ORMs in other situations (like Sequelize on Node) and I haven’t retained any of that either.
> Over a decade ago now I used NHibernate, the .NET version of Hibernate on a project. Since that project I’ve written code in JavaScript (Node), Python, Rust, played around with a little Go and Kotlin.
> In all those years the only database engine I’ve used seriously is Postgres.
Interesting, I would think changing database happens a lot more than changing language for most developers. Over the last decade I've worked on systems that used MySQL, Postgres, Oracle, H2, and Sybase, but they've all been on the JVM and almost all used Hibernate (one used EclipseLink but a lot of the knowledge transferred over - even if something isn't called exactly the same thing, they have the same kind of capability structured in a similar way - much smaller than the differences between databases IME. Indeed even having to use e.g. Django ORM occasionally a lot of stuff transferred over). Spending time learning to use an ORM well was absolutely a good investment, far more useful than a bunch of SQL details would've been.
Like, if a company has a Ruby/MySQL stack, they're going to hire someone whose experience was Ruby/Postgres over someone whose experience was Python/MySQL. So if you're a Ruby dev then you open more doors for yourself by learning Ruby's standard ORM in depth than you do by learning a specific database in depth.
> I can’t remember anything about NHibernate. It’s not even specific to NHibernate either, I had to use ORMs in other situations (like Sequelize on Node) and I haven’t retained any of that either.
I suspect that reflects more on what you paid attention to and were interested in using rather than anything fundamental about how easy or hard ORMs are to learn.
> a lot of the knowledge transferred over - even if something isn't called exactly the same thing, they have the same kind of capability structured in a similar way
At a certain point this is getting beyond parody. That statement sounds exactly like it’s discussing SQL!
> I suspect that reflects more on what you paid attention to and were interested in using rather than anything fundamental about how easy or hard ORMs are to learn.
Nor am I saying anything about anything being easy or difficult to learn. I’m talking about what’s transferable. In my experience ORMs are far less transferrable than SQL knowledge.
I think it’s safe to say we’re going to have to agree to disagree here.
> At a certain point this is getting beyond parody. That statement sounds exactly like it’s discussing SQL!
Nope. The underlying relational model is great. Knowing what tables are like, how and why indexes work (and when they don't), transaction isolation levels, all that stuff is extremely useful transferrable knowledge (and will help you out whether you're using an ORM or not). Knowing the three or four different bizarre pseudo-COBOL variants that different database vendors use to express something like "pull rows recursively from this table" or "format this string using these two numbers and this date" is stamp collecting at best.
Disagree. All too often, JPA/Hibernate dumbs the relational model down into record-at-a-time processing with navigational queries reminiscent of pre-relational network databases and counting and joins implemented by unnecessary fetching and client-side processing rather than aggregate queries and joins. Furthermore, it brings fuzzy locking semantics/locking as a side effect of lazy/eager fetching and artifacts such as a pattern of unnecessary "id" columns due to lack of support or asymmetrical and idiosyncratic handling of compound keys, also extra magic for "many-to-many connectives" (the wording alone is non-relational), lack of attention for decimal arithmetic/overflow with money values, idiosyncratic date/time conversions and mappings of enums into ordinals, etc. etc.
Not my experience at all. The support for aggregate queries and joins is very good if you actually use it; likewise the support for decimals, date/time and enums (though I say that from a position of thinking a lot of database date/time handling is wrong, so take that as you will). I'm not a fan of lazy fetching but if it's something you want then the locking semantics are a natural consequence of that. Many-to-many connectives are indeed non-relational, but again if they're something you want (and again I mostly avoid them) then they work the way that they have to work.
Changing databases on an existing application doesn't happen, but I've worked across teams within a single company for ~8 years and in that time I've used:
1. SQL Server
2. MySQL
3. Neo4j (very briefly)
4. PostgreSQL
5. DynamoDB
Each of those was for a different set of applications, and none of those applications changed database, but point being sometimes an engineer will be made to use a variety of databases in their career, even sometimes within the same company (although you could also chalk this up to a particularly laissez-faire style of tech direction).
In our case company was strictly "Oracle-only", but one team did a quick implementation in startup-style of Rails and used mysql. No one forced them to migrate to oracle, company just hired DBAs that now mysql.
Changing the database for an existing system happens very rarely, but changing the ORM or language is even rarer. So learning the ORM well is just as rewarding as learning the database well, IME - and more so once you take into account changing jobs, since you're more likely to take another job using the same ORM but a different database than vice versa.
I've used many different databases. They're all very similar I've not had trouble adjusting. Every ORM I've used has required more time to learn. I'm not against ORMs but I've yet to see a situation where one was a net benefit. Aspects of ORMs are great but going all in tends to add significant complexity.
I'd argue that means it's doing its job quite successfully! The point of using an ORM is so you don't have to also be a DBA on top of writing code. If I have to remember a bunch of implementation details and program weirdly because of the leaky abstraction that is an ORM, then the ORM has failed. If I grab all the rows from the database and then WHERE clause them in my code, instead of querying the database with a WHERE clause, and then wonder when my program's slow, that's on me. But if the ORM makes it straight forwards not to, so I don't need to grok the database, so I can focus on the other problems, then I'd consider it a success.
what's there to remember? NHibernate you basically use Linq, so if you remember Linq you remember NHbernate. The only extra bits are the setup and mappers, which are sort of trivial. The pain points come around because NHhibernate decides to lazy load everything or ends up doing crazy joins. But overall I found NHibernate not too bad, it certainly was fast doing a lot of basic CRUD type stuff.
However, these days I use Dapper.NET and SQL. Dapper gives a nice mapper for parameterized queries and maps results to types. I think it's a nice middle ground.
That's the same debate as whether you to hand craft xml files or have a library do it for you. You'd better know in details how the format works, but going through a library will help cover most common issues you wouldn't want to deal with by hand.
Except that an XML file that passes the spec and contains the required data is as good as it will ever get. The world's foremost XML-typing genius is not going to improve on that.
On the other hand, with hibernate, you get mediocre, inefficient SQL, and could produce much better results by focusing your energies on learning the database instead of learning hibernate.
On hibernate: there is a common approach of having pure ORM handling of 99% of the queries and use a lower level query building tool for the 1% that needs it.
The query to fetch your user profile should be mediocre, properly cached, and fully defineable in the ORM. And most of your queries should be straight and obvious joins between tables with no crazy pants handling.
Something in your basic data structure that throws off an ORM would also probably throws off your new employees looking at the code for the first time, and could be fixed for readability and maintainance.
A thought exercice: XML entities can be self referencing, have you ever though of how you validate a document that has recursive entity definitions ?
That's one quirk that comes first to mind, but the XML format definition is probably at leat a few hundred pages and I'm hopeful there's enough in there to fuel anyone's worst nightmares.
It's kinda interesting in itself that XML is seen as a plain and boring data format. I don't wish on anyone to be the receiving end of an XML typing genius' documents.
The XML specification does contain a schema: the DTD. This is why it is 37 pages; without the DTD part it would be at most a half of that.
Other schemas are not merely popular, they are more powerful. In DTD the type of the element depends only on its own name. In XSD the type depends potentially on the context: the type of 'xxx' in 'aaa/xxx' and 'bbb/xxx' may be different. And in Relax NG we can define different types, for example, for the first 'xxx' and for the subsequent 'xxx's. These extensions make the validation somewhat more elaborate, but still linear, as it we remain within the complexity of a regular expression. These are formal validators; then there is Schematron which seems to be more like a business-rule kind of a validator that also has its uses.
I think I was seeing all the XSLT and XQuery and all the kitchen sink directly bound to XML, but those are just meta tools that don't bear directly on the language.
No. I see that as a reflection of the reality of the database; if your database contains rows that violate your domain invariants, what would you expect to happen?
It may not be a bad idea to fail fast by ORM calling the constructor (same way as Jackson does it when parsing JSON).
Broken invariants may propagate and cross system boundaries making things much worse (I have seen a case, when $200M transaction was rolled back in 19 systems because data was not properly validated at entry - it was a crazy day for everyone in production support).
That comparison would only really make sense if people were advocating writing SQLite storage files by hand.
In this situation SQL is the library. It’s the interface that allows you to query and write the underlying data while knowing nothing about the underlying format. An ORM is just a library sitting on top of the library you already have. There’s just as much to learn, it’s just a higher level of abstraction (until it isn’t because you need something low level).
I think that "requires a tweak at the string level" is not precisely true/correct, but the overall idea is true. For any non-trivial, long-lived, application you will at least have to inspect the ORM-generated SQL string for some query and you'll have to either adjust your ORM calls (e.g., add even more magical Hibernate annotations) or use an "escape hatch" to write the query by hand.
The larger point isn't really that you can't accomplish everything with the ORM, IMO, but rather that the conventional ORM value proposition of "you don't have to write/understand SQL" is totally false. You will have to understand SQL and you will have to fiddle with your ORM to generate the SQL you want at some point. But, if you're going to end up fiddling with your ORM and inspecting the generated SQL anyway, then why not just start with something closer to the SQL in the first place?
Phrased differently, we have to learn SQL no matter what--and you won't convince me otherwise--, so why should I have to learn SQL, and Hibernate's APIs and gotchas when I do Java, and Laravel's Doctrine APIs when I do PHP, and Entity Framework when I do C#, etc, etc.
I interpret parent's point as doing the SQL level tuning through the ORM's dedicated mechanisms, and not through a raw string.
Any decent ORM has extra procedures to tweak the resulting query and inject optimizations that it can't arrive at automatically, kicking the ORM away every time there's some tweak to do is counterproductive.
This is bullshit, IME. I've been doing this for over 10 years, and there's not a single one of those "requires a tweak at the string level" queries that couldn't be handled better by actually spending 5 minutes reading the Hibernate documentation and doing what it says to do in that situation. But the same SQL fanboys who believe every developer ought to memorize tri-state truth tables and COBOL-style function names can somehow never be bothered to do that.