Overview
The Strangler Fig pattern is the primary migration strategy: incrementally replace the legacy system component by component while the legacy system continues to operate. The migration proceeds in parallel with feature development — it is never a "pause and migrate" operation. The migration is complete when the last legacy component is strangled by its replacement.
Migration Patterns
Strangler Fig for Architecture Migration
Apply the Strangler Fig to Clean Architecture adoption in a legacy codebase:
- Create the
domain package with repository interfaces and domain models — empty initially.
- For each new feature: implement it following Clean Architecture fully. The new feature uses the domain layer.
- For each bug fix in legacy code: leave the fix in place but add a corresponding domain model and repository interface.
- For each legacy screen that requires significant modification: extract the business logic into a Use Case, leave the UI unchanged temporarily.
- Over time, all new code uses the Clean Architecture pattern. Legacy code is progressively replaced as screens require modification.
XML to Compose Migration (Android)
ComposeView in XML layouts and AndroidView / AndroidViewBinding in Compose allow the two UI frameworks to coexist in the same application. Migration strategy:
- Add Compose dependency and a
ComposeView in the XML layout of the target screen.
- Implement the new screen or component in Compose inside the
ComposeView.
- Once the Compose implementation is complete and tested, remove the XML layout and replace with a
setContent {} call in the Activity/Fragment.
- Migrate screens in order of complexity: simple screens first, complex screens with many states last.
UIKit to SwiftUI Migration (iOS)
UIHostingController wraps a SwiftUI View in a UIKit container. UIViewRepresentable embeds a UIKit view in a SwiftUI hierarchy. Migration strategy mirrors the Android approach: new screens in SwiftUI, legacy screens in UIKit with UIHostingController-wrapped components for new features, gradual replacement as screens require modification.
React Native New Architecture Migration
Migration from Bridge to New Architecture (JSI + Fabric) requires: enabling the New Architecture in android/gradle.properties and Podfile, migrating each native module from TurboModuleRegistry.getEnforcing to the new TurboModule spec, migrating each native UI component to the new Fabric ComponentRegistry. Third-party libraries must be New Architecture compatible — audit all dependencies before migration.
Migration Governance
Migration phases are tracked as engineering epics with explicit completion criteria. Each phase has a rollback plan. The migration is complete when: the last legacy component is removed, CI confirms no references to the legacy API remain, and the architecture fitness functions pass without exclusions.
Migration velocity is measured: percentage of codebase on new architecture, tracked monthly. Target: 10% migration per sprint for a medium-sized codebase. Migrations that stall at 50% complete are more dangerous than either the legacy system or the new system — they create dual-maintenance overhead and confusion for new engineers.
Anti-Patterns to Avoid
⚠ 1. Big Bang Rewrite
"We'll rewrite the entire app in Compose/SwiftUI/Clean Architecture over the next quarter. Feature development is paused until the rewrite is complete." The rewrite always takes longer than estimated. The legacy system continues to accrue production issues that must be fixed in the legacy codebase, creating two codebases to maintain.
Hover to see the fix ↻
↺ Correct Approach
Strangler Fig. The legacy system continues to operate. New code uses the new pattern. Migration proceeds incrementally without halting feature development.
⚠ 2. Migration Without Fitness Functions
Migrating the architecture without automated enforcement of the new standards. Engineers write new code in the old pattern because it is familiar. Six months in, the new and old patterns coexist chaotically.
Hover to see the fix ↻
↺ Correct Approach
Architecture fitness functions in CI enforce the new standard from day one. New legacy code cannot be added without explicitly disabling the fitness function gate — which requires a documented justification.
Flowchart
%%{init:{'theme':'base','themeVariables':{'fontSize':'14px','fontFamily':'IBM Plex Sans, system-ui, sans-serif','primaryColor':'#DBEAFE','primaryTextColor':'#1e3a5f','primaryBorderColor':'#2563EB','lineColor':'#374151','clusterBkg':'#F9FAFB','clusterBorder':'#D1D5DB','edgeLabelBackground':'#FFFFFF'},'flowchart':{'curve':'orthogonal','padding':30,'nodeSpacing':65,'rankSpacing':75,'useMaxWidth':true}}}%%
flowchart TD
LEG["Legacy Codebase
XML Views · MVC
Monolithic module"] --> SF
subgraph SF["🌿 Strangler Fig Pattern"]
S1M["Step 1: Add domain package
Repository interfaces
Domain models — empty initially"]
S2M["Step 2: New features
Implement in Clean Architecture
Old features untouched"]
S3M["Step 3: Bug fixes
Add domain model alongside fix
Do not rewrite the fix"]
S4M["Step 4: Significant modifications
Extract Use Case from legacy
Leave UI temporarily"]
S5M["Step 5: Progressive replacement
All new code uses new pattern
Legacy replaced as screens modified"]
end
SF --> NEW["Modern Codebase
Compose · Clean Architecture
Feature modules · MVVM"]
subgraph FF2["⚙ Fitness Functions — Guard the Migration"]
AFF3["No Use Case imports Android SDK
CI build fails on violation"]
AFF4["No feature module cross-dependencies
Gradle dependency check"]
AFF5["No XML layouts in migrated modules
File extension scan"]
end
S1M --> S2M --> S3M --> S4M --> S5M
NEW --> FF2
style SF fill:#E3F2FD,stroke:#1565C0
style FF2 fill:#E8F5E9,stroke:#1B5E20
style LEG fill:#FFEBEE,stroke:#B71C1C
style NEW fill:#E8F5E9,stroke:#1B5E20
References
- Fowler, Martin — Strangler Fig Application. martinfowler.com/bliki/StranglerFigApplication.html
- Fowler, Martin — Branch by Abstraction. martinfowler.com/bliki/BranchByAbstraction.html
- Ford et al. — Building Evolutionary Architectures. O'Reilly, 2017.
- Google — Migrating to Jetpack Compose. developer.android.com/jetpack/compose/migrate
Mobile Engineering Reference
← Mobile Development