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¶
- 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.
- Sequence phases so each depends only on prior phases — the later phase's simplicity requires the earlier phase's completion.
- Choose each phase's AI involvement level by considering novelty + risk:
- 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.
- Iterative AI workflow once patterns are clear but pre-formalization.
- Structured AI skill (see patterns/ai-migration-skill-workflow) once the workflow has stabilised across enough migrations to be packaged with progressive disclosure.
- 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).
- 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¶
- sources/2026-02-03-instacart-migrating-to-jetpack-compose — canonical wiki instance. Four phases, AI-level per phase calibrated to novelty + risk, visual-parity gate on the UI-rendering phase, feature-flag dual-system for the navigation-host phase.
Related¶
- patterns/ai-migration-skill-workflow — the AI-skill shape deployed within a phase (Phase 3 at Instacart).
- patterns/migration-as-agent-skill — Cloudflare/vinext sibling on web frameworks (single-skill, one-shot migration, no phases because the target is a clean reimplementation).
- patterns/ai-driven-framework-rewrite — the creative-rewrite sibling for framework reimplementation rather than codebase migration.
- patterns/staged-rollout / patterns/phased-migration-with-soak-times — generic staged-rollout mechanics at the deployment layer complementing the code-migration phasing here.
- concepts/ai-assisted-refactoring-economics — the economics argument that makes previously-deprioritized migrations feasible.
- systems/jetpack-compose — the canonical target.
- systems/android-fragment — the canonical source.