Skip to content

PATTERN Cited by 1 source

Phased framework migration

Pattern

When migrating a large codebase from one framework to another, sequence the migration into phases that each decouple one orthogonal axis of coupling at a time. Each phase ships small, validated changes. Phases with different risk profiles get different AI-involvement levels. Incrementalism is the risk-mitigation mechanism — each phase can be validated in production before the next begins.

Forces

  • Framework migrations are expensive — 100s of features, 1000s of call-sites, often multi-quarter effort.
  • "Big bang" rewrites carry the highest risk: a single regression blocks the entire migration.
  • Framework coupling has multiple orthogonal axes — rendering, navigation, state management, dependency injection, build system — that can be decoupled independently.
  • Stability-critical systems (e.g. in-store hardware) can't tolerate a single-shot migration; intermediate states must be shippable.
  • AI assistance changes the cost curve (see concepts/ai-assisted-refactoring-economics) — but AI-generated changes still need to be validated; small phase increments make validation tractable.

Solution shape

  1. Identify the orthogonal axes of framework coupling. E.g., for Android: UI rendering (Views/XML ↔ Compose), navigation (XML nav graphs ↔ type-safe DSL), navigation host (Fragment ↔ Compose Navigation), state management, dependency injection.
  2. Sequence phases so each depends only on prior phases — the later phase's simplicity requires the earlier phase's completion.
  3. Choose each phase's AI involvement level by considering novelty + risk:
  4. Manual for the first phase that seeds pattern knowledge — you need engineer muscle memory of the conventions before you can teach them to an AI.
  5. Iterative AI workflow once patterns are clear but pre-formalization.
  6. Structured AI skill (see patterns/ai-migration-skill-workflow) once the workflow has stabilised across enough migrations to be packaged with progressive disclosure.
  7. Ship + validate each phase in production before starting the next. Parallelise phases only when dependencies allow (e.g., Instacart runs Phase 4 in parallel with the tail of Phase 3 behind feature flags).
  8. Feature-flag dual-system support during phase transitions — two navigation systems running side-by- side, one data model in two states, etc.

Canonical application — Instacart Caper

Migrating Android app from Fragments + XML to Jetpack Compose:

Phase Axis decoupled AI level
1. Implicit Fragment hosts Decouple Fragment-class scaffolding from Composable body (MyFeatureScreen() parameterless + MyFeatureScreenInternal(...) pure-Compose split). Manual — deliberately, to learn patterns.
2. Type-safe navigation Decouple XML resource-ID routing from Kotlin-DSL type-safe routing while keeping Fragment-based nav. 30+ sub-graphs, 130+ destinations. Iterative AI workflow (5-step). Reported 5–7× faster, 300–350 eng-hours saved.
3. Fragments → Compose screens Decouple rendering substrate. 100+ Fragment features → pure Compose. 17-step AI skill with engineer verification checkpoints including Paparazzi visual-parity gates.
4. Compose Navigation Decouple navigation host (Fragment-based → Compose Navigation). AI skill (early experiments); runs in parallel with Phase 3 behind feature flags.

The Instacart post names the risk-mitigation payoff:

"By decoupling the navigation refactor (Phase 2) from the UI refactor (Phase 3), we were able to ship small, AI- generated changes incrementally. Each phase had clear success criteria and could be validated in production before moving forward, reducing the blast radius of any potential errors."

Consequences

  • Bounded blast radius per change — each phase can be rolled back without unwinding the rest.
  • Each phase validates the next phase's preconditions — Phase 1's parameterless / internal split is exactly what Phase 4 needs to swap navigation hosts cheaply.
  • AI risk is contained — small AI-generated changes validated in production before scale.
  • Feature velocity preserved — phased parallelism means feature teams don't block on migration.
  • Longer calendar time — a four-phase plan is slower to complete than a single-shot rewrite would be if it worked (but single-shot rarely does for this scale).
  • Intermediate states exist — dual-system code, compat shims, migration-mode configs; these carry their own complexity cost and must themselves be retired later.

Counter-indications

  • Small codebases — phase overhead dominates savings.
  • Greenfield work — no existing framework to migrate away from.
  • True framework re-write where the API contract changes — see patterns/ai-driven-framework-rewrite + patterns/clean-reimplementation-over-adapter for the one-shot rewrite shape (different pattern).
  • Framework coupling is not actually orthogonal — if rendering and navigation can't be separated, the phase boundaries can't exist.

Seen in

Last updated · 319 distilled / 1,201 read