Safe vs breaking changes
| ✅ Usually safe (additive) | ❌ Breaking |
|---|---|
| New optional request field | Removing or renaming a field |
| New response field | Changing a type or format (string → object) |
| New endpoint | Making an optional field required |
| New enum value if clients are tolerant | Changing defaults or semantics silently |
| New error detail inside the existing envelope | New error shape or status code for an existing case |
Strategy
- Tolerant reader: clients ignore unknown fields. Document that as part of the contract.
- Version boundary: decide which versions get new behaviour and state it explicitly.
- Deprecation with data: measure who still calls v1 before you remove anything.
- Contract tests (e.g. Pact) in CI for internal consumers.
Disable Fallback Publishing was enforced in the v2 release service only. Legacy v1 releases were left unchanged, which is an explicit compatibility boundary. We also reused the existing SKIPPED status and error envelope, so no new fields, statuses or error codes were introduced. Existing clients kept working, and the new rule applied only where the product had opted in.
Sources & further learning
Videos, courses, docs and books I recommend for this topic.
Related topics
Idempotency
Doing an operation twice has the same effect as doing it once. The foundation of safe retries, at-least-once messaging and reliable APIs.
Strangler Fig Migration
Replace a legacy system incrementally — route traffic slice by slice to the new system behind a facade until the old one can be switched off.
Architecture Decision Records (ADRs) & Trade-off Thinking
Capture each significant decision — context, options, decision, consequences — so the "why" survives people leaving. Plus how to reason about trade-offs.