Quando um app cresce, a lógica de negócio espalhada dentro das telas vira um nó impossível de testar e manter. Arquitetura mobile é a disciplina de separar responsabilidades — UI de um lado, regras de negócio de outro, acesso a dados em um terceiro — para que cada parte seja simples, substituível e testável. É exatamente o tipo de decisão que se espera de um sênior.
Por que separar UI da lógica
A tela (View) deveria ser "burra": mostrar dados e encaminhar eventos. Se ela também decide regras de negócio, faz chamadas de rede e formata dados, fica impossível testá-la sem subir a UI inteira, e qualquer mudança vira risco. Separar permite testar a lógica sem tela, trocar a UI sem reescrever regras, e dividir o trabalho no time.
A analogia: um restaurante. O garçom (View) anota e serve, mas não cozinha. A cozinha (lógica) prepara o prato sem se importar com qual mesa. O estoque (dados) abastece a cozinha. Cada um troca de pessoa sem parar o restaurante.
MVC, MVVM e MVI em uma pincelada
São padrões que organizam quem fala com quem entre tela, lógica e dados.
| Aspecto | MVC | MVVM |
|---|---|---|
| Peças | Model, View, Controller | Model, View, ViewModel |
| Quem prepara dados p/ tela | Controller (some confunde com a View) | ViewModel, exposto como estado observável |
| Acoplamento da View | Tende a inchar (Massive View Controller) | View observa o ViewModel; baixo acoplamento |
| Testabilidade da lógica | Difícil quando mistura com a View | Alta: ViewModel testável sem UI |
MVI (Model-View-Intent) leva o MVVM adiante com um estado único e imutável e um fluxo unidirecional: a View emite intenções, elas viram um novo estado, a View se redesenha. Frameworks declarativos (Compose, SwiftUI, React) combinam naturalmente com essa ideia.
Camadas: apresentação, domínio, dados
+------------------------------------+
| APRESENTACAO (View + ViewModel) | o que o usuario ve
+------------------------------------+
| DOMINIO (casos de uso, | regras de negocio
| entidades) | puras, sem framework
+------------------------------------+
| DADOS (repositorios, | de onde vem o dado
| API, banco, cache) | (rede/local)
+------------------------------------+
dependencia aponta para baixo -->
A regra de ouro: dependências apontam para dentro/baixo. O domínio não conhece a UI nem a API concreta — ele é o coração estável do app.
O repositório
O repositório é a fachada entre domínio e dados: ele decide se um dado vem da rede, do banco local ou do cache, e entrega isso pronto para o domínio. A View nunca sabe (nem deve saber) a origem. Isso é o que viabiliza estratégias como offline-first sem espalhar essa lógica pela tela.
interface UsuarioRepository {
fun obter(id): Usuario
}
// implementacao decide: cache? local? rede?
// dominio so chama obter(id) e confia
Injeção de dependência
Em vez de uma classe criar suas próprias dependências (val api = ApiReal()), ela recebe de fora. Assim, em produção você injeta a implementação real; em teste, uma falsa (fake/mock). Ferramentas como Hilt/Dagger, Koin, Swinject ou injeção manual via construtor fazem isso. É comum em entrevista pedir para explicar por que DI ajuda nos testes — a resposta é exatamente poder substituir o real pelo falso.
Por que tudo isso torna o app testável
- ViewModel/casos de uso: testáveis com testes unitários rápidos, sem subir tela.
- Repositório atrás de interface: você injeta um fake e testa sem rede real.
- Domínio puro: sem dependência de framework, roda em qualquer ambiente de teste.
Arquitetura não é sobre diagramas bonitos; é sobre conseguir trocar uma peça (a UI, o banco, a API) sem reescrever as outras — e provar que cada uma funciona isoladamente com um teste.
Conclusão
Separar apresentação, domínio e dados, esconder a origem dos dados atrás de um repositório, usar MVVM/MVI para libertar a View de regras e injetar dependências para tornar tudo substituível: esse é o kit de arquitetura que mantém um app grande sustentável e testável. O sênior não escolhe um padrão por moda, mas pela testabilidade e clareza de responsabilidades que ele traz.
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.