practice

Refactor and Re-architect

Changing the application's structure — the most expensive migration strategy, justified only where the structure itself is the constraint.

refactorrewritemodernisationincrementalrisk

Definition

Refactoring changes internal structure without changing behaviour. Re-architecting changes the structure at a system level — decomposing a monolith, replacing a data model, moving to an event-driven design.

When it is justified

Only when the structure itself is the binding constraint:

  • Change cost is high and rising, evidenced by lead time in that area.
  • A component's resource profile is fundamentally incompatible with the rest.
  • A regulatory or residency requirement cannot be satisfied by the current structure.
  • The technology is at end of life with no upgrade path.

"It is old" and "it is not how we would build it now" are not justifications. Working, supported, low-change systems should be left alone.

Incremental, never big-bang

Rewrites of long-lived systems fail at a well-documented rate, for structural reasons rather than incompetence:

  • The requirements exist only in the code's behaviour, including behaviour nobody intended and some customer now depends on.
  • The business does not stop changing, so the new system chases a moving target while the old must still be maintained.
  • No value lands until the end, so the project is cancellable for its entire duration and receives no corrective feedback.

The incremental alternative — strangler fig — inverts all three: value lands progressively, each slice is validated in production, and the work can be paused in a stable state.

The sequence that works

  1. Insert a routing facade, everything still pointing at the existing system. A no-op release that proves the routing, observability and rollback.
  2. Extract one capability, chosen for learnability rather than importance.
  3. Run both and compare for read paths — serve the old result, log the differences. This is the only reliable way to discover undocumented behaviour, and it will find dozens of cases.
  4. Move the data with the capability, or accept the old system as system of record with a defined synchronisation.
  5. Repeat, and decommission as you go.

The characteristic failure

The migration that never finishes. The last 20% — rare capabilities, batch jobs, reports, partner integrations — is the hardest. Funding runs out and the organisation permanently operates two systems, which is strictly worse than either alone.

Guard against it: budget decommissioning as explicit work, and track "capabilities remaining on legacy" as the primary metric rather than capabilities delivered on the new system.

Interview question

"When would you re-architect rather than replatform, and how would you sequence it?"