View renders and forwards intent. ViewModel orchestrates state and use cases. Model encapsulates data and domain/infra rules. In apps with a rich domain, the Model follows ddd; I/O stays behind ports (clean-architecture). Style decision: software-architecture.
Responsibilities
| Layer | Does | Does not do |
|---|---|---|
| View | Bindings, layout, UI events | Business rules, direct I/O, API parsing |
| ViewModel | Observable state, commands, transformation for UI | Know-how of widgets/colors/detailed visual navigation |
| Model | Entities, repositories, services | Knowing the View |
Flow
flowchart LR
View -->|"intenção / comandos"| ViewModel
ViewModel -->|"lê/escreve"| Model
Model -->|"dados / resultados"| ViewModel
ViewModel -->|"estado observável"| View
- View triggers command (tap, submit, appear).
- ViewModel validates, calls use cases/repositories.
- ViewModel updates state (loading / success / error).
- View reacts to state without business logic.
State
- Expose state as an immutable snapshot or clear observable properties.
- Model UI state with unions:
idle | loading | ready(data) | failed(error). - Avoid duplicated state between View and ViewModel.
- Side effects (navigation, toast) via events/effects consumed once, not forgotten flags.
Dependencies
- Inject repositories/services into the ViewModel (constructor/factory).
- View creates/obtains ViewModel via container, environment wrapper, or project factory.
- ViewModels do not import UI frameworks beyond the minimum of presentation types.
Testability
- Unit test ViewModels with a fake/mock Model.
- Test policies and transformations without bringing up the UI.
- Views: thin smoke/UI tests; heavy logic already covered in the ViewModel.
Adaptation per stack
- SwiftUI:
Observable/@Observable,@State,@Environment; ViewModel without referencingViewconcrete. - React / RN: ViewModel as a feature store/hook (
useXViewModel) separated from presentational JSX. - Android: official ViewModel + UiState; no View Context.
Anti-patterns
- Massive View with networking
- ViewModel that formats HTML/complex SwiftUI View builders
- Model that imports UI packages
- God ViewModel for the entire app screen
- Tangled bidirectional callbacks without a single state
Completion criteria
- Clear View / ViewModel / Model boundaries in the files touched
- UI state modeled and testable
- I/O isolated behind interfaces/repositories
- Thin Views; ViewModels with no dependency on widgets
- ViewModel tests for the feature's main flow
Integration with other skills
- Domain:
ddd - Ports/use cases:
clean-architecture - Decision:
software-architecture