Every aging system eventually gets the same three options put in front of it: rewrite it, wrap it, or retire it. I have watched teams reach for rewrite first, because it is the most interesting of the three, and I have come to think that is usually the wrong order. Here is the order I use instead.
First: is the behavior still wanted
Before anything else, I ask whether anyone still needs what the system does. Not whether anyone uses it, which is a different question with a less flattering answer, but whether the behavior would be rebuilt if it vanished tomorrow.
Old systems accumulate features the way a garage accumulates boxes. Some of them were last opened a decade ago. If a meaningful share of the behavior is unwanted, retirement of that share is the cheapest modernization available, and it makes every other option smaller. I think retire deserves far more consideration than it gets, and it should be considered first, not as a last resort.
Second: can a boundary be drawn
If the behavior is wanted, I ask whether a boundary can be drawn around the system. Can it be put behind an interface that the rest of the world talks to, so that what happens inside stops mattering to anyone outside.
When the answer is yes, wrapping is my default. The old system keeps running, the new interface is what everything else depends on, and the question of what to do inside the boundary becomes a question the team can answer later, piece by piece, with real usage data. Wrapping also has the property I value most: it can be stopped halfway and still have been worth doing.
When the answer is no, because the system's tendrils reach everywhere and no interface can be drawn, that is itself important information. It usually means the system is less a component than an environment, and a rewrite of an environment is a multi-year program, whatever the estimate says.
Third: is the knowledge recoverable
Only then do I ask about rewriting, and the question is not whether the team can write the new code. It is whether anyone still knows what the old code does and why. Behavior that exists because of a customer problem in 2014 is not in the documentation, and often not in anyone's head.
A rewrite reproduces what the team understands. Everything else is lost, and discovered later by the people who depended on it. If the knowledge is recoverable, through tests, logs, or people who were there, a rewrite can be scoped honestly. If it is not, I think the honest estimate for a rewrite is unknowable, and a team that proceeds anyway is choosing to find out in production.
Why the order matters
Asked in this order, the questions shrink the problem at each step. Retiring what is unwanted makes the boundary easier to draw. Drawing the boundary makes the rewrite, if there ever is one, a series of small rewrites behind a stable interface instead of one large bet.
Asked in the other order, starting with rewrite, the questions never get asked at all. The rewrite becomes the plan, the plan acquires a date, and the date becomes the thing everyone defends. I have seen enough of those to prefer the boring order.
Photo source: https://photos.robertstowe.com/cumberland-island
