ContentsThe library

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.

FIG 1Renaming a column, as it is usually attempted and as it has to be done
plaintext
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 same change, done in one statement and in six deploys. The six-step version takes days rather than minutes and every intermediate state is valid for both versions, which means every step can be stopped or reversed on its own. The note at the bottom is the part most often got wrong: steps three and four cannot be combined, because until every instance is writing both columns there are rows where the new one is empty.

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 contents

This 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

The rest of this course

  1. 01Say Out Loud What One Row Is Claiming
  2. 02Seventy-Eight Copies and No Tiebreakeropening only
  3. 03The Email Address Was Reused by the New Employeeopening only
  4. 04There Is No Column That Can Hold a Listopening only
  5. 05The Query Returned Nothing and the Query Was Correctopening only
  6. 06Copy the Value Only If You Are Also Building the Thing That Repairs Itopening only
  7. 07The Report Was Right in March and Is Wrong Nowopening only
  8. 08For Twenty Minutes, Both Versions Have to Be Rightyou are here

Read alongside