Modernise the iOS codebase without putting the roadmap on hold.
Modernisation should reduce delivery risk, not create a multi-year rewrite programme. I help teams choose sensible boundaries, sequence migrations and keep shipping while Swift, concurrency, UI and dependencies move forward.
Common work
- Swift 6 strict-concurrency assessment and an adoption plan.
- Callback, Combine or RxSwift flows moved selectively to async/await.
- UIKit-to-SwiftUI migration at feature or component boundaries.
- Objective-C reduction where it removes real risk.
- Swift Package Manager modularisation and dependency boundary repair.
- Architecture simplification and state-management improvements.
- CI, tooling and minimum deployment target updates.
- Test seams around high-risk legacy behaviour.
The principles I hold to
- No rewrite by default.A rewrite is a product decision with a delivery cost, not a technical preference.
- Migrate at stable seams.Change at boundaries that already exist, so a partially migrated app stays coherent.
- Establish a measurable reason for each change.Crash rate, build time, change cost, delivery friction. If a change cannot be justified, it waits.
- Keep the app releasable.At every point in the migration, you should be able to ship what is on the main branch.
- Document the interoperability and the end state.Temporary bridging code is fine as long as everyone knows it is temporary and what it is bridging to.
What you receive
- A current-state assessment of the codebase and its constraints.
- A target architecture decision record.
- A sequenced migration roadmap with the reasoning for the order.
- A pilot implementation on a representative feature.
- Reusable patterns your team can apply to the rest.
- Team handover and mentoring, as scoped.
How the engagement is shaped
Most modernisation work starts with an assessment and a pilot. The assessment establishes what the compiler, the architecture and the delivery pipeline actually say about the codebase. The pilot proves the chosen pattern on one representative feature, at a size where being wrong is cheap.
After that, you can take the pattern in-house, or I can stay for a defined number of days a month while the migration works through the rest of the app.
Relevant experience
Why this work suits me
At Westpac I set the iOS technical standards for a large, long-lived codebase: modular boundaries and dependency rules, the UIKit-to-SwiftUI migration path, and how Swift 6 strict concurrency gets adopted. That included migrating legacy Objective-C and UIKit surfaces incrementally, without stopping delivery.
GlowUp and Motorway were built entirely in SwiftUI, so I know what the destination looks like when it is done well rather than in theory. And across fifteen years I have worked through MVVM, MVVM-C, Coordinators, VIPER and the Composable Architecture on real products, which makes me fairly resistant to the idea that any one of them is the answer.
Common questions
Do we have to replace UIKit?
No. UIKit is a supported, actively maintained framework, and a stable UIKit screen that nobody needs to change is not a problem to be solved. The question is where SwiftUI would improve delivery or product quality, not how quickly UIKit can be removed.
How long does Swift 6 adoption take?
It varies enormously with codebase size, how much shared mutable state exists, and how much Objective-C interop is in play. The honest first step is an assessment: turn on strict concurrency checking, see what the compiler says, and size the work from real diagnostics rather than an estimate.
Will this force us to raise our minimum iOS version?
Some of it might, and that is a business decision rather than a technical one. I will tell you which parts of a modernisation depend on a higher deployment target, what each one buys you, and what share of your users a change would affect based on your own analytics.
What happens to our product roadmap?
The whole point of migrating at stable seams is that feature work continues. In practice modernisation runs as a proportion of team capacity rather than a stop-the-world programme, and the sequencing is chosen so that in-flight product work is disrupted as little as possible.
When is a rebuild actually the right answer?
Occasionally. If the product itself is being replaced, if the foundations are abandoned and unsupportable, or if a full design rebuild is happening anyway, a rewrite can be the cheaper path. It remains the exception, and it should follow evidence rather than frustration.
Related reading
Weighing up a migration?
Tell me about the codebase, the team and the roadmap pressure you are under. I will reply by email with a candid view of what is worth doing first.