← ALL POSTS
CUSTOM SOFTWARE EXPLAINER

Rescuing legacy software: modernize without the rewrite

Somewhere in your business there's a piece of software everyone is afraid of. Maybe it's a custom system built twelve years ago by a developer who's long gone. Maybe it's an Access database that grew into a monster, or a Visual Basic app running the warehouse. It still works, mostly, which is exactly why it never got replaced. But it only runs on one aging machine, nobody understands the code, and every year it gets harder to hire anyone willing to touch it.

The standard advice is "rewrite it from scratch." We want to talk you out of that, or at least out of doing it the usual way.

Why full rewrites usually fail

The big-bang rewrite has a predictable life cycle. It gets scoped at six months and takes two years, because the old system contains a decade of accumulated business rules nobody wrote down: the special pricing for that one customer type, the workaround for the tax edge case, the report the bank requires in exactly that format. The old code is the only complete documentation of how your business actually works, and every one of those rules has to be rediscovered, usually by shipping the new system without it and hearing about it from an angry user.

Meanwhile, the business doesn't stop. New requirements land in the old system while the new one chases a moving target. Budgets run out at 80% done, which in software means the hard 20% never happens. We've been called in to clean up after more than one of these, and the common thread is always the same: everything was bet on a single cutover day that kept sliding.

Rewrites can succeed, but they succeed when they're small, well documented, and lucky. That's not a plan.

The alternative: incremental rescue

The approach that actually ships is to replace the system piece by piece while the old one keeps running. The pattern has a name, the strangler fig pattern, after the vine that grows around a tree until it eventually stands on its own. In practice it looks like this:

Step one: stabilize what exists

Before improving anything, stop the bleeding. Get the code into version control if it isn't. Get the old system running on hardware or a virtual machine that isn't one power surge from disaster. Set up real backups and test a restore. Document how to build and deploy it, even if the process is ugly. None of this is glamorous, and all of it buys you time to do the rest without a gun to your head.

Step two: put a wrapper around it

Most legacy systems have one saving grace: their data is in a database. Even if the code is untouchable, you can usually build a thin API layer that reads and writes that data safely. Suddenly the old system can talk to modern things: your website, a mobile app for field staff, a reporting dashboard, an integration with QuickBooks. The legacy core keeps doing what it does; the wrapper gives it a future. This step alone often delivers most of what people wanted from the rewrite.

Step three: peel off pieces

Now replace the system one function at a time, highest pain first. Reporting is often the best first candidate: build new reports against the same database and retire the old ones. Then maybe the customer-facing piece, then invoicing, then scheduling. Each piece is a small project with its own budget and its own finish line. Users move over gradually. If a new piece has problems, you fall back to the old one for that function, not for everything.

Step four: retire the core, eventually

After enough pieces move out, what's left of the old system is small enough that replacing it is a normal-sized project instead of a moonshot. Some businesses never fully get there, and that can be fine. A stable, backed-up legacy core doing one boring job behind an API is not a crisis. It's just old, like a building with good bones.

What this costs and how long it takes

Incremental rescue usually costs about the same as a rewrite in total, sometimes a bit more. The difference is when you get value. A rewrite pays out nothing until the end, if the end comes. The incremental path pays out at every step: stabilization removes the disaster risk in weeks, the API wrapper unlocks integrations in a month or two, and each replaced piece improves daily life immediately. You can also stop at any point and keep everything you've gained. Try stopping a rewrite at 60% and see what you have.

How to know it's going right

The old system gets more boring every quarter, not more terrifying. There's a current backup you've actually restored from. New features get built in new code against the wrapper, never bolted onto the legacy core. And nobody is waiting for a big cutover day, because value has been shipping the whole time. If the plan you're being pitched has a single go-live date eighteen months out, ask harder questions.

Stuck on this, or want it done for you? That's the job.

Email us →
RELATED READING
Python: the duct tape of business automation Explainer
Send SMS and email alerts from your app Step-By-Step Guide
Adding AI to your app without the hype Explainer
Build a REST API with Node.js and Express Step-By-Step Guide
Native, React Native, or just a good website? Explainer
NO FORMS. JUST EMAIL.
mason@hurbs.io
or (832) 457-4317, LA and Houston