Legacy modernization without the big rewrite
Legacy modernization with the strangler fig pattern: why big-bang rewrites fail, why the shared database is the real project, and when to cut over.
Sergio
CEO, DGTL
Somewhere in your company there's a system nobody wants to touch. It's 10 to 20 years old, written in .NET, Java, or PHP, it runs orders, billing, or the back office, and the people who knew it best have left. Someone will propose rewriting it from scratch.
Don't. Replace it piece by piece, and plan the database before anything else. (For a young, mostly AI-written codebase, read refactor versus rebuild instead.)
Why do big-bang rewrites of legacy systems fail?
Because the old system's behavior is the only complete specification, and nobody has read all of it. Martin Fowler's 2024 essay on the strangler fig pattern is blunt: "Replacements seem easy to specify, but often it's hard to figure out the details of existing behavior." On rebuilding everything at once: "we've seen this simple-sounding plan go down in flames most of the time."
Two forces do the damage. One is time: the business can't freeze while the system is replaced, and AWS's prescriptive guidance (vendor documentation) notes that during a big-bang migration it's "extremely hard or even impossible to add new features." The other is parity. In their Patterns of Legacy Displacement series (2021), Thoughtworks technical directors Ian Cartwright, Rob Horn, and James Lewis describe rewrites that promise to do exactly what the old system did: "Workarounds for past bugs and limitations have become 'must have' requirements." A team can "deliver 80% of individual process steps but still be unable to complete the whole business process."
These are practitioner essays, not studies. Our read: a rewrite gets the rules everyone remembers and breaks on the ones nobody wrote down, like a customer's special rounding rule or the month-end job that quietly fixes yesterday's data.
What is the strangler fig pattern?
The strangler fig pattern replaces a legacy system one piece at a time while it keeps running. A facade, usually a proxy or API gateway, sits in front of the old system and routes each request to the legacy code or to its new replacement. As pieces move, more traffic goes to the new system, until the old one serves nothing and you switch it off. Fowler named it after rainforest figs that grow around a host tree and replace it.
Microsoft's Azure Architecture Center guide (vendor documentation, updated in 2026) adds three conditions. The facade can't become a single point of failure or a bottleneck. Where old and new code still call each other, an anti-corruption layer translates so legacy conventions don't leak into the new design. And the pattern may not fit if you can't intercept requests or change the legacy source.
Most write-ups stop at the facade. That's the easy part.
Why is the database the hard part of legacy modernization?
Because in a 15-year-old system, the database is the integration layer. Business rules live in stored procedures, reports query tables directly, and someone in finance has a spreadsheet wired straight to production. Move the invoicing code behind a new service and you haven't moved invoicing: everything else still reads and writes the invoice tables.
Microsoft's guide agrees: "Legacy systems typically depend on a centralized monolithic database that serves multiple domains." Its database example moves one domain at a time. Here it is, with our additions.
How do you move one domain's data without stopping the business?
- Inventory every reader and writer first. Before routing anything, list everything touching the domain's tables: code, stored procedures, triggers, reports, BI extracts, integrations, spreadsheets. Query logs and database auditing catch what a code search misses. This is your cutover checklist.
- Route first, move data later. The new service takes over the domain's requests but still reads and writes the legacy tables. If something breaks, flip the route back.
- Copy, then sync. Load history into a new domain database with a one-off ETL, then keep it current with change data capture (CDC), which reads changes from the legacy database's transaction log. The legacy database stays authoritative.
- Reconcile, in writing. Microsoft says to validate consistency before cutover; make it a daily report: row counts, totals by account and day, a field-by-field check of a sample. Agree with finance on what "matching" means, and don't cut over until the report stays clean through at least one month-end close.
- Cut over, with a way back. The new domain database becomes the system of record, and legacy readers you haven't moved get fed by a sync in the other direction. AWS warns that this kind of sync leaves the stores eventually consistent and recommends treating it as tactical, so give it an end date.
- Name the point of no return. Dropping the legacy tables and procedures is hard to undo: rolling back means restoring those objects and replaying data changes, which Microsoft says "significantly increases effort and risk." Its advice: "Treat the removal of legacy objects as a deliberate final step for each domain." Put a date on it, name who signs off, and confirm the step 1 inventory shows no remaining readers.
Repeat per domain. This loop is the project.
Which domain should move first?
One with a clear seam, few writers, and a feature the business is waiting for: it proves the method and earns the next round. Skip the general ledger and the lookup table that teaches you nothing. AWS warns that premature decomposition can be costly when the domain isn't clear, because you can get the boundaries wrong. If you can't draw it on a whiteboard, don't move it yet.
Does .NET 8 end of support change the plan?
If you run .NET 8 or 9, it changes the order. Microsoft's .NET support policy, checked in October 2026, lists November 10, 2026 as end of support for .NET 8 (LTS) and .NET 9 (STS), with .NET 10 (LTS) supported until November 14, 2028. From November 10, Microsoft will ship no more fixes or updates for either. The date doesn't apply to .NET Framework 4.8.1, which stays supported as long as it runs on a supported version of Windows.
Verizon's 2026 Data Breach Investigations Report, vendor research covering more than 22,000 confirmed breaches worldwide from November 2024 through October 2025, found 31% of them started with a software vulnerability, ahead of stolen passwords. That's all software, not just .NET, but software you can't patch is an open door.
Our read: a runtime upgrade is maintenance, not modernization, and it shouldn't wait for one. Move to a supported version first, then strangle the system on your own schedule. A rewrite started under a support deadline is the big bang again, with less time.
Who owns which part of a strangler fig migration?
It's one project across four practices. Build runs the facade, the new services, and the adapters between them. Data runs the hardest part: CDC, reconciliation reports that prove both systems agree, and finance and operations reporting that keeps working while tables move, ideally from a warehouse, not production, with one definition of each number. Secure has a stake because an unsupported runtime goes unpatched. Advisory frames the business case and the order domains move in.
Split those across vendors and the reconciliation report is the first thing nobody owns.
Related: The bill for AI-written code → · The modern data stack → · Multi-tenant architecture →