A common backend mistake: treating database schemas like temporary code.
Code deploys in minutes. You ship it, watch it, roll it back if it's wrong. A schema doesn't work like that. The moment production data exists, the schema becomes the memory of the system — and memory doesn't roll back.
Every shortcut compounds:
- The column you added as nullable "for now" still has three meanings two years later
- The status value you retired still sits in a million old rows
- The constraint you skipped in the app gets skipped by the second service too
So schema design has to consider what code design can postpone: relationships, constraints, future queries, data integrity. Put the constraint in the database, not just the validation layer — applications change, get rewritten, multiply. The database is the last writer standing, and the only one that sees every row.
And migrations on live tables are production events, not chores: expand, backfill, dual-write, contract — in that order, over days, not in one deploy.
Code evolves quickly. Databases remember everything. Design like it.
Next in this series: all DB access lives in one place. I write about backend systems that look small until they aren't — follow along if that's your world; the longer pieces live on my Substack.
Top comments (0)