Hacker News new | ask | show | jobs
by ozim 9 days ago
Don't use an ORM.

Highly debatable. When your highest cost is developers salaries.

Don't reinvent a type system by having a single table where each row can mean many different things depending on a "type int" enum col.

Easy to say, harder to not do when you have business requirements on table, customer pressure and budget already gone on discussing with DBA who maybe is right but you are burning money right here and right now. The same with point no. 9

7 comments

I would highly recommend using ORM's, with the caveat to know exactly when not to use them. Startups do not fall in that bucket.

1. Most of these advices are unfortunately impractical and incomplete for startups. A good Data Model is highly dependent on understanding the business requirements, data flows. Means unless you are repeating yourself in the same domain its really hard to come up with a good schema in first iteration.

2. Startups are in the mode of discovering the schema for most part

3. Deleting columns is harder than adding additional columns, no one takes that risk so everyone ends up with schema bloat

4. Once you go a little bigger you will realize that the integer based UUID are not that great of a choice. Those are separate tables which maintain those index counters and not part of your DDLs. They have their own set of issues with data merging, backups and recovery

For the OP, I looked at the repo (https://github.com/hatchet-dev/hatchet/blob/main/sql/schema/...) ,

1. seems like the schema has database functions - Thats a potential scaling issue, plus you are asking vertical only scalable component to do something which could have taken care by horizontally scalable component

2. TEXT datatype for pretty much every attribute - this is a footgun, you cant use them for indexes properly, in the absence of length checks they can be abused from client side

I've never actually known business requirements ahead of time, when I worked for a startup and for a large company. Stuff happens. You build your schema iteratively and yes, accept some temporary bloat when cols get added thoughtlessly.

The UUID backup/recovery thing isn't an issue if you're doing append-only. Joins on UUIDs are far slower, enough that even at small scale it can cause issues when you have many joins. Anyway I won't argue too hard against UUIDs cause they work too, just anything is better than using meaningful fields as the PKs.

In my experience, ORMs save a little bit of writing SQL and then cost an unbounded quantity of time in debugging mysterious problems because knowing why a query is slow now requires understanding the DB, your own code, and also the ORM.
In my experience ORM doesn’t save anything on writing queries. You still have to write somewhat same code that looks like sql query. You still need to know joins, you still need to know DB structure.

Getting rid of SQL queries is not the job of ORM.

ORM saves you time on object mapping boilerplate THAT IS THE JOB of an ORM it is right there in the name „object relational mapper”.

And also more loc than SQL usually. It's not even a deferred cost, it's at least slightly worse upfront
The best way to cure a developer of their ORM dependency is to put them on a project with a complex OLAP / data warehouse component. OLTP workloads are reasonably well aligned with a lot of ORM patterns so it's more difficult to demonstrate the caveats here (but it's definitely still possible). The limitations of ORMs are much more apparent with OLAP workloads. ORMs simply cannot cope with provider specific requirements. All ORMs fall on their asses when it comes time to load any meaningful amount of data into the provider.

The biggest consequence of forcing the RDBMS through a lazily evaluated object graph is that we've become decoupled from the mechanical realities of what the database provider can do. I had a client quickly drop the "you must use EF" commandment for the project I was assisting on once they saw how many rows it was loading per unit time without EF. "I didn't know that was possible". Many such cases.

Real problem I encounter usually is that business people (and devs) don’t understand OLAP vs OLTP.

They think they can bolt on dashboards or make interface having basically OLAP in the same project and make it perfectly performant.

Here in this thread you have bunch of devs claiming ORM doesn’t work - it works perfectly fine for OLTP. Those devs who claim to be so great knowing SQL also don’t seem to understand that business people are throwing them under bus requiring OLAP stuff to be bolted on OLTP application.

To add on that business people expect OLAP views or dashboards to be „real time” — only after they have dashboard developed to look at it once a month or once a quarter.

What also pains me when I deal with devs is that they pick up synchronization jobs, well batch jobs are fine but then they are scolded by business that batch jobs are slow. Where we have all kinds of tech to make event driven updates to OLAP environments.

It was kinda debatable until people started Claude coding everything. Even before, I would've said every SWE should just know SQL, it's not much buy-in to understand the foundation of like your entire backend. Also I'm not a DBA if that's what you meant.
I have never seen a dev and we never would hire a dev that doesn’t know SQL and yet we still use ORM for each and every app we develop.
Leaning SQL is arguably less dev work over the long run than learning an ORM and then learning how it works so you can fix performance issues.
Yep, there have been extended periods of time where my entire job title might as well have been "ORM remover" because they backed themselves into a corner
Do you have any meaningful experience as a software developer?

