Refactoring a legacy business system without stopping the business

Refactoring a legacy business system without stopping the business

When we took this system over, its state was typical: it ran, but nobody dared change it. Business logic scattered across page files, missing constraints in the database, no tests, deployment by manual copy.

We did not rewrite it. The business cannot stop, and a rewrite means a long double-track period — riskier than the debt itself. The plan was incremental refactoring: grow a new structure on the outside, then migrate the old logic into it one layer at a time.

Step one was stopping the bleeding: unify database connections and exception handling, pull the scattered raw SQL into a data access layer, and kill the change-one-place-break-three pattern.

Step two was layering: extract a service layer to own the business rules, leaving pages to handle rendering and input validation only. After this step, business logic finally had a single address.

Step three was constraints and security: add indexes and foreign keys to the critical tables, standardise password storage on PBKDF2 hashing, and put every endpoint behind unified authentication.

The rule that mattered most: every step had to ship. We moved weekly, deployed to production every week, and the business never noticed. Six months later, the maintainability of the system was in a different league.

← Back to the journal