Backward Compatibility Review

A backward compatibility review evaluates whether existing users and integrations can continue to rely on a system after a change. It examines observable behavior and plans a migration when an established contract must change.

A backward compatibility review checks whether a proposed change preserves the contracts that current users and integrations rely on. Those contracts may include Python function signatures, HTTP endpoints and payloads, database schemas, event formats, command-line behavior, and documented error handling.

Start by identifying consumers and the behavior they can observe. Check both explicit interfaces and relied-upon behavior, such as response field meanings, ordering assumptions, default values, and timing or retry expectations where relevant. Tests, API specifications, changelogs, and usage searches can help reveal dependencies, but they may not capture every external consumer.

Assess the change from the consumer's perspective: can existing code still call the interface, parse its output, and interpret the result as before? An additive field may be compatible with tolerant clients but break clients that reject unknown fields. A renamed field, changed default, tightened validation rule, or altered status code can break consumers even if the implementation remains internally correct.

When a change cannot preserve the old contract, consider a staged migration: introduce a replacement, support both forms temporarily, communicate a deprecation timeline, and remove the old behavior in a planned breaking release. Compatibility is contextual, so state assumptions about consumers and protocol guarantees rather than treating any category of change as universally safe.

Key points

Interview questions

Can a change be breaking even when a function's signature stays the same?

A function can remain callable while violating a behavioral contract. For example, it might still accept the same arguments but return results in a different order or raise a different exception for an established input. I would review semantics and edge cases, not just names and types. Tests that assert externally visible behavior help make those expectations explicit.

How do you conduct a backward compatibility review?

I would first identify the affected contract and its consumers, including external clients and internal services. Then I would compare observable behavior before and after the change: signatures, payload shape, defaults, errors, and persistence or event formats. I would check tests and specifications, while noting that undocumented consumers may exist. If the change is breaking, I would propose a migration path such as supporting both forms temporarily and communicating a deprecation deadline.

Is adding a field to a JSON response backward compatible?

Not necessarily. A client that ignores fields it does not recognize may continue to work, while a strict schema validator or generated model may reject the added field. I would check the client contract and validation behavior, then test representative consumers. The review should describe the assumption that makes the addition safe rather than labeling it universally compatible.

Why can changing a default value be a compatibility break?

Changing a default can change results for callers that omit the parameter, even though their code still runs. I would search for omitted-argument usage, establish the old and new behavior, and determine whether the default is part of the supported contract. If the new behavior is required, a new explicit option or a staged deprecation may avoid silently changing existing callers.

How would you make a database schema change compatible with a rolling deployment?

A safe database migration generally follows expand-and-contract. First add the new structure in a way that works with both old and new application versions, then deploy code that can use it and migrate data as needed. After verifying that old readers and writers are gone, remove the obsolete structure in a later step. This reduces risk during rolling deployments and makes rollback more practical.