Path 02Lesson 5 / 6

Change an existing system safely

Preserve current contracts while you introduce a change. Account for old clients, data, and deployment order.

Advanced11 minReviewed

Published by How we write

What you will learn

  • Identify contracts that a local code change can affect.
  • Explain a staged expand-and-contract change.
  • Distinguish code rollback from data recovery.

Identify the contracts around the change

Existing software has callers, stored data, scheduled jobs, and operational procedures. Some dependencies are not visible in the file you want to edit. An agent can produce a locally correct change that breaks one of these contracts.

Before implementation, identify the readers and writers of the affected data. Inspect routes, background jobs, reports, and external integrations. Check whether other teams or older client versions depend on the current behavior.

Ask the agent to show its evidence for this map. A search result is a useful starting point, but dynamic calls and external consumers may require an owner to confirm the dependency.

Make current behavior observable

For a poorly documented module, add focused checks around behavior that must remain stable. These checks describe the current contract. They do not establish that every existing behavior is desirable.

If current behavior conflicts with a requirement, record the conflict. Do not preserve a security defect merely because a test captured it. Obtain the decision needed to distinguish intended behavior from a defect.

Use realistic, non-sensitive fixtures. Include old data shapes and incomplete records where they can occur. A new schema tested only with newly created data can hide migration problems.

Review the transition between versions

Consider a fictional rename from customer_name to display_name. An immediate rename can break an old application instance during deployment. Updating both files in one pull request does not make the deployment atomic.

A staged approach can preserve compatibility:

  1. Add the new field without removing the old field.
  2. Define how new writes keep the required values consistent.
  3. Backfill existing records with a restartable process.
  4. Verify completeness and reader behavior.
  5. Move readers to the new field.
  6. Remove the old field only after its consumers are gone.

The exact method depends on the database and write patterns. Dual writes can introduce inconsistency if one write fails. A database transaction or another explicit synchronization method may be necessary. Do not apply this example without checking the system’s guarantees.

Martin Fowler describes this general transition as parallel change, also called expand-and-contract. The key idea is a compatible transition before removal.

Plan recovery separately from rollback

Code rollback restores an earlier application version. It does not automatically undo a data migration. The old version may not understand the new data. A destructive migration can remove information that a code rollback cannot recover.

Identify the recovery action for each step. A restartable backfill may be safe to resume. A wrong transformation may require a correction from preserved source data. A destructive operation may require a verified restore procedure.

Ask who owns the recovery decision and how long it can take. Avoid treating “we have backups” as evidence that the recovery meets the service requirement.

Keep the change reviewable

Separate unrelated cleanup from the functional change. Provide the compatibility plan, verification results, and removal conditions in the pull request. Mark the point after which rollback needs additional work.

An agent can help inspect consumers and prepare migration code. A responsible owner must still accept the transition and recovery plan. The final design is only one part of a safe change.

Do the exercise

Choose a small field or API change. List every reader and writer, including background jobs. Describe an additive first step, a transition check, and a removal condition. Identify which step could prevent rollback.

Download worksheet (Markdown)

Check your understanding

You rename a database column and update the application in the same release. What can still fail?

Sources & further reading

Related reading from Taiga