When an app grows, business logic scattered across screens becomes an untestable, unmaintainable knot. Mobile architecture is the discipline of separating responsibilities — UI on one side, business rules on another, data access on a third — so each part is simple, replaceable and testable. It is exactly the kind of decision expected of a senior.
Why separate UI from logic
The screen (View) should be "dumb": display data and forward events. If it also decides business rules, makes network calls and formats data, it becomes impossible to test without spinning up the whole UI, and any change becomes a risk. Separating lets you test logic without a screen, swap the UI without rewriting rules, and split the work across the team.
The analogy: a restaurant. The waiter (View) takes orders and serves, but doesn't cook. The kitchen (logic) prepares the dish without caring which table it's for. The pantry (data) supplies the kitchen. Each can change people without stopping the restaurant.
MVC, MVVM and MVI in a nutshell
These are patterns that organize who talks to whom between screen, logic and data.
| Aspect | MVC | MVVM |
|---|---|---|
| Parts | Model, View, Controller | Model, View, ViewModel |
| Who prepares data for the screen | Controller (sometimes blurs with the View) | ViewModel, exposed as observable state |
| View coupling | Tends to bloat (Massive View Controller) | View observes the ViewModel; low coupling |
| Logic testability | Hard when mixed with the View | High: ViewModel is testable without UI |
MVI (Model-View-Intent) takes MVVM further with a single, immutable state and a unidirectional flow: the View emits intents, they become a new state, and the View redraws. Declarative frameworks (Compose, SwiftUI, React) pair naturally with this idea.
Layers: presentation, domain, data
+------------------------------------+
| PRESENTATION (View + ViewModel) | what the user sees
+------------------------------------+
| DOMAIN (use cases, | pure business rules,
| entities) | no framework
+------------------------------------+
| DATA (repositories, | where data comes from
| API, database, | (network/local)
| cache) |
+------------------------------------+
dependency points downward -->
The golden rule: dependencies point inward/downward. The domain knows neither the UI nor the concrete API — it is the stable heart of the app.
The repository
The repository is the facade between domain and data: it decides whether a piece of data comes from the network, the local database or the cache, and hands it ready to the domain. The View never knows (and shouldn't know) the origin. This is what makes strategies like offline-first viable without spreading that logic across the screen.
interface UserRepository {
fun get(id): User
}
// implementation decides: cache? local? network?
// domain just calls get(id) and trusts it
Dependency injection
Instead of a class creating its own dependencies (val api = RealApi()), it receives them from outside. That way, in production you inject the real implementation; in tests, a fake (fake/mock). Tools like Hilt/Dagger, Koin, Swinject or manual constructor injection do this. Interviewers often ask you to explain why DI helps with tests — the answer is exactly being able to swap the real for the fake.
Why all this makes the app testable
- ViewModel/use cases: testable with fast unit tests, without spinning up a screen.
- Repository behind an interface: you inject a fake and test without a real network.
- Pure domain: no framework dependency, runs in any test environment.
Architecture isn't about pretty diagrams; it's about being able to swap one piece (the UI, the database, the API) without rewriting the others — and proving that each one works in isolation with a test.
Conclusion
Separating presentation, domain and data, hiding the data source behind a repository, using MVVM/MVI to free the View from rules and injecting dependencies to make everything replaceable: this is the architecture kit that keeps a large app sustainable and testable. A senior doesn't pick a pattern because it's trendy, but for the testability and clarity of responsibilities it brings.