Part 7 · 1 chapters · ~8 min

ORMs at Staff Level

Profiling ORM output with query logs and pg_stat_statements, unsafe generated migrations, transactions through an ORM (propagation, nesting, savepoints), pool interaction across instances, multi-tenancy patterns, when to drop to SQL and how to structure a codebase that does both, testing strategies, and writing the team's ORM position as an RFC.

11

The position, written down

code
RFC: how we use the ORM (excerpt)
1 the ORM for CRUD, simple relations and most reads; SQL (via the query builder or raw, parameterised) for reports,
  bulk operations, locking money paths and anything where the generated SQL is worse than hand-written
2 every list endpoint declares its loading strategy; strict lazy-loading errors on in tests (Rails strict_loading,
  Django nplusone, Hibernate statistics assertions)
3 generated migrations are reviewed as SQL; dangerous operations need a safe pattern (Postgres course P10)
4 transactions are explicit at the service layer, short, and never span external calls
5 pool size per process × processes × replicas stays under the pooler's server pool (Scaling course P2)
6 tenancy enforced in a repository base class AND by database row-level security (Auth course P7)
7 tests run against real Postgres (Testcontainers); no in-memory database substitutes
8 query budget: p95 query count per endpoint tracked; regressions fail CI
testing strategytrade-off
real database per test run (Testcontainers)accurate; seconds of start-up
transaction rollback per testfast; hides commit-time behaviour (deferred constraints, on_commit hooks)
SQLite or in-memory substitutesfastest; different SQL dialect and behaviour: misses real bugs