“Temporary” has settled in.
A system grew over the years. A special case was added, then a new sales channel, then an import whose format nobody was allowed to change. Today the code looks the part. That’s annoying, but it doesn’t yet tell you which part should be replaced.
The old system often holds knowledge about how the business really works. An odd-looking condition may protect a process nobody else remembers. Remove it and you have less code at first. Whether you also have fewer problems becomes clear later.
First check what’s load-bearing.
We start with the processes people rely on. What has to work reliably? Where do errors come from? Which dependency is blocking a change? Answering that means talking to the people who use and run the system as much as reading the code.
For critical behaviour we write verifiable examples and tests. A special rule may be questioned. It just shouldn’t disappear by accident.
A good boundary is a start.
If a part can be separated cleanly, it can be renewed on its own. An interface gets a clear contract. A slow process is measured and reworked. A dependency is replaced without reinventing the whole application at the same time.
Every step needs an answer to two questions: how do we know it works, and how do we get back if it doesn’t? A small rollout with a tested way back is a far more pleasant appointment than a big one with fingers crossed.
And sometimes it really does need rebuilding.
If the architecture permanently blocks the changes you need, or core dependencies can no longer be run sensibly, a rewrite can be the right decision. In that case we want to understand the scope, the migration and the handover into operation beforehand.
We judge by what improves for your system and your team: reliability, how easily it changes, runtime or operating effort. “Now with a new framework” doesn’t answer that question.
Your system has a few stories to tell?
We’re listening