Designing a Table to Live With
For Twenty Minutes, Both Versions Have to Be Right
Last timeStoring What Was True Then
A deploy is gradual, so old and new code run at once against one schema. Every safe migration is the same six steps, and a few changes have no safe sequence at all.
The previous seven lessons were about what the schema should be. This one is
about getting there from where you are, while people are using it, which is a
different discipline with its own rules.
Two versions, one schema
Start with the fact that makes this hard. A deploy is not an instant. New
instances start while old ones are still serving, so for some period both
versions of the code are running against one database.
That period is longer than it sounds. The rolling deploy itself is minutes. A
background worker that only restarts between jobs can be an hour. A cached page
holds old output for as long as its lifetime. A mobile app that half your users
update within a fortnight is a version of your code running against your
schema for months, and you cannot make them upgrade.
So the rule is not that the schema must be valid after the change. It is that
the schema must be valid for every version of the code that can still run,
at every moment during the change.
THE ATTEMPT
ALTER TABLE customers RENAME COLUMN phone TO phone_number;
The instant this runs, every old instance breaks, because
it is still selecting phone. The deploy is halfway done.
Every request handled by an old instance fails until the
rollout finishes, and a rollback makes it worse.
THE SEQUENCE, SIX DEPLOYS
1. ADD COLUMN phone_number, nullable, no constraint
Old code ignores it. New code is not out yet.
2. Backfill in batches, 5000 rows at a time
Both versions still read phone. Nothing depends on the
new column yet, so a failed batch is harmless.
3. Deploy code that writes BOTH columns
Every write keeps them equal from here on. Old code
still writing only phone is fine: see note below.
4. Deploy code that READS phone_number
The first step that depends on the backfill. If the
numbers do not match, stop here and fix, because
nothing has been removed yet.
5. Deploy code that no longer writes phone
Now the old column is dead but still present.
6. DROP COLUMN phone, after the longest-lived client has
had time to be replaced
Note on step 3: while old instances write only the old
column, new rows have an empty new column, so step 4
cannot begin until the whole fleet is on step 3. That is
the reason these are separate deploys and not one.The six steps
The sequence generalises. Any change to a column is the same six steps, and
naming them makes the next one mechanical.
The lesson stops here
5 more paragraphs to go
You have read the opening. The rest of the argument, the problems that check whether it landed, and the lines worth keeping at the end all come with a plan.
The first lesson of every course in the library reads the whole way through, free, so you can see exactly what the rest of them are.
See the planThe contentsThis is the reading half
Starting the course gives you your own copy of it. Every idea on every page has problems standing under it, marked with a reason rather than a tick, and any sentence you do not believe can be opened and argued with. None of that can happen on a page nobody owns.
The contents