State management on iOS is a debate magnet. Pointfree’s TCA (The Composable Architecture) has caught on in the community: Elm-inspired, Redux-style unidirectional data flow, with strong testability.
After 12 iOS apps on MVVM, I tried TCA on a small project. Verdict: TCA is a great tool, but it isn’t right for every project. Here are the criteria I use to choose.
MVVM’s strengths
MVVM feels natural in SwiftUI. @State, @Observable, @Environment already lean on Apple’s own recommended patterns.
1. Low learning curve. Almost every iOS dev knows MVVM. A new team member is productive within a day or two.
2. Minimum boilerplate. A ViewModel is a class, bound to a view. That’s it. TCA adds Store, Reducer, Action, State, and Environment, five distinct concepts.
3. Natural fit with Apple’s frameworks. SwiftUI, Combine, async/await, Observation all support MVVM natively. TCA needs its own wrappers in places.
4. Easier debugging. You know where to put a breakpoint in a ViewModel. In TCA, tracing state changes across action dispatch, reducer execution, and effect processing is harder.
TCA’s strengths
1. Testability is excellent. TCA’s TestStore is really good. You send actions, assert state, and verify effects fired. Hitting 90%+ unit test coverage is easy.
2. Time-travel debugging. You can see action history and replay from any past state. Reproducing complex bugs is dramatically easier.
3. Predictable state changes. State only mutates inside a reducer. Tracing “when did this property take this value?” is far more deterministic than in MVVM.
4. Feature composition. Building a big feature out of smaller sub-features is native in TCA. Each sub-feature declares its own State, Reducer, and Action, and the parent composes them.
5. Side-effect handling. TCA’s Effect API manages async operations declaratively. Cancel, debounce, and retry logic is built in.
When to pick which
Pick MVVM:
- Fewer than three people on the team
- Project timeline under three months
- Junior iOS devs on board (learning curve)
- App logic is relatively simple (fewer than five complex features)
- You’re on UIKit, not SwiftUI
- You’re in fast prototype or MVP mode
Pick TCA:
- Five or more developers and a shared pattern matters
- Long-lived enterprise app (three years and counting)
- Deeply nested features (dashboard to sub-dashboard to widget to setting)
- You have an 80%+ test coverage target
- You need time-travel debugging
- The team is comfortable with functional programming
Tips if you’re thinking about moving to TCA
On an existing MVVM project considering TCA:
Switch:
– The team isn’t stuck on MVVM, feature velocity is fine
– You don’t have three to six months to spend on a refactor
– Test coverage is already 70%+
Partial switch:
– Rewrite one or two complex features in TCA
– Leave the rest on MVVM
– Coexistence is possible but it adds complexity
Full switch:
– A major-version rewrite (v2.0)
– The team is ready for TCA training
– Three to six months of pure refactor is acceptable
A recurring problem in the TCA community
Even inside the TCA community there’s no consensus on “ideal TCA usage”. Which reducers should compose and which shouldn’t, what belongs in Environment, how to organise Effects, the debates go on.
That flexibility sometimes reads as ambiguity. For a team starting fresh, MVVM’s “write a ViewModel, bind it” clarity can be more practical.
Boilerplate numbers
A small login feature:
MVVM: ~150 lines of code
– View: 50 lines
– ViewModel: 80 lines
– Model: 20 lines
TCA: ~250 lines of code
– View: 50 lines
– State: 20 lines
– Action: 15 lines
– Reducer: 70 lines
– Environment: 30 lines
– Effects: 40 lines
– Store binding: 25 lines
65% more code. The ratio drops as features get more complex because TCA’s composition advantage kicks in, but for simple features the overhead is real.
What I pick for myself
All 12 of my iOS apps are MVVM. Why? Every one of them is either solo or a two-person team. The timelines are short and feature velocity matters. TCA’s testability is great, but writing 250 LOC instead of 150 isn’t worth it.
If I joined a five-plus person team shipping an enterprise app, I’d seriously consider TCA. For indie or small-agency work, MVVM wins.
Takeaway
TCA is a strong architecture, but not for every project. The learning curve is high, the boilerplate is real, and it has some friction against the Apple ecosystem. In return it gives you strong testability, state predictability, and composition.
Team size, project lifespan, and your coverage target drive the call. Don’t pick on fashion, pick on what you actually need.