Every tutorial, bootcamp, and sprint ritual is built to teach one direction: how to add. Ship the feature, launch the thing, get it live. Almost nothing teaches the opposite motion — how to remove something people already depend on — and that motion is harder, riskier, and more revealing of seniority than anything else on the roadmap.
This isn’t the same as killing your favorite feature: the private act of deciding something you love isn’t earning its keep. That’s a judgment you make looking inward. Deprecation is what happens next, out in the world, when the thing you’re removing is load-bearing for someone else. The decision was the easy half. The craft is in the handoff.
What makes it hard is the implicit promise. Every feature you ship quietly says: this will keep working. People build habits, workflows, and sometimes their own products on top of that promise. There’s a useful adage in software — Hyrum’s Law — that with enough users, every observable behavior of your system will come to be depended on by somebody, whether or not you ever documented it. Which means a deprecation is never just deleting code. It’s revoking a promise, and the only real question is whether you revoke it well or badly.
A good deprecation has a shape, and the shape is almost always an overlap, never a cutover. You announce — with a reason, a replacement, and a date, in that order of importance, because “we’re removing X” lands very differently from “here’s what to use instead, and here’s why.” You stop the bleeding by closing the thing to new users first while leaving it running for the people already on it. You open a window where old and new both work, so nobody has to leap a gap. And only then do you sunset — and even then you leave a marker where the thing used to be, pointing at the replacement, rather than letting it vanish and betting people won’t notice. (They notice. A silent removal is just change blindness turned against the users who trusted you.)
The instinct, when deciding what to pull, is to count. Only 2% of users touch this, so it’s safe to remove. But usage volume is the wrong meter. The right one is dependence — how badly do the people who use it need it, and how hard is their escape. The loud minority who complain are often your most invested users, the ones who built the most on your promise, which is exactly why they’re loud.
It helps to treat the steps as a series of doors, most of them two-way. Closing a feature to new signups is easily reversible. Hiding it is reversible. Deleting the data behind it is not. So sequence the reversible moves first and buy yourself information before you walk through the one door you can’t walk back.
The reason deprecation reads as senior isn’t that it’s technically hard. It’s that it forces you to hold two things at once: the health of the product, which wants less surface area, and the trust of the user, which wants the ground to stay solid underfoot. Juniors optimize one and discover the other in the support queue. What marks someone who’s done this before is a removal that leaves users feeling guided rather than abandoned — same deletion, opposite memory.
A roadmap full of additions is a product accumulating promises it will someday struggle to keep. Learning to take one back cleanly — with a reason, a path, a window, and a marker — isn’t the sad part of the job. It’s the part that keeps the rest of the promises worth making.
Sources
- Hyrum's Law on implied dependencies
- the expand-and-contract (parallel-change) migration pattern
- one-way vs. two-way-door decisions
Liked this? Get the next one in Working Theory.
Going weekly in August (it's in beta now). One genuinely interesting read on building, the brain, and the science most people missed.
Subscribe →