Chapter 15: Deprecation

seg deprecation software-lifecycle engineering-process

Status: Notes complete


Overview

Deprecation is the process of actively removing old systems, APIs, or infrastructure that are no longer needed — or replacing them with better alternatives. Chapter 15 argues that deprecation is one of the most undervalued and underfunded activities in software engineering. Most organizations invest heavily in building new systems but almost nothing in retiring old ones. The result is system accumulation: a growing graveyard of legacy systems that drain maintenance resources, confuse users, increase cognitive load for developers, and resist change.

The chapter’s central thesis is that deprecation must be treated as a first-class engineering activity — planned from the start, resourced adequately, and executed with the same rigor as building new systems. Google’s experience has shown that without intentional deprecation processes, the technical debt of legacy systems compounds until it becomes a serious drag on engineering velocity.


Core Concepts

Deprecation: The process of moving users off an old system, API, or tool and onto a newer replacement, followed by eventual removal of the old system. Distinct from simply abandoning a system — deprecation is active, not passive.

Advisory deprecation: A form of deprecation in which users are warned that something is deprecated and encouraged to migrate, but no enforcement or deadline is set. Migration is voluntary.

Compulsory deprecation: A form of deprecation in which a firm deadline is established. After the deadline, the old system is shut down or removed regardless of whether all users have migrated. Migration is mandatory.

Haunted Graveyard: A system (or set of systems) that everyone knows should be removed or replaced but that nobody is willing to touch. Fear of breakage, unclear ownership, and missing documentation make the system effectively immortal despite being obsolete.

Deprecation tax: The ongoing cost — in maintenance time, cognitive overhead, and engineering velocity drag — paid by keeping old systems alive alongside newer replacements.


Why Deprecate?

The True Cost of Keeping Old Systems

The intuition that “if it ain’t broke, don’t fix it” is dangerously misleading for software systems. An old system that appears to be running fine still imposes costs:

  • Maintenance burden: Security patches, OS upgrades, dependency updates, and hardware migrations must be applied even to systems nobody actively develops.
  • Cognitive load: Every old system is a thing engineers must understand, remember, route around, or account for when making changes to the broader platform.
  • Opportunity cost: Engineers maintaining legacy systems cannot build new capabilities.
  • Integration surface: Old systems have APIs, data formats, and behavior expectations. Newer systems must work around these, creating compatibility cruft.
  • Risk accumulation: Old systems accumulate unreviewed security vulnerabilities, undocumented behaviors, and dependencies on end-of-life infrastructure.

The economic reality is that systems do not become free to operate just because development has stopped. In fact, old systems often become more expensive over time as their dependencies age, their original authors leave, and their documentation rots.

The Hyrum’s Law Problem

Chapter 15 references Hyrum’s Law (introduced earlier in the book): “With a sufficient number of users of an API, it does not matter what you promise in the contract: all observable behaviors of your system will be depended upon by somebody.”

This means that even if an old system is nominally replaceable, users will have developed dependencies on behaviors that were never intentionally specified — and those users will break when the old system is removed. This is one of the core reasons deprecation is hard: you cannot always know in advance what you are removing.


Why Deprecation Is Hard

Technical Reasons

  1. Unknown dependencies: No matter how carefully you instrument a system, some consumers will be unknown — internal tools, one-off scripts, batch jobs that run infrequently, or legacy integrations not visible in current monitoring.
  2. Hyrum’s Law effects: Users depend on accidental behaviors, not just documented APIs. Replacing a system with a “better” one that behaves even slightly differently will break something.
  3. Data migration complexity: Old systems often have data in old formats. Migration requires schema translation, data cleaning, and often running old and new systems in parallel during a transition period.
  4. Behavioral parity: New systems must replicate not just the specification of old systems but all the edge cases and implicit contracts that users have come to rely on.

Organizational Reasons

  1. Misaligned incentives: The team that built the new system benefits from users migrating to it. But the migration work falls on the users of the old system. The users have little incentive to do migration work when the old system still works adequately.
  2. No ownership: Once a system is in maintenance mode, it is often unclear who is responsible for driving its deprecation. Without explicit ownership, nothing happens.
  3. Resource starvation: Deprecation is rarely glamorous work. It is hard to get headcount, priority, or executive sponsorship for removing something compared to building something new.
  4. Organizational memory loss: The team that built the old system may have left. The new team does not fully understand the old system’s behavior, making migration risky and slow.

