Card 06/ 09

WalkthroughDifficulty: Intermediate2 min

Renaming a Field With Expand and Contract

Add the new name, write both, move the clients, then remove the old name, and no client breaks at any step.

Expand and contract, also called parallel change, makes a breaking change in steps that are each safe on their own. The API first expands, adding the new form beside the old one, then waits while clients move, and only then contracts, removing the old form. Applied to renaming customerName to a nested customer.name, no client sees a missing field at any point.

It works like moving house with mail redirection: for a while both addresses reach you, until everyone has the new one. The comparison breaks on timing. Redirection ends on a fixed date whether or not everyone has moved; expand and contract waits until the last client has.

The fields of an order response at each step of the rename

InputRename customerName to customer.name on GET /orders/{id}

  1. Before

    1. id
    2. customerNameold
    3. total

    Every client reads customerName.

  2. Expand

    1. id
    2. customerNameold
    3. customer.namenew
    4. total

    The API writes both with the same value, and accepts either in requests. The contract marks customerName as deprecated.

  3. Migrate

    1. id
    2. customerName
    3. customer.namenew
    4. total

    Clients move to read customer.name, then to write it. The team tracks which clients still use the old name.

  4. Contract

    1. id
    2. customer.namenew
    3. total

    Once no client reads or writes customerName, the API removes it.

ResultThe rename finished without a version change and without a client failing, because each step only added, moved or removed something nobody used.

Why the steps are each safe. Expand only adds, which a tolerant client survives. Migrate changes clients, not the API. Contract removes a field nobody uses any more, which by the breaking-change test breaks no one.

The step teams skip. Contract. The old field lingers for years because removing it needs evidence that nobody uses it, so collect that evidence from the start, by logging which clients read and send it.

Where it does not work. When the client cannot be moved, such as an old mobile app nobody updates, the contract step never arrives, and the change belongs in a new version instead.

The same pattern elsewhere. Database schemas change the same way: add a column, write both, backfill, move readers, drop the old column.