That’s a silly take. I somehow learned over the long run: SQL different flavors, couple of ORMs, multiple programming languages and multiple frameworks. Not counting different troubleshooting different operating systems and different applications I had to work with.

We all learn whatever we need to learn to deal with the situation. I've had to learn more distinct ORMs than SQL flavors, even though you also need to know the SQL when you use an ORM. Doesn't mean I wanted to.

However, each time a teammate wanted to use an ORM, I didn't call it silly or question their credentials.

ORMs are just tech debt. Even if your highest cost is developer salaries, you're just pushing that cost down the line.
I'd also argue whether ORMs actually save that much time in practice. In Java, for example, the main time sink is the JDBC plumbing and its easy to use something like JDBI that handles that plumbing without abstracting away the underlying SQL.

The application->database layer is pretty impactful and it pays to pay attention to it, because poor access patterns will cause a lot of trouble in the future, and its made worse by not having a very accurate understanding of whats going on in that layer.

I think a lot of developers don't have a good sense on where their time sinks actually are. Boilerplate is not pleasant to write but also not the timeline-destroyer people tend to think it is. And its often not enough of a time-sink to warrant introducing "magic" that will have very large negative future impacts.

Yeah, they'll often conflate the ORM with the nice stuff you want like connection pools. And the thing about time estimates is real. Another thing is they'll optimize too hard for having fewer tables.
For active record patterns I disagree: it’s nice to work with data in a way that feels natural. Chugging simple stuff around in a recognizable way is what you’d end up writing anyway in many applications. Writing your ORM-lite is waste.

When it comes to advanced queries learning the ORM equivalent to the SQL it should write… ORM’s can be outright terrible, and I completely agree with you.

Every ORM has their own names and way of doing things, so this knowledge is hard to port to other ORMs. It’s requires you knowing the right SQL first, then knowing how to write that in the ORM dialect.

Reaching for the more advanced ORM trickery means grasping hard to grasp subjects twice with the risk of misunderstanding twice, and as a bonus worse ORM documentation than plain active record features. Oh, and others need to understand what you’ve written as well.

you’re going to pay the cost regardless. one approach absorbs the cost up front, and the other defers it, with interest
> Highly debatable. When your highest cost is developers salaries.

I think everyone always is needlessly partisan when ORMs get mentioned.

Personally, I view it like so:

  * using something separate from your ORM for migrations *can* be good (e.g. you don't couple your DB to your app's ORM), like dbmate; needs to be said
  * making plenty of views for MOST of your complex queries is a good idea, if approaches like BFF are popular for APIs, then why not the same in regards to interacting with your DB? also makes testing a breeze, instead of having to pull some unreadable generated SQL bullshit from trace logs
  * you can make read only entity mappings against those views and keep the querying complexity in the DB but let the ORM handle the app side stuff
  * with that in mind, using the ORM for most of the simple queries and regular CRUD stuff is also a breeze
  * sprinkle in some DB procedures/functions if needed, but also don't go all gung-ho in storing 90% of your business logic in the DB and using the app as a glorified view/controller, while that might appeal to a subset of people, in the *present* time that inevitably sucks
  * similarly to CTE's, your views can reference other views, as building blocks; also sometimes having two similar views that just compose others is nicer than dynamically generated SQL (since once you start trying to generate it dynamically, people get too eager about it and before you know it you can't figure out WTF is going on)
Like I don't passionately hate something like jOOQ or myBatis on Java side as well, it's just that often they mean that you can't quite surmise what the query will be, compared to just being able to look at a DB view and incorporate it into your SQL query tool of choice easily. Same goes for Hibernate, if you have to write complex HQL queries, then maybe consider whether you can do things more simply. There are also projects out there for which JDBI3 and the likes of which are perfectly okay, too! Note that I only mention Java cause it has a lot of ORMs and options, with various approaches to solving the same issue.

Reading some other comments, I'd also add: know SQL, use SQL for the problem it's good at, same for ORMs; don't let either overstep the other. In my opinion a really good litmus test for this is whether you are capable of generating all of your ORM mappings when you point a tool at your schema and its tables/views. If not, and you need complex workarounds, something is wrong.