Strangler migration case study and interview preparation
Case study: replace legacy checkout without a rewrite freeze
Place a stable CheckoutGateway around the legacy implementation. Characterize behavior with contract/golden tests. Build new checkout as a vertical slice using the same domain commands and server idempotency. Route only eligible new journeys; a journey keeps its implementation after starting. Compare shadow reads where privacy/load permit, but never shadow a payment write.
Roll out by employee/account/app-version cohorts with crash, latency, duplicate-order, payment, conversion, support, and data-reconciliation guardrails. Rollback routes future journeys to legacy; in-progress/new-format data needs forward-compatible completion or repair. Completion means 100% observed stability followed by deletion of legacy code, adapters, flags, dependencies, tests, and dashboards.
Interview questions
- Refactor versus migration? Refactor preserves external behavior; migration changes a technology/contract/data boundary and needs coexistence planning.
- Why strangler pattern? It shifts traffic slice-by-slice through a stable boundary, limiting blast radius and enabling learning.
- What makes rollback impossible? Irreversible writes, schema contraction, external side effects, and clients already acting on new semantics.
- How migrate LiveData to Flow? Preserve lifecycle, initial state, hot/cold, replay, error/completion, event, and testing semantics.
- Biggest DI coexistence risk? Duplicate graphs/scopes creating multiple supposed singletons.
- How measure modularization? Build impact, dependency direction/cycles, API surface, ownership, defects, tests, and lead time—not module count.
- When contract old data/API? After telemetry proves supported consumers no longer use it and recovery/backup windows are addressed.
Checklist
- Business/data/security invariants and baseline measured.
- Stable seam with old/new contract tests.
- Coexistence ownership and compatibility window defined.
- Persisted/distributed changes use expand-migrate-contract.
- Staged routing, guardrails, diagnostics, and incident owner ready.
- Rollback limits and forward-repair paths documented.
- Developer/product impact measured against baseline.
- Legacy deletion condition, owner, and date committed.
Exercises
- Migrate a callback-based Java sync engine to Kotlin coroutines without losing queued work.
- Plan a screen-by-screen View/Compose migration with shared navigation and design system.
- Split a database-owning monolith while preventing cross-module DAO access.
- Review a proposed “six-month rewrite” and replace it with measurable vertical slices.