CodeCrafting All articles
Build & Delivery

A Small Sign Before the Skip: Retiring Code Without Losing Its Story

CodeCrafting
A Small Sign Before the Skip: Retiring Code Without Losing Its Story

Photo: Юрий Д.К., CC BY 4.0, via Wikimedia Commons

Most code removals begin with a confident search and end with a tidy pull request. Tests go green, the build stays clean, and everyone moves on. A few months later someone asks why a once-important function existed, who relied on it, or what replaced it. The only remaining answer is a commit hash and a vague memory of a Friday afternoon.

Deprecated code has a habit of vanishing without a story. That is fine for a typo fix. It is less fine for a VAT calculator, an address parser, or the odd little adapter that kept an old payment provider alive. The blue plaque test is a small way to slow that forgetting down.

Borrow the sign, not the ceremony

The London blue plaque scheme has marked the homes of notable people since the 1860s. Whatever you think of the choices, the idea is sound: a short, public note that says this place mattered, and here is why. Code can use the same trick without becoming a museum.

A blue plaque for code is not a long comment block. It is a compact marker attached to anything you intend to retire. It answers four questions: what was this for, where should callers go instead, who owns the migration, and when should someone review the decision. If a new starter can find those answers from the code or the pull request, the plaque has done its job.

Four lines, not a memoir

Keep the marker short enough that people will actually write it. Long explanations rot quickly and nobody reads them. A working shape might look like this:

@deprecated Use calculateVat from billing/tax instead.
Original purpose: legacy invoice rounding for the old billing flow.
Migration route: see docs/migrations/invoice-rounding.md
Owner: billing-platform
Review by: 2027-03-31

That example is deliberately plain. The exact syntax matters less than the habit. In Java, use the deprecation tag and annotation. In Python, raise a warning in the right place and document the replacement. In TypeScript, a JSDoc deprecation note will show up in the editor. Go has a convention for deprecation comments. .NET has Obsolete. The point is not to pick a favourite tool. The point is to put the sign where a developer will trip over it while trying to use the thing.

Avoid writing a plaque that says only legacy. That is not a plaque. It is a shrug. If nobody can remember the original purpose, say that, name the person or team most likely to know, and open a small issue to recover the story. An honest plaque with a gap is better than a confident fiction.

Put the sign where people actually look

A comment in a file is useful only if someone opens the file. Most callers will meet the deprecated code through autocomplete, a compiler warning, or a failed build. So repeat the sign in the places that matter: the API reference, the package README, the migration guide, and the lint message. A short line in the lint output saying use X instead, see docs/migrations/foo.md is worth more than a paragraph buried three directories away.

For libraries and internal platforms, add the plaque to the public documentation as well. UK teams often maintain systems for years across reorganisations, supplier changes, and the quiet replacement of one team by another. The next maintainer may not have been in the room when the decision was made. They will, however, see the warning in their editor.

A small register beats a big policy

A register sounds like bureaucracy. Keep it small enough to survive. A Markdown table in the repository is enough:

Deprecated item Replacement Owner Review by Tracking issue
oldVatRound billing/tax.calculateVat billing-platform 2027-03-31 #1842
AddressLine2 parser address/parse identity 2027-01-15 #1910

The register is not the source of truth for every line of code. It is a visible queue of promises. Review it in the same meeting where you look at dependency updates or flaky tests. If an item has no owner, it is not ready to be deprecated. If it has no review date, it will sit there until someone builds a new feature on top of it.

Let the build enforce the signpost

Good intentions fade. A lint rule does not. Add a rule that flags new uses of the deprecated API. In many codebases you cannot fail the build for every existing call on day one, so start with a baseline: warn on old usages, fail on new ones, and shrink the baseline over time. That is the same pattern many teams use for accessibility checks and dependency warnings. It keeps the build clean without pretending the problem is solved.

Make the lint message point to the migration route. A warning that says do not use this is just noise. A warning that says use calculateVat instead and links to a two-minute migration note is an invitation.

Set a review date, not a demolition order

A removal date can be useful, but it can also become fiction. A better label is review by. On that date, the owner does one of two things: remove the code, or renew the plaque with a reason and a new date. Renewal is allowed. Life happens, migrations stall, and a supplier integration takes longer than the diagram suggested. What is not allowed is letting the date pass in silence.

This is where the practice connects to maintenance budgets. Retiring code is work. It needs a slot in the sprint, not just a hopeful note in a backlog. The plaque makes that work visible before it becomes an emergency.

Commemorate, then clear the site

Once the last caller is gone, remove the code, update the register, and keep the migration note where future readers can find it. The plaque is scaffolding around deletion, not a permanent exhibit. The aim is not to preserve every old function. The aim is to make sure that when the skip arrives, someone can still explain what used to stand there.

So before you delete that strange little adapter, put up a small sign. Four lines, a register entry, and a lint warning will do more for your future team than another heroic act of tidying up.

All Articles

Related Articles

The Boundary Moved, the Report Didn't: Modelling UK Places Over Time

The Boundary Moved, the Report Didn't: Modelling UK Places Over Time

Checked, Dated, Stuck On: A Maintenance Tag for Every Dependency

Checked, Dated, Stuck On: A Maintenance Tag for Every Dependency

Give Way, Not Guesswork: Signposting Your API Like a British Junction

Give Way, Not Guesswork: Signposting Your API Like a British Junction