Psychological Reasons

  1. Sunk cost fallacy: “We invested so much in building X — surely we should keep it running.” The sunk cost is irrelevant; what matters is the forward-looking cost-benefit.
  2. Fear of breaking things: “The old system works. What if migrating breaks something important?” This fear is rational but often paralyzing — it ignores that the ongoing cost of keeping the old system may be higher than the risk of migration.
  3. The Haunted Graveyard effect: Systems that are old, poorly documented, and not well understood generate a kind of institutional superstition: nobody wants to touch them, so nobody does, so they persist indefinitely.

Deprecation During Design: Planning for the End from the Beginning

One of Chapter 15’s most important and counterintuitive insights is that deprecation planning should begin at design time, not when deprecation becomes necessary. Every system that is built will eventually need to be deprecated. Building systems that are easier to deprecate is a form of sustainable engineering.

Design Practices That Facilitate Future Deprecation

Explicit versioning from the start: APIs with explicit version numbers can have old versions deprecated and removed without breaking users of newer versions. APIs without versioning accumulate all their users in a single dependency that cannot be removed piecemeal.

Narrow, well-specified interfaces: Systems with small, well-defined interfaces have fewer observable behaviors for users to depend on (reducing Hyrum’s Law surface area). Systems with large, loosely-specified interfaces accumulate accidental dependencies.

Usage instrumentation: Building in telemetry to track who uses what features of a system is essential for eventual deprecation. Without usage data, you cannot know which dependencies exist or which users need to be migrated.

Avoiding “just one more feature”: Systems that are nominally deprecated but keep receiving new features never actually get removed. The decision to deprecate a system must come with a commitment to freeze its feature set.

The Design Horizon

The authors recommend that engineers ask: “What would it take to deprecate this system in 3-5 years?” Answering this question at design time surfaces constraints that can be addressed cheaply early (e.g., adding versioning, reducing interface surface area) but would be very expensive to address later.


Types of Deprecation

Advisory Deprecation

In advisory deprecation, users are notified that a system or API is deprecated and that they should migrate to the replacement. No deadline is set. No enforcement is applied. Migration is entirely voluntary.

When advisory deprecation works:

  • The user community is small and well-known
  • The replacement is clearly superior and migration is low-effort
  • There is a strong trust relationship between the deprecating team and its users

Why advisory deprecation often fails:

  • Without a deadline, there is no urgency. Users rationally defer migration indefinitely.
  • “Eventually” becomes “never.” Google has observed advisory deprecations that lasted years longer than intended because no enforcement mechanism existed.
  • Advisory deprecation adds complexity (maintaining both old and new) without removing it.

Compulsory Deprecation

In compulsory deprecation, a firm shutdown date is set and communicated well in advance. After that date, the old system is turned off regardless of whether all users have migrated.

Why compulsory deprecation works:

  • It creates a deadline that converts abstract future work into concrete near-term urgency.
  • It forces the deprecated system’s users to confront their dependency and plan for migration.
  • It actually results in the old system being removed, ending the maintenance burden.

Risks and requirements of compulsory deprecation:

  • The replacement must be genuinely ready — compulsory deprecation of an old system onto a worse replacement destroys trust.
  • Communication must be early and repeated. Users who miss the notification and are broken by the shutdown are legitimate stakeholders with a grievance.
  • The deprecating team must be prepared to support users during migration.

The Advisory-to-Compulsory Pipeline

In practice, the most successful deprecation strategies combine both: begin with an advisory period to allow early adopters to migrate willingly, then transition to a compulsory phase with a firm deadline once the replacement is proven. This provides a migration runway while ensuring the old system is actually removed.


Deprecation Warnings

Deprecation warnings are a key mechanism for communicating deprecation to developers who use an API or library. Chapter 15 discusses both their design and their limitations.

Good Deprecation Warning Design

  • Point to the replacement: A warning that says “this function is deprecated” without pointing to the replacement is worse than useless — it tells the developer there is a problem without giving them the information to solve it.
  • Indicate the timeline: “Deprecated, will be removed in Q3 2025” is actionable. “Deprecated” with no timeline creates uncertainty that leads to inaction.
  • Be prominent but not noisy: Warnings that fire on every use of a deprecated API quickly become noise that developers learn to ignore. Warnings should be visible enough to be noticed but not so frequent they are tuned out.

