app-modernization
app-modernization
Modernizes legacy applications incrementally — strangler-fig slices, expand-contract data migrations, parity-verified cutovers, and clean decommissioning. Use when migrating a monolith or legacy stack, upgrading frameworks in place, extracting services, replatforming, or when the user mentions modernization, migration, or a legacy rewrite.
- Category
- Category: architecture
- legacy
- strangler-fig
- migration
- replatform
- cutover
- parity
- expand-contract
- decommission
- monolith
- modernization
Install this skill
npx . --tool claude-code --only app-modernizationRun from a git checkout of this repo — see the README for details.
Modernization is incremental replacement behind a stable facade, not a rewrite. The legacy system encodes years of fixed bugs and business rules nobody documented; the goal is to move off it without losing either. Every slice ends in production — a modernization that lives on a branch is a science project.
When to apply
Use when migrating a legacy or monolithic application to a modern stack, upgrading a framework in place, extracting services from a monolith, replatforming (cloud, runtime, database), or whenever someone proposes "just rewrite it".
Workflow
- Assess — inventory modules, dependencies, data stores, and integration points. Score each on business value × change risk. Output: a ranked list of migration slices. Modernization is a portfolio decision before it is a code exercise.
- Pick the seams — find (or carve) module boundaries where old and new can coexist behind a facade, interface, or route table. No seam, no slice — do the modularization work first.
- Slice — order slices by value ÷ risk. The first slice is a tracer bullet: small, high-visibility, low blast radius. Each slice ships to production before the next starts.
- Choose the per-slice pattern — from the pattern table below; one pattern per slice, written down before code.
- Verify parity — the new path proves it behaves like the old one on real cases (fixture-driven round trips, golden-master diffs) including the weird legacy edge cases, before any traffic moves. Document deliberate deltas; don't silently "fix" behavior.
- Cutover — route a fraction of traffic (or one tenant/flow) to the new path, watch the signals, widen, flip. Every cutover has a rehearsed rollback — if you can't roll back, you're not cutting over, you're betting.
- Decommission — delete the old code path, its tables, its feature flags, its deploy config, its runbook. Done means the old thing is gone, not that the new thing works.
Migration patterns
- Strangler fig — grow the new system around the old; route at a facade; delete old code per slice. The default choice.
- Branch by abstraction — for in-place framework upgrades: old and new implementations behind one interface, flip callers one at a time.
- Parallel run (shadow) — run new alongside old on live traffic and diff outputs. The cure for "we don't actually know what this code does".
- Expand–contract — for schema and API changes: add the new shape, migrate writers/readers, contract (remove) the old. Never a breaking in-place change.
- Dual-write → backfill → verify → read-switch — for data: write both stores, backfill history, verify counts and checksums, switch reads, stop writing old.
Rules
- No big-bang rewrites — a rewrite re-learns every bug the legacy code already fixed and freezes feature delivery for its duration.
- Behavior first, structure second — changing what the system does and how it's built at the same time makes every regression ambiguous. Sequence them.
- Every cutover has a tested rollback — rehearsed, not theoretical.
- Decommissioning is part of done — a leftover half-old system rots, confuses on-call, and doubles the maintenance bill.
- Parity over perfection — match current behavior before improving it; improvements get their own slices.
Related skills
- round-trip-testing — proving old/new parity with fixture-driven round trips.
- domain-modularization — carving the seams before you slice.
- lean-implementation — keeping each slice minimal and shippable.
- minimal-fix — the shape of individual fixes made during migration.