Posted by b-man 4 days ago
Just write SQL. I figured this out when I realized that my application was written in Rust, but really it was a Postgres application. I use PG-specific features extensively. My data, and database, are the core of everything that my application does, or will ever do. Why am I caring about some convenient abstractions to make it easier to work with in Rust, or Python, or whatever?
Nah. Just write the good SQL for your database.
I'm not doubting that it can be done, I'm just curious to see how it's done.
The resulting codebase was about 50kloc of C# and 10kloc of SQL, plus some cshtml and javascript of course. Sounds small, but it did a lot -- it contained a small CMS, a small CRM, a booking management system that paid commissions to travel agents and payments to tour operators in their local currencies, plus all sorts of other business logic that accumulates in 15+ years of operation. But because it was a monolith, it was simple and a pleasure to maintain.
That said, SQL is an objectively terrible language. It just so happens that it's typically the least of all the available evils.
I completely agree, it is absolutely essential to understand what SQL is emitted, and how SQL works. Perhaps the strawman argument against ORMs is that they preclude you from knowing SQL. They don't.
You will find that if you check sources they are lifted almost verbatim. LLMs are a way to cut through the noise, but they are rarely "authoring" anything here.
It's wild how far a little marketing can go to sell the same or an arguably worse product that used to be free and less unethical.
ORMs are way more trouble than they’re worth because it’s almost easier to write the actual SQL and just map the resulting table result.
There are many others as well. Sure Rails/Laravel/Django people use the ORM supplied by their framework, but many of us feel it's un-necessary and limiting.
Limiting because for example many of them don't support cte queries(rails only added it a couple of years ago). Plus it get weird when sometimes you have to use sql.raw because your ORM can't express what you want.
Also transactions are way faster when done in a SQL function than in code. I have also seen people do silly things like call startTransaction in code and the do a network request resulting in table lock for the duration of that call.
Some people complain that writing postgres functions make testing harder, but with pglite it's a non issue.
As an aside I have seen people in finance/healthcare rely on authorization provided by their db, and just give access to only particular tables/functions to a sql role owned by a specific team.
People who write percentages make shit up 98% of the time.
Or in other words: Source?
So add another layer that has to be maintained/debugged when you don't have to?
Writing queries is trivial and in any marginally complex case I'll write something which beats the ORM for efficiency. I suppose they are a god send if you don't know SQL but you can learn SQL quite quickly.
ORMs are one of those things that a lot of people think is a replacement for knowing SQL. Or that ORMs are used as a crutch. That has nothing to do with it. Very similar to how people here talked about TypeScript 10 years ago in a very dismissive way. Not really understanding its purpose. Most people haven't used something like Entity Framework either which is game changing level ORM. Massive productivity boost, and LINQ rivals SQL itself in that you can write very small yet powerful queries equivalent to much more complex and powerful SQL.
I've definitely had issues when using sqlalchemy where some REST API type returns an ORM object that ends up performing many queries to pull in a bunch of unnecessary data. I think this is harder to do accidentally with SeaORM because the Rust type system makes hiding queries and connections harder.
Most of my usage of SeaORM has been as a type query builder, which is really what I want from an ORM. I don't want to have to deal with lining my "?" or "$1" binds or manually manipulate strings to build a query. IMO a good query builder moves the experience closer to writing actual SQL, without a query builder I find myself writing "scripts" to write SQL.
Since then I've embraced ORMs for CRUD. I still double-check its output, and I'm not afraid to bypass it when needed.
You may not need to use an ORM, but hand writing SQL, especially CRUD, should be a terminable offense. You _cannot_ write it better than a process that generates it.
But that is the result of having multiple applications needing to enforce valid states in the database.
"Business logic" is a loose term. The database is the effective store for state so it must enforce states, eg by views, triggers, and procedures.
Other "business logic" can happen outside of the db in different languages. When individual apps need to enforce valid states, then complexity, code, etc grows exponentially.
At my new company, the use of stored procedures unchecked has really hurt part of the companies ability to build new features so I'm surprised to see what seems like sound advice, "don't use stored procedures", called out as a cargo cult.
If you don't have a good way to keep stored procedures in version control, test them and have them applied consistently across different environments (dev, staging, production) you quickly find yourself in a situation where only the high priests of the database know how anything works, and making changes is painful.
Once you have that stuff in git, with the ability to run automated tests and robust scripting to apply changes to all of your environments (I still think Django's migration system is the gold standard for this, though I've not seen that specifically used with stored procedures myself) their drawbacks are a lot less notable.
Git? (and migrations)
> change management
Again. Just like any other code.
> and automated tests.
Just write an automated test like you write any other kind of test?
Like any tool, you just have to understand when to use it and when not to.
My experience is following
1) Tx are faster when they are executed a sql function since you cut down on network roundtrip between statements. Also prevents users from doing fancy shenanigans with network after calling startTransaction.
2) It keeps your business logic separated from your other code that does caching/authorization/etc.
3) Some people say it's hard to test sql functions, but since pglite it's a non issue IMO.
4) Logging is a little worse, but `raise notice` is your friend.
> At my new company, the use of stored procedures unchecked has really hurt part of the companies ability to build new features
Isn't it just because most engineers aren't as well versed in SQL as they are in other programming languages.
If not, why would you then avoid putting code alongside your data at the database layer?
There are definitely valid reasons to not do it for some cases, but as a blanket statement it feels odd.
Stored procedures can do things like smooth over transitions by having a query not actually know or care about an underlying structure. They can cut down on duplication or round trips to the database. They can also be a nightmare like most cases where logic lives in the wrong place.
In contrast, every company I've joined that used Entity Framework had enterprise products that ended up being a tightly coupled mess from IQueryable<T> being passed around like the world's favourite shotgun.
"Bad programmers worry about the code. Good programmers worry about data structures and their relationships”
Some quotes stick with you throughout your whole career.
My biggest learnings:
Don't prematurely normalize data, but if it is obvious it can always stay normalized, normalize it. Read the normal forms. Learn about indexing and how data is actually being stored on disk. Just knowing about indexes is a huge advantage even today. Understand and know when to use different styles of data storage: row oriented, column oriented, key value, bigtable style (2d key value), document (rare). Pick good systems. Spend more time than you think you should designing your data. The system is often easy if the data is right. Learn ACID and CAP theorem. Learn when and where you can trade on fundamental database principles in your data model for performance or ease of development. Honestly, a lot of this stuff senior engineers at big tech are just expected to know these days, but it still isn't really obvious and not everyone has big tech problems. Still if you know how to solve the problems at scale and you can get out of your own way it is much easier to write smaller systems (most problems people have).
So in terms of resources, go learn about each of those concepts. Read papers. Ask an LLM about them. Play with databases and storage systems. Maybe try to write your own simple database. Go read about how people design massively scaled distributed systems and what systems they use to manage data. Just like with programming languages, be flexible and open minded. Read about how distributed systems work (CAP theorem). Almost all data systems make tradeoffs in that realm to meet cost/performance/implementation goals.
It's definitely worth learning SQL very well, but you also need to learn the data structures your RDBMS uses, how queries translate into operations on that data, and what those operations look like in a query plan.
You can go surprisingly far with just that knowledge.
A great resource is https://use-the-index-luke.com/
The relational model is pretty simple though. Pandas is an awful mess.
Things like allowing repeat clauses, compute select before where, etc are what solve for composition issues
By the time you are referring to, we were already on the classical 3 tier architecture, the
There are indeed Web frameworks for RDMS, that allow to expose the database as microservices, like Oracle's APEX, which grew out of Oracle's Visual Basic version, which used PL/SQL instead of BASIC.
Do they though? I've been writing SQL for over twenty years, and my experience is that LLMs have been better at writing it than I am for at least most of 2025, for most use cases. I have zero doubt that I will only be writing SQL when I want to for fun no later than sometime 2027.
Wow, bad career choices?
IMO for machine-to-machine talk we should not be using a long text that needs to be parsed carefully and securely on the other side, but rather a structured structure that's easy to de-serialize (like AST packed into a protobuf, but for SQL). So that any invalid SQL parameters like "1;DELETE FROM users;--" would just fail to parse.
It may be called ABI, although it may be textual as well (like json), not necessarily binary (like protobuf).
PostgreSQL already supports binary wire protocol, but I never seen it's being used, instead people prefer sending raw SQL strings designed for humans even from applications.
The basic thesis is that the relational model and SQL has been the prevailing choice for database management systems for decades and that won't change soon.
Resubmitted because it's a good one: https://news.ycombinator.com/item?id=46359878