Start a modernization plan with the reason for the change and the limits on the work: uptime windows, integrations you cannot change, and engineering time available alongside product development.

Summary: Use incremental, reversible milestones. Freeze behavior at the edges, ship behind feature flags, and use canary metrics and error budgets to decide when to move forward.

The decision: triggers and constraints

Write the reason for change in one line, then list what cannot move. Use that page to choose the approach, sequence, and acceptance checks.

Decision factors

Reasons for change and limits on the work

Triggers

  • Security exposure or unsupported dependencies
  • Performance or reliability limits hurting customers
  • High change failure rate or slow releases
  • Vendor lock-in or license costs

Constraints

  • No downtime or tightly-bounded maintenance windows
  • Regulatory scope or evidence requirements
  • Limited engineering time alongside product work
  • Integration contracts you can’t break

Strangler-fig vs big-bang rewrites

A strangler-fig approach replaces one capability at a time alongside the old system. A big-bang rewrite cuts over all at once. The table compares their delivery and migration risks.

Approach comparison

Strangler-fig vs. big-bang rewrite

AreaStrangler-fig (incremental)Big-bang rewrite
Delivery Reversible milestones that release one capability at a time Full build before release; users receive the replacement at cutover
Risk Limits blast radius with parallel run and rollbacks One cutover requires validation of the full replacement
Scope control Focus on the constraint; stop when the goal is met Scope may expand to include unrelated improvements
Evidence Canary metrics, error budgets, and staged acceptance Production evidence may arrive later in the project

When to consider microservices

Services help when the system’s change boundaries are already clear and owned: teams, data contracts, deployment cadence, and monitoring. The team needs reliable deployment and monitoring for the existing application before adding more services.

  • Use services to isolate independent change with separate failure domains.
  • Keep deployment units focused enough to test and roll back cleanly.
  • Invest in observability and SLOs and error budgets before increasing moving parts.

Database-first modernization and contract tests

Document and test the database interfaces first. Contract tests capture today’s read/write behavior so you can change code without surprising integrations.

Data-first pattern

Modernize behind stable database contracts

Freeze behavior

  • Write contract tests capturing today’s reads/writes
  • Document invariants and out-of-band jobs
  • Pin data shape where integrations depend on it

Change safely

  • Introduce new tables, keep the old API
  • Dual-write or adaptors during the transition
  • Gate by feature flags; measure with SLOs

Cut over

  • Backfill and verify with replay data
  • Flip producers/consumers in stages
  • Remove the shim when error budget holds

Operational safeguards

Include deployment, monitoring, and recovery checks in each stage of the code changes.

  • Feature flags guard incomplete behavior behind targeted traffic.
  • Canary deploys shift a limited percentage first; watch golden signals.
  • Rollback procedures are tested before each cutover.
  • Error budgets decide when to pause change and fix reliability.

Milestone reviews

Each milestone needs acceptance checks, owners, and a rollback plan. Halt when error budgets are exceeded; resume when they recover.

Production patterns we use

  • Parallel run: write to both stores or both endpoints while verifying behavior.
  • Adapter shims: present the old interface on new code during cutover.
  • Replay: backfill and verify with captured production inputs.
  • Dark launch: deploy behind a header and compare outputs before exposing users.