Back to blog
Article

When a rewrite is the right call, and when it is not

When a rewrite is the right call, and when it is not
S

StriveBit

5 min readField Notes

When a rewrite is the right call, and when it is not

A client in Noida asked us to look at a Django monolith their previous vendor had built over three years. The codebase had 47 apps, no test suite, and a migration history that had been squashed twice without anyone recording what the squashes resolved. Deployments took 45 minutes because the build step ran a full data migration on every push. The previous vendor had left eight months ago. No one on the client side could explain why the billing module calculated tax the way it did.

We spent two weeks reading the code before we recommended a rewrite. That recommendation came with a specific reason: the cost of understanding the existing code exceeded the cost of writing a replacement. We could prove this because we had tracked the hours. In two weeks we had fully understood four of the 47 apps. At that rate, mapping the rest would take five months before we could write a single new feature. A rewrite, scoped to the six apps the business actually used, was a three-month job.

That calculation is the only honest basis for a rewrite. You do not rewrite because the code is ugly. You rewrite because the effort to safely modify the existing code is demonstrably greater than the effort to replace it.

The far more common case is the opposite. A manufacturing client in Greater Noida asked us to "modernize" a PHP application that ran their inventory and purchase orders. The code was procedural PHP 5.6, written in 2017, with no framework. Every page was a single file that mixed SQL, HTML, and business logic. By any aesthetic measure, it was a mess.

But it ran their warehouse correctly. The purchase order workflow matched how their store manager actually thought about stock. The reporting queries, buried inline in PHP, produced numbers their accountant had verified against Tally for four years.

We did not rewrite it. We upgraded PHP to 8.2, which took a week of fixing deprecated function calls and mysql\_ extensions. We extracted the database layer into a single include file so that the connection logic lived in one place. We added a migration tool — Phinx — and created an initial migration that represented the current schema. Then we started pulling the most-modified pages into a lightweight routing setup, one at a time, as the client requested changes.

The client spent roughly 40 hours of our time. A rewrite would have been 400. The system kept working through the transition. The store manager did not have to learn a new interface. The accountant's verified numbers did not change.

The temptation to rewrite usually comes from a specific feeling: the code is hard to read, therefore it must be hard to maintain, therefore it should be replaced. That syllogism breaks at the second step. Code can be hard to read and still be cheap to maintain if the changes you need are small and infrequent. A 2017 PHP file that the client touches twice a year does not need to become a React frontend with a Laravel API. It needs to keep running, and it needs to accept the occasional small change without falling over.

There is a middle case we see often enough to name. A client has a working application but a broken deployment. The code is fine; the pipeline is not. They have no CI, no staging environment, deploys happen over FTP, and the last person who knew the server password left. This is not a rewrite problem. It is an infrastructure problem. We containerize the application, set up a CI pipeline, create staging and production environments, and document the deploy process. The code stays. The way it ships changes.

We treat rewrites the way we treat surgery: avoidable unless the alternatives are worse, and the alternatives are usually worse only when you can measure it. The measurement does not need to be precise. But it needs to exist. "The code feels old" is not a measurement. "We spent 80 hours last quarter fixing bugs in the authentication module, and the module has 600 lines" is a measurement. The first does not justify a rewrite. The second might.

When a client asks us whether they should rewrite, we ask them to let us spend a week in the code first. Sometimes we come back with a rewrite recommendation, as we did with the Django monolith. More often we come back with a list of specific fixes that cost a fraction of a rewrite and address the actual pain. The pain is rarely "the codebase is old." The pain is usually a specific bug, a slow page, a feature that takes too long to ship, or a deploy that breaks at 2am. Those have targeted solutions. A rewrite is a targeted solution for exactly one problem: the code is more expensive to understand than to replace.

Back to all articles

Ready to build something great?

We help ambitious teams build software that lasts. If you're interested in working with us or want to discuss your project, let's connect.

Get in touch