Most active commenters
  • The_Colonel(4)
  • capitainenemo(3)

←back to thread

873 points belter | 31 comments | | HN request time: 0.609s | source | bottom
1. imjonse ◴[] No.42947407[source]
> ORMs are the devil in all languages and all implementations. Just write the damn SQL

It depends on what you're writing. I've seen enough projects writing raw SQL because of aversion to ORMs being bogged down in reinventing a lot of what ORMs offer. Like with other choices it is too often a premature optimization (for perf or DX) and a sign of prioritizing a sense of craftsmanship at the expense of the deliverables and the sanity of other team members.

replies(8): >>42947752 #>>42947978 #>>42948317 #>>42948504 #>>42953164 #>>42954817 #>>42956074 #>>42956308 #
2. qaq ◴[] No.42947752[source]
It's not so much optimization but experience that on any sufficiently large project you gonna run into ORM limitation and end up with mix of ORM and direct queries. So might as well...
replies(2): >>42948245 #>>42954198 #
3. hitchstory ◴[] No.42947978[source]
Depends upon the ORM. Like all frameworks, a really good one is a significant productivity boost while a bad one is faworse than none at all.
replies(1): >>42957122 #
4. The_Colonel ◴[] No.42948245[source]
Starting with raw SQL is fun. But at some point you find out you need some caching here, then there, then you have a bunch of custom disconnected caches having bugs with invalidation. Then you need lazy loading and fetch graphs. Step by step you'll build your own (shitty) ORM.

Same thing for people claiming they don't need any frameworks.

replies(4): >>42948519 #>>42950241 #>>42951262 #>>42953407 #
5. magicmicah85 ◴[] No.42948317[source]
It’s the devil I know and for most of my projects I’ll likely never forsake ORM for raw SQL.
6. Twirrim ◴[] No.42948504[source]
One job I had, we got handed a code base with at least 4 different reinventions of an ORM in it.

It became clear that each developer who'd worked on the code had written their own helpers to avoid direct SQL. It took a fair bit of persuading leadership, but the first task ended up being doing a huge reactor of everything SQL. Unsurprisingly enough, lots of bugs got squashed that way.

7. wesselbindt ◴[] No.42948519{3}[source]
> you find out you need some caching here, then there

Forgive my ignorance, but how do ORMs help with adding caching? Or are you implying they obviate or reduce the need for caching?

