Go One Layer Deeper

One ordinary line of code, expanded downward. Every layer names what it hides for you, how it fails, and where to learn it properly. Descend as far as the problem requires — and stop.

One ORM call, all the way down
Depth
A method call that is a transaction, a connection, a dialect-specific statement and a durability guarantee — most of which is invisible until it is the thing that is wrong.
1await userRepository.save(user)
  1. 1
1/8 layers · Enough to build
Why should an application engineer care?

ORMs remove genuinely tedious work and are worth using. They also make the expensive operations look exactly like the cheap ones, which is why performance problems in ORM code are usually structural rather than local.

The question this ladder asks

What SQL did that actually produce, and in which transaction?

What are you delegating to an orm? →
Where this goes wrong in production
  1. ORM
  2. N+1 queries
  3. Database load
  4. Latency
  5. Production incident
The lesson behind it →

What are you delegating here?

What are you delegating to an orm?
Database
You write
1const user = await userRepository.findByEmail(email)
The abstraction handles
  • SQL generation for your dialect
  • Parameter binding — which is what makes it injection-safe by default
  • Object ↔ row mapping and type coercion
  • Connection acquisition and release from the pool
  • Change tracking, so save() writes only what changed
Still your responsibility
  • Query behaviour — what SQL this actually produces, and whether it is one statement or fifty
  • Index requirements — the ORM cannot create the index findByEmail needs; it will happily scan without it
  • Transaction boundaries — where the transaction starts, ends, and what isolation level you got by default
  • N+1 risks — lazy loading turns attribute access into a query, invisibly, inside loops
  • Data consistency — cascades, orphans, and what a partial failure leaves behind
Know your escape hatch

When: The generated query is slow, the plan is wrong, or the shape of the read does not match any entity.

Drop to: Raw SQL for that query, and EXPLAIN to read what the database decided.

Keeping the ORM for 95% of the code and writing three hand-tuned queries is the normal outcome, not a failure of the ORM.