The Strangler Pattern Does Not Choose the Writer
Strangler Fig migrations do not usually fail because traffic routing is hard. They fail because traffic moves before write ownership moves. The painful moment arrives when the dashboard says thirty percent of requests are on the new stack while both stacks still mutate the same customer, order, policy, or billing record.
The Assumption That Breaks It
Teams treat Strangler Fig as a proxy pattern. Put a gateway in front of the monolith, route one URL to a new service, and celebrate the traffic percentage. That is only access modernization. State modernization starts when one system, and only one system, is allowed to change a business fact.
For single-writer strangler migration, a senior review should ask which coexistence decision is being made, which evidence proves it, and what signal would force the team to pause.
A Migration With Two Checkout Paths
A wealth platform moved client profile updates to a new service while branch staff still used the legacy CRM. Self-service updates wrote Postgres. Branch updates wrote Oracle. A nightly sync tried to reconcile both. The first month looked fine because row counts matched. The second month produced returned statements and compliance calls because addresses changed back overnight. Better sync logging did not fix it. The fix was a signed writer table, disabled legacy writes for migrated cohorts, and CDC from the new writer into old read models.
Single-Writer Ownership Before Routing
Where Migration Plans Hide Ownership
Teams often focus on moving code and routing traffic.
They forget to ask: who is allowed to update the database row?
Dual-write: two systems, same record
Suppose both systems can run:
UPDATE customer SET address = 'A' -- legacy job
UPDATE customer SET address = 'B' -- new service
Now:
- Two writers touch the same entity.
- Race conditions decide which value survives.
- Caches and read replicas show different answers depending on timing.
- Event streams may publish conflicting facts.
- Support and ops cannot tell which system is "right."
This is the dual-write problem. It is common in Strangler migrations because both systems stay alive for a while. That coexistence is normal. Dual-write without rules is not.
Why it feels fine until it does not
Early in a migration, traffic is low and demos look good. Both systems "sync." Someone says dual-write is temporary.
Month six, temporary is still there. Operations reconciles account status in Excel. Engineering talks about "better sync." The real issue was never sync. It was two owners of the same write.
Route Shape Versus Ownership Shape
Bad: both systems write billing
Old billing ----write----> billing\_table <----write---- New billing
Typical failures:
- Duplicate charges or duplicate credits.
- Conflicting balances.
- Rollback is unclear (which system's change do you undo?).
- Auditors ask which ledger is authoritative. Nobody has a crisp answer.
Good: one writer, clear handoff
Old billing ----read only----> billing\_table
^
| single writer
New billing
During coexistence:
- New service owns writes.
- Legacy reads or calls new APIs.
- You compare outputs (parity / drift checks) until trust is high.
- You remove legacy write paths and later retire legacy code.
What Changes When Writers Are Named
Moving a feature to a microservice is not the same as transferring ownership of state.
Migration is about:
- Who may change each entity.
- When write ownership moves from legacy to modern.
- How you prove both sides agree before you cut over traffic.
It is not only about:
- Splitting repositories.
- Exposing REST APIs.
- Hitting a traffic percentage on a load balancer.
Teams celebrate "30% of traffic on the new stack" while both stacks still mutate the same rows. The migration looks green on a dashboard and red in operations.
Worked Example: billing migration
Goal: replace old billing with a new billing service.
| Phase | Legacy billing | New billing | billing_table |
|---|---|---|---|
| Wrong | writes | writes | conflict |
| Wave 1 | read + UI | writes | single writer |
| Done | retired | writes | single writer |
During wave 1, if an advisor triggers a billing action in the old UI, that UI should call the new service, not write the table directly.
Where This Shows Up: fintech and healthtech
Fintech and wealth: conflicting policy status or balance on a client record breaks advisor trust and regulatory reporting. Writer rules must match who owns the ledger or core feed overnight vs intraday updates.
Healthtech: two systems updating the same care plan or authorization flag means clinicians see different values in different screens. Single-writer per cohort, with legacy read-only for audit history, is the usual pattern.
The pattern is the same. Only the entity names and reviewers change.
Where Single-writer strangler migration Control Belongs
Legacy UI ----writes----> Customer row <----writes---- New profile service
\\---------------- bidirectional sync ----------------/
Correct wave:
Legacy UI ----read/API----> Profile service ----writes----> Profile DB
\\----CDC/outbox----> Legacy read model
The Ownership Tradeoff
The tradeoff is clarity versus convenience. Clear ownership creates temporary integration work. Convenience creates reconciliation work that looks temporary until it becomes someone's job.
For single-writer strangler migration, the useful review is not a generic architecture checklist. It should inspect writer ownership, parity evidence, wave boundaries, rollback, and retirement. If those fields are missing, the team may still be busy, but leadership does not yet have a decision-quality artifact.
Review Packet Before Release
For single-writer strangler migration, the release review should not start with percentage of traffic shifted or number of services created. It should start with the ownership table. For every entity touched by the wave, name the current writer, the target writer, the read paths that remain on legacy, the jobs that still mutate data, and the condition that disables those jobs. If a batch process, admin SQL script, or vendor feed can still update the entity, the wave is not ready.
For single-writer strangler migration, parity evidence should sample production-shaped cases by business segment, not only random identifiers. Compare the values that users, auditors, reports, and downstream integrations care about. In financial services, that means balances, statuses, fee calculations, disclosures, and event timestamps. In manufacturing, it means lead times, lot traceability, reservation state, and label outputs. HTTP 200 on old and new paths is not parity. Matching business outcomes under realistic edge cases is parity.
For single-writer strangler migration, rollback design is simple when the old writer never stopped writing. It is difficult when writes have moved. Decide whether rollback means routing traffic back to legacy, replaying events, freezing writes, or operating a manual exception queue. If rollback would reintroduce two writers, the safer response may be fail-closed and human handling rather than automatic reversal.
For single-writer strangler migration, require a retirement ticket in the same wave plan as the build ticket. Modernization without retirement is accumulation. The old path may remain read-only for audit or reporting, but writable legacy behavior should have a deletion or disablement date tied to evidence.
Failure Modes to Rehearse
Single-writer strangler migration test plans should include concurrent writes, stale reads, replay after partial failure, and rollback after ownership moves. Test a legacy batch job running while the modern service writes the same entity. Test a support-user override, not only a customer-facing request. Test what happens when CDC pauses for an hour and then resumes. Test deletion, merge, and correction flows because those are where hidden writers often appear.
For single-writer strangler migration, sample cases should include the ugly tail: old product codes, inactive customers, manually corrected orders, regional exceptions, and records created before the current schema existed. Those cases are not edge noise. They are often the reason the legacy system survived for years.
Paths Worth Comparing for Single-writer strangler migration
Keep legacy as writer while the new service reads and shadow-compares. Move writes by cohort only when support can explain the boundary. Route legacy UI commands through the new owner when familiar screens must remain. Avoid two-way sync unless the organization is willing to fund a permanent conflict-resolution team.
In single-writer strangler migration, the alternative paths are not steps on a ladder. Each one carries a different mix of risk, cost, and learning. The weak choice is the one that hides the tradeoff until users, operators, or auditors discover it for you.
The Rule for Strangler Programs
Strangler Fig migrations do not usually fail because traffic routing is hard. They fail because traffic moves before write ownership moves. The painful moment arrives when the dashboard says thirty percent of requests are on the new stack while both stacks still mutate the same customer, order, policy, or billing record. The practical lesson is to demand evidence that fits single-writer strangler migration, not a universal checklist. The artifact should expose writer ownership, parity evidence, wave boundaries, rollback, and retirement clearly enough for another team to challenge the decision.
If single-writer strangler migration is the decision in front of your team, use the Modernization Snapshot to pressure-test the boundary before it hardens.