replies(2): >>42948686 #>>42948792 #
8. ivan_gammel ◴[] No.42948686{4}[source]
They do caching themselves so that some of your queries via ORM won’t hit the actual db.
replies(1): >>42949394 #
9. The_Colonel ◴[] No.42948792{4}[source]
JPA implementations have "managed entities", sometimes called session or 1st level cache which is making sure that every entity is loaded at max. one time within a transaction. Like e.g. checking user/user permissions is something which typically has to be done in several places in course of a single request - you don't want to keep loading them for every check, you don't want to keep passing them across 20 layers, so some form of caching is needed. JPA implementations do it for you automatically (assuming you're fine with transaction-scoped cache) since this is such a core concept to how JPA works (the fact it's also a cache is kind of secondary consequence). JPA implementations typically provide more advanced caching capabilities, caching query results, distributed cache (with proper invalidation) etc.
replies(1): >>42948809 #
10. wesselbindt ◴[] No.42948809{5}[source]
Ah yep, of course! Thanks!
11. capitainenemo ◴[] No.42949394{5}[source]
So, given the main issue with ORM is the object/relational part... (https://web.archive.org/web/20160301022121/http://www.revisi...)

Why is caching not a feature in DB connection pools? I mean, most databases have it on their side, why not have it as an option for the same query sets prior to hitting the db, with configurable invalidations? Or is it, and I've just never thought to look for it.

replies(2): >>42949808 #>>42952224 #
12. The_Colonel ◴[] No.42949808{6}[source]
Integrating cache into connection pools brings little added value since connection pools don't have enough context/information to manage the cache intelligently. You'd have to do all the hard work (like invalidation) yourself anyway.

Example: if you execute "UPDATE orders SET x = 5 WHERE id = 10", the connection pool has no idea what entries to invalidate. ORM knows that since it tracks all managed entities, understands their structure, identity.

replies(1): >>42950152 #
13. capitainenemo ◴[] No.42950152{7}[source]
I guess I was thinking more of frequently run queries against infrequently modified data or where stale data doesn't matter so much. The sort of things that are ideal cache targets. You'd think you could tag queries like that. Sort of the things that a CDN caches but more granular. Sure if it's stuff that's frequently changed, an ORM could reason about it just like, well, the database does, but then you're back into all the bad things about running your shadow database with a badly fitting model, and you'd be better off just ensuring all or part of the database ran closer to your app with replication, say, in memory on same server.
14. qaq ◴[] No.42950241{3}[source]
caching is orthogonal to using or not using ORM. You might opt to have caching with or without ORM in a consistent manner. You can also opt to add read replicas fronted by say pgcat in Postgres case without having separate caching layer.
replies(1): >>42950714 #
15. The_Colonel ◴[] No.42950714{4}[source]
I guess this is a point where terminology matters. If you work with SQL database in an OOP language, you pretty much always do some object-relational mapping, no matter if you have a big framework or just raw SQL connection.

But this is not what people usually call as ORMs. All the "bad kind of ORM" (JPA impls, Entity Framework, SQLAlchemy, Doctrine, Active Record...) have some concept of an entity session which is tracking the entities being processed. To me, this is a central feature of an ORM, one of its major benefits. It is, incidentally, also serving as a transaction-scoped cache.

I won't of course dispute that you can have caching on other levels as well (which may perform differently, for different use cases).

16. stackskipton ◴[] No.42951262{3}[source]
As SRE who dealt with more caching errors then I care to. Alot of caching comes down to YAGNI.

To his point: It's very hard to beat decades of RDBMS research and improvements

Your RDBMS internal caching will likely get you extremely far and speed difference of Redis vs RDBMS call is very unlikely to matter in your standard CRUD App.

replies(1): >>42953875 #
17. ivan_gammel ◴[] No.42952224{6}[source]
That would be a result set layer, not a connection pool. Could make sense if you worked with rows, but if you use ORM, why mapping cached row again and again? ORMs cache hydrated objects, which seems to be more efficient.
replies(1): >>42953337 #
18. nodamage ◴[] No.42953164[source]
I've never understood the ORM hate because a good ORM will get out of the way and let you write raw SQL when necessary while still offering all of the benefits you get out of an ORM when working with query results:

1. Mapping result rows back to objects, especially from joins where you will get back multiple rows per "object" that need to be collated.

2. Automatic handling of many-to-many relationships so you don't have to track which ids to add/remove from the join table yourself.

3. Identity mapping so if you query for the same object in different parts of your UI you always get the same underlying instance back.

4. Unit of work tracking so if you modify two properties of one object and one property of another the correct SQL is issued to only update those three particular columns.

5. Object change events so if you fetch a list of objects to display in the UI and some other part of your UI (or a background thread) add/updates/deletes an object, your list is automatically updated.

6. And finally in cases where your SQL is dynamic having a query builder is way cleaner than concatenating strings together.

For those who are against ORMs I am curious how you deal with these problems instead.

replies(1): >>42959318 #
19. capitainenemo ◴[] No.42953337{7}[source]
Yeah, it was more to see if there were any benefits to an ORM that could be used without the, well "ORM" part :)
20. gilbetron ◴[] No.42953407{3}[source]
There are plenty of libraries/packages for SQL that do all of that for you, too. The choice isn't between a sophisticated ORM and just throwing SQL text at a socket. The fundamental assumption of ORMs is broken, but much of the tooling works well and exists in non-ORM places.
21. lcnPylGDnU4H9OF ◴[] No.42953875{4}[source]
> Redis vs RDBMS call is very unlikely to matter in your standard CRUD App

To any juniors reading: cache the response payload (or parts of it), not the results of database queries.

22. jolt42 ◴[] No.42954198[source]
It seemed to me TOPLink had this figured out, and then hibernate took it all away.
23. snapetom ◴[] No.42954817[source]
> being bogged down in reinventing a lot of what ORMs offer.

There's a saying - if you hate ORMs and don't use them, eventually you're going to write your own ORM.

24. arwhatever ◴[] No.42956074[source]
Just mentioned to an acquaintance a couple of days ago that Entity Framework is the biggest flip-flop of my personal career. I was a _rabid_ supporter when it was released a decade and a half or so ago, and the appeal has decreased linearly over time, to the present day.

Statically-typed queries written in a mini-DSL within your application language seems like such a joy!

But then the configuration is a hassle. The DbContext lifecycles are a hassle. The DbContext winds up a big ball of mutable state that often gets passed all up and down your call stack, reducing the ability to reason about much of the code locally. Was this instance initialized with or without change tracking? How many and what changes have been applied? Were these navigation properties lazily or eagerly loaded?

And it promises to keep your domain persistence ignorant with its fluent configuration syntax. But then you have compromise on that here, then compromise in it there.

Pretty soon, you realize that you started out building a project for domain X or domain Y, only to realize that you're trying to shoehorn domain X/Y behavior into your Entity Framework app.

25. torginus ◴[] No.42956308[source]
I'm a hardliner on supporting this - I'd go further - all the DB code should be in SQL, with the database being manipulated by stored procedures and the db schema not even being exposed to the common developer.

As far as I know this is a very oldschool view on how to treat dbs, but I still think this is the only correct one.

I hate ORMs with a passion - they're just a potential source of bugs and performance issues, coming from either bugs in the engine, devs not understanding SQL, devs misjudging what query will get generated, leaky abstractions etc.

It's big enough of an ask to understand SQL itself, it's the height of folly to think you can understand SQL when it's being generated by some Rube-Goldberg SQL generator, especially if said generator advertises that you don't need to know SQL to use it.

replies(1): >>42962885 #
26. default-kramer ◴[] No.42957122[source]
And not just the ORM, but the way it's used. If you ensure that lazy-loading is turned off from day 1 and stays off, you might be okay. But if you don't pay attention to this and write a bunch of code for N years until all the "select N+1"s you've been unwittingly doing finally force your DB to a crawl... now you're in trouble.
27. priyadi ◴[] No.42959318[source]
You are describing data mapper ORMs, a.k.a the good ORM. I think all the other ORM-loathing guys here had bad experiences with active record ORMs, a.k.a the bad ORM.

Also, infrastructure guys and DBA types tend not to like ORMs. But they are not the ones trying to manage the complexity in the business process. They just see our queries are not optimal, and it is everything to them.

replies(3): >>42959735 #>>42960026 #>>42960101 #
28. nodamage ◴[] No.42959735{3}[source]
Yes I suspect a lot of the ORM hate comes 1) from people using poorly designed ones or 2) from people working on projects that don't really require the features I mentioned. Like if you are generating reports that just issue a bunch of queries and then dump the results to the screen you probably don't care that much about the lifetime of what you've retrieved. But just because an ORM might not be the right tool for your project doesn't make it a bad tool overall, that would be like saying hammers are bad tools because they can't be used to screw in screws.
29. whilenot-dev ◴[] No.42960026{3}[source]
Oh was I enthusiastic when I first got my hands on an active record ORM: "I can use all my usual objects and it'll manage the SQL for me? Wow!". That enthusiasm reached rock bottom rather quickly as soon as I wanted to fine tune things. Turns out I'm not a fan of mutating hierarchical objects and then calling a magical .commit()-method on it, or worse: letting the ORM do it implicitly. That abstraction is just not for me and I'd rather get my hands "dirty" writing SQL, I guess.
30. globular-toast ◴[] No.42960101{3}[source]
Right! They should really be considered two different things. I've worked a lot with Django (the bad type) which people tend to love, but I've seen the horrors that it can produce. What they seem to love about it is being able to write ridiculously complicated SQL using ridiculously complicated Python. I don't get it. These types of ORMs don't even fully map to objects. The "objects" it gives you are nothing more than database rows, so it's all at the same abstraction level as SQL, but it just looks like Python. It's crazy.

SQLAlchemy is the real deal, but it's more difficult and people prefer easy.

31. jugg1es ◴[] No.42962885[source]
You must live a charmed life if you haven't run into major problems with stored procedures.