4 ms·
Postgres Is Your Friend. ORM Is Not
- janmarsal 8mo agoPostgres is amazing and ORM is your friend. Migrations alone is a good reason why using ORMs is a good idea.
- manuelabeledo 8mo agoMigrations aren’t necessarily tied to ORMs. There are tons of tools out there to run migrations and nothing else.
- andreldm 8mo agoAgreed, in many Spring projects I worked migrations were handled by flyway or liquibase while the ORM was always Hibernate.
- altmanaltman 8mo agoWhile there is a compelling case for leveraging the full power of Postgres (especially features like SKIP LOCKED and pg_notify), this approach feels like a classic trade-off between fine-grained control and long-term maintainability. Relying solely on raw SQL and manual mapping certainly eliminates "ORM magic," but it replaces it with a significant maintenance burden. For specialized, high-performance systems like video transcoding, this level of hand-tuning is a superpower; however, for the average CRUD-heavy SaaS app, the "boilerplate tax" of writing eighty lines of repository code for a simple related insert might eventually cost more in development velocity than the performance gains are worth.
- nicoburns 8mo ago> for the average CRUD-heavy SaaS app, the "boilerplate tax" of writing eighty lines of repository code for a simple related insert might eventually cost more in development velocity than the performance gains are worth. Perhaps, but IME this kind of thing is much more often the cause of poor performance in CRUD apps than the frontend frameworks that are usually blamed. I have been able to make very snappy SaaS apps by minimizing the number of queries that my API endpoints need to perform. I've also found that the ORM mainly reduces boilerplate for Insert/Update operations, but often adds a very significant amount of boilerplate for read queries. We ended up using a very lightweight orms for simple inserts / upserts and writing raw SQL for anything else.
- manuelabeledo 8mo ago> For specialized, high-performance systems like video transcoding, this level of hand-tuning is a superpower Where does SQL fall in the video transcoding pipeline?
- tags2k 8mo agoThis straw-mans ORMs by listing out what crappy ones do. I mean, accidental writes? You've either got a terrible ORM, no tests, or both.
- ecshafer 8mo agoI gotta agree with you, total straw man. I haven't seen any of the issues this guy has with ORMs.
- cowboylowrez 8mo agoYeah ORMs help when they're appropriate but ya gotta learn how they work and where the footguns are plus you still really want to know how a database server works. Given the articles title, I doubt the prerequisites were met.
- DrewADesign 8mo agoConsidering anybody with a noggin is going to be separating the SQL into it’s own module or whatever rather than just throwing straight inline SQL at your database wherever you it, you’re hardly less likely to have things like accidental writes, anyway. This is clearly someone who fell in love with Postgres, felt ORM abstractions that diluted the Postgres goodness were bad, and then did some mental experiments to consider all of the theoretical ways ORMs suck.
- Doctor_Fegg 8mo agoAh, we haven't had an "ORMs bad" post for at least three days.
- dakolli 8mo agoEveryone too busy writing and posting their "How I use Think for me Saas" / BrEaK It InTo SmAlLeR TaSkS blog posts.
- RockRobotRock 8mo agoI sure loved delving into this blog post.
- rrr_oh_man 8mo agoYup, sloppy slop-slop
- DangitBobby 8mo agoIs there a platform convention for this yet? Can we flag obvious slop?
- Zanfa 8mo agoThough the article mentions the distinction between ORMs and query builders, it doesn't really make a case against query builders being bad. After all, it wraps up by building a kinda crappy one-off query builder.
- bakugo 8mo agoThis again... No, just because raw SQL queries work great for your toy blog/todo app with 3 tables and simple relationships, doesn't mean they work great for real world business applications with 100 tables and complex networks of relationships. Try maintaining the latter before you make blanket claims like "ORM bad".
- nubinetwork 8mo agoI guess I'll bite. How/When do you know you actually need an ORM?
- rrr_oh_man 8mo agoMaybe if you add a new variable to a table and need it in a query five views down? But honestly I much prefer using assisted queries like the supabase package, but leaving the tables alone. ORM can be very unwieldy in an unstable environment. I’ve once tried a "type-safe" SQL extension and it was pretty neat. Imho something like this is much more useful than a lot of ORM-overhead.
- throwaway613746 8mo ago[dead]
- bakugo 8mo agoIf you're asking yourself "do I need an ORM?", then you should probably default to using one, unless you understand your complete use case well enough to know you'd be better off without one. It's also important to note that not all ORMs are created equal. Some are more restrictive than others, and that should also be taken into account.
- manuelabeledo 8mo ago> just because raw SQL queries work great for your toy blog/todo app with 3 tables In my experience, ORMs work well for toy projects, but become cumbersome to maintain in enterprise ones, especially where performance matters. There is a large overlap between engineers who refuse to learn SQL because it's not "convenient", and those who prefer ORMs because they are "easier", resulting in cohorts that don't know how to use either. But also, I don't see how ORMs make managing large databases any easier, other than those with embedded migration capabilities, which can be very well extracted to their own tools.
- MarcLore 8mo ago[dead]
- aardvark179 8mo agoIt’s been swinging for at least 30 years, Toplink came out in 1994, and I have worked on systems that were written half a decade earlier that contained things we’d all call ORMs.
- deleted 8mo ago[deleted]
- j45 8mo agoAgreed, ORMs are OK to start with if you like and then optimize the queries where needed. There are cases where older ORMS might be more optimized for some cases compared to new ones, and vice versa. Avoiding learning SQL is the biggest gap. Selecting a NoSQL database because it seems easier, and then spending so much time trying to make a NoSQL database into a relational database is usually not too pretty.
- rrr_oh_man 8mo agoEdit: Thanks for the merciless downvotes. :) But it’s a bot writing the above. Look at the user's comment history. "Not x, but y", poorly formatted listicles, mid-paragraph questions to the reader, and em dashes galore.
- luckylion 8mo agoThe day where they'll be hard to tell apart from humans is close. My alarms didn't ring on this on already, I'll be taken out by the first wave of impostors :( I agree after a closer look though. the pattern is so strong, you can identify it visually. comments 2, 3, and 4 are all three paragraphs, the next three are all one longer paragraph, and all are of very similar length.
- zelphirkalt 8mo agoI don't see any emdashes in the above, nor do I see any mid-paragraph questions.
- DrewADesign 8mo agoI’m glad you’re head-over-heels in love with Postgres— it’s really cool, and I’ve occasionally had projects that really benefited from it… but most of those incredible features just aren’t useful for run-of-the-mill projects. Learning how to profile your ORM queries is a lot easier than maintaining a bunch of code from a different language embedded into your code base. If you’re writing articles about Postgres, you probably have no idea how much of a PITA that context switch is in practice. It’s funny how getting expertise in something can make it more difficult to understand why it’s useful to other people, and how they use it.
- manuelabeledo 8mo agoThere are projects, like SQLC, that cover most of the perceived advantages of ORMs, without the downsides. One of these downsides is, in my opinion, the fact that they hide the very details of the implementation one necessarily needs to understand, in order to debug it.
- DrewADesign 8mo agoLet me just say that I wrote my first (professional) SQL queries about 25 years ago and at various post points have worked extensively with Postgres, a bit less so with Oracle, and occasionally with MySQL and MSSQL. (And also some of the JSON object store databases before switching to Postgres for that stuff.) The only ones I’ve used ORMs with are Postgres and MySQL. SQLC does not address most of the perceived advantages to ORMs. Sure it addresses some of the concerns of hand-writing and sending SQL to databases from various languages, but that’s not what most people I’ve spoken to in the past couple of decades most valued about ORMs. What most projects really need databases for is some place to essentially store context-sensitive variable values. Like what email address to send something to if the user ID is 12345. I’ve never, ever had to debug ORM’s SQL when doing things like that. Rarely have I needed to with more complex chains of filters or whatnot, and that usually involved taking a slightly different approach with the given ORM tools rather than modifying them or writing my own SQL. When I’ve had more complex needs that required using some of the more exotic Postgres features, writing my own queries has been trivial. It’s of paramount importance for developers to understand the frameworks and libraries, such as ORMs, they’re using because those implementation details touch everything in your code. Once you understand that, the code your ORM composes to make your queries is an IDE-click away. Not having to context switch between writing SQL and whatever native language you’re working in, especially for simple tasks, has yielded so so so much more to my time and mental space than being exactly 100% sure that my code is using that left join in exactly the way I want it to.
- sunbum 8mo agoAgreed, write raw SQL, this has never had any security impact whatsoever[1] - Your friendly local pentester [1] - https://en.wikipedia.org/wiki/SQL_injection https://en.wikipedia.org/wiki/SQL_injection
- christophilus 8mo agoPorsager’s Postgres package does a great job of letting you feel like you’re writing raw sql, but avoids the attack vectors. Anyway, I agree that ORMs are pretty terrible. I like writing SQL or using a lightweight builder like Kysely. Was a huge Dapper fan back in my C# days. There are plenty of reasonable alternatives to ORMs that don’t open you to SQL injection attacks.
- lowsong 8mo agoParameterized queries have been a thing for decades, which mitigate SQL injection attacks.[1] This is true of the examples in the post too, they used this: query = """ SELECT * from tasks WHERE id = $1 AND state = $2 FOR UPDATE SKIP LOCKED """ rec = await self.db.fetchone(query=query, args=[task_id, TaskState.PENDING], connection=connection) [1] https://en.wikipedia.org/wiki/SQL_injection#Parameterized_statements https://en.wikipedia.org/wiki/SQL_injection#Parameterized_st...
- Lockal 8mo agoParameterized queries fail to protect from SQL injection for decades, because database engine developers fail to listen. What could work instead, if any parameter could be safely injected: SELECT $1, $2($3) FROM $4 WHERE $5 $6 $7 GROUP BY $1 ORDER BY $8 $9 but at that point SQL loses its point and turns into MongoDB query language.
- deleted 8mo ago[deleted]
- deleted 8mo ago[deleted]
- manuelabeledo 8mo agoMostly agreed with the author about ORMs. The provided querying abstraction works against developers when queries reach a certain level of complexity, and at the end of the day, understanding these complexities is not optional. But I would caution against adding too much business logic to the database, and tying message passing to your database doesn’t sound like the best of ideas.
- luckylion 8mo agoBut there's also value gained in it, isn't there? I very much like doctrine's query builders and being able to analyze and manipulate queries programmatically, e.g. dynamically add a filter to a query and a join if needed. That's pretty simple with a query builder once you've gotten comfortable with the concept and the ORM itself, but it's pretty hard to do with plain sql unless you write plenty of specific code to handle all the known things you might care about.
- manuelabeledo 8mo agoIt sounds to me that you saying that SQL is hard because you’d rather learn the intricacies of an ORM. Also, this whole point predicates upon the assumption that ORMs are infallible when translating queries into SQL, which most definitely are not.
- luckylion 8mo agoNo, I'm saying if you want to alter SQL queries programmatically, you'll either do some quick hacks with regexps that you'll regret, or you need to build something to do that, and that will look suspiciously like a query builder.
- manuelabeledo 8mo agoI’m having a hard time trying to understand exactly what you want to do, that cannot be done with SQL. Any concrete examples? I personally rely on views to reuse base queries and then add filters on top of them.
- Waterluvian 8mo agoWhen someone says that X is bad and not to use it, what I really hear is, “I’m ignorant to some use cases but that won’t stop me from having a loud opinion.” I oscillate on being tired or amused by just how common tech people make this basic error. But I don’t believe it’s ever in bad faith. I think people in general suffer from perceiving their context as the context even though they’ve experienced maybe 1% of what there is out there.
- throwaway613746 8mo ago[dead]
- charettes 8mo agoThere are valid reasons for not using an ORM but the points made in this article are plain false. >“Roughly” because Django ORM doesn’t support the JSONB `?` operator. The `has_key` [lookup](https://docs.djangoproject.com/en/6.0/topics/db/queries/#has-key https://docs.djangoproject.com/en/6.0/topics/db/queries/#has...) does exactly that. > And if you need real SQL intervals, Django pushes you towards raw expressions or `Func()` wrappers. It's possible to use a very similar construct to SQL Alchemy here by using the `Now` [function](https://docs.djangoproject.com/en/6.0/ref/models/database-functions/#now https://docs.djangoproject.com/en/6.0/ref/models/database-fu...) (it uses `STATEMENT_TIMESTAMP` which is likely more correct than `NOW()` here alternatively there is `TransactionNow`) by doing `Now() - timedelta(days=30)`. The result is the following `filter` call filter( metadata__tags__has_key="python", created_at__gte=( Now() - timedelta(days=30) ), ) which translates to the following SQL ("app_video"."metadata" -> 'tags') ? 'python' AND "app_video"."created_at" >= ( STATEMENT_TIMESTAMP() - '30 days'::interval ) which can be confirmed in [this playground](https://dryorm.xterm.info/hn-47110310 https://dryorm.xterm.info/hn-47110310)
- aragilar 8mo agoAlso, the django ORM is fairly easy to extend, it's not like it was written as one big blob.
- fud101 8mo agoIs that python code that runs on postgres? how does this work..