The Limitations of Deprecation Warnings

  • Deprecation warnings only reach developers who are actively building or maintaining code that uses the deprecated API. They do not reach developers who have written code and moved on, or consumers of compiled artifacts.
  • Warnings are ineffective for systems (as opposed to APIs). You cannot emit a warning from a running service the way you can from a library call.
  • Warnings can accumulate: a codebase that has accumulated thousands of deprecation warnings has a warning problem of its own.

Managing the Deprecation Process

Process Ownership

Deprecation without explicit ownership fails. The critical failure mode is “everyone knows X should be deprecated, but nobody is responsible for making it happen.” Chapter 15 recommends:

  • A named deprecation owner: A specific person or team who is accountable for the deprecation’s completion.
  • Clear scope: The deprecation owner must know the full set of users/consumers who need to migrate.
  • Authority to enforce: In compulsory deprecation, the owner must have organizational backing to shut down the old system even over objections from users who have not yet migrated.

Milestones and Progress Tracking

Deprecation is a project that requires project management. Key milestones:

  1. Announcement: Public communication that deprecation is planned, with timeline.
  2. Replacement readiness: The replacement is feature-complete and validated.
  3. Migration support period: Users can migrate with assistance from the deprecating team.
  4. Enforcement: Warnings become errors, or access is restricted.
  5. Shutdown: The old system is removed.

Progress should be tracked quantitatively: “X% of users have migrated” is a meaningful metric that creates accountability and allows the deprecation owner to focus effort on the remaining blockers.

Deprecation Tooling

At Google’s scale, manual deprecation tracking is insufficient. The chapter describes tooling approaches:

  • Static analysis: Tools that flag uses of deprecated APIs in the codebase and can generate migration diffs automatically.
  • Usage dashboards: Real-time visibility into which teams/systems are still using the deprecated system.
  • Automated migration: For structured, rule-based migrations (e.g., renaming a function), automated code transformation tools can migrate entire codebases at once.

The Haunted Graveyard Anti-Pattern

The Haunted Graveyard is one of the book’s most vivid anti-patterns. It describes a collection of systems (or a single critical system) that everyone knows should be removed or updated but that nobody is willing to touch:

  • The original authors have left
  • The documentation is incomplete or inaccurate
  • The system is poorly tested
  • Nobody fully understands its behavior
  • Attempts to change it have broken things in the past
  • It has dependencies that are themselves undocumented

The result is a system that exists in a state of institutional superstition: engineers believe terrible things will happen if they disturb it, so they work around it instead of addressing it. This compounds over time — more workarounds accumulate, the system becomes more entangled with the rest of the codebase, and the cost of eventually removing it grows.

How Haunted Graveyards Form

  1. A system is built, works, and then enters maintenance mode.
  2. The original team moves to other projects; ownership becomes diffuse.
  3. The system is not actively developed, so documentation and tests are not maintained.
  4. Knowledge of the system’s behavior becomes concentrated in a few people who eventually leave.
  5. Attempts to modify the system break things, confirming the fear.
  6. Engineers begin routing around the system rather than through it.
  7. The system’s actual function becomes unclear — is it still needed? By whom?
  8. The system becomes too scary to touch, let alone remove.

Preventing Haunted Graveyards

  • Never let a system become undocumented: Active maintenance of documentation, especially as authors rotate off, is essential.
  • Maintain test coverage: Systems with good test coverage are safer to modify and understand.
  • Explicit deprecation planning: Systems in maintenance mode should have an explicit deprecation plan, not an indefinite future.
  • Proactive ownership transfers: When a team changes, explicit ownership of all systems (including legacy ones) should be transferred and documented.

Incentive Problems in Deprecation

Chapter 15 spends significant time on the structural incentive problems that make deprecation difficult even when everyone agrees it should happen.

The Benefit-Cost Mismatch

The primary incentive problem:

  • Who benefits from deprecation? The platform/infrastructure team that removes the old system: reduced maintenance burden, simplified architecture, freed engineering capacity.
  • Who bears the cost of migration? The users of the old system: engineering time spent migrating, risk of breakage, opportunity cost of not building new features.

This mismatch means that rational actors will resist migration even when the total system-wide benefit is large. The deprecating team has to do more than just make migration possible — they have to reduce the cost to migrators or provide direct assistance.

Solutions to Incentive Problems

Provide migration assistance: The team deprecating a system should be prepared to do some or all of the migration work for users. This shifts the cost burden to the team that benefits most from the deprecation.

Remove the option to stay: Compulsory deprecation with a hard deadline removes the option of indefinitely deferring migration. When the old system will not be available on a given date, the migration must happen.

Align organizational incentives: Treat “migrated off deprecated system” as a positive metric in team performance reviews. Make the deprecation work visible and valued.

Leadership support: Deprecation of large, widely-used systems requires explicit leadership support. Without top-down backing, user teams will always find higher-priority work.


Google’s Approach: Deprecation as Engineering

Google has institutionalized a number of practices that treat deprecation as a normal, funded, resourced part of the engineering process:

  • Deprecation is explicitly resourced: Teams that own infrastructure are expected to fund deprecation work, not just new development.
  • Deprecation is tracked at the organizational level: Large deprecations are tracked in engineering-wide roadmaps, not just in team backlogs.
  • Code owners are responsible for migrations: When an API is deprecated, the owning team is expected to either provide automated migration tools or do the migration for dependent teams.
  • “No new code in deprecated APIs”: Once deprecation is announced, new code cannot be written against the deprecated API. This prevents the migration problem from growing while the existing migration work is in progress.

TL;DRs

(From the book’s Chapter 15 TL;DRs)

  • Code is a liability, not an asset. The more code in your system, the more you have to maintain.
  • Every system that is built will eventually need to be deprecated. Plan for this from the start.
  • Deprecation is hard for technical, organizational, and psychological reasons. Treat it accordingly.
  • Advisory deprecation rarely works at scale. Compulsory deprecation with deadlines is more effective.
  • Deprecation requires explicit ownership, clear milestones, and organizational support to succeed.
  • The Haunted Graveyard is the failure mode of systems that are never properly deprecated.
  • Hyrum’s Law makes deprecation harder than it appears: users depend on behaviors you never intended to provide.
  • The team deprecating a system should expect to do migration work, not just announce the deprecation.
  • Build systems that are easy to deprecate: narrow interfaces, explicit versioning, usage instrumentation.

Key Takeaways

  1. Code is a liability: Every line of code must be maintained, debugged, and eventually removed. The more code, the higher the maintenance burden — even code that is “done.”
  2. Deprecation must be planned at design time: Systems built without deprecation in mind accumulate invisible dependencies and accidental contracts that make eventual removal far more costly.
  3. Advisory deprecation fails at scale: Without deadlines and enforcement, rational users defer migration indefinitely. Compulsory deprecation with firm shutdown dates is the mechanism that actually achieves removal.
  4. The Haunted Graveyard anti-pattern arises when systems are never formally deprecated — they become undocumented, poorly understood, and feared, making them effectively immortal.
  5. Hyrum’s Law is the technical root of why deprecation is hard: every observable behavior of a widely-used system will be depended upon by someone, even behaviors that were never specified or intended.
  6. Incentive misalignment is the organizational root of why deprecation is hard: the team that benefits from removal is not the same as the team that must bear the cost of migration.
  7. Explicit ownership is the single most important process factor: deprecation without a named, accountable owner will not happen.
  8. Migration assistance is the most effective way to overcome user resistance: when the deprecating team does the migration work, the cost-benefit calculation changes for users.
  9. Deprecation tooling — static analysis, usage dashboards, automated migration — is necessary at scale to track progress and reduce migration cost.
  10. “No new code in deprecated APIs” is a discipline that prevents migration debt from growing while existing migration work is in progress.

  • ch16-version-control-and-branch-management — Version control as the infrastructure that makes large-scale deprecation and migration work tractable
  • ch14-larger-testing — Testing is essential for deprecation safety; systems without tests cannot be safely migrated
  • DDIA Chapter 4 (Encoding and Evolution) — The technical challenges of schema evolution parallel the deprecation challenges described here

Last Updated: 2026-06-02