MVI는 단방향 데이터 흐름을 갖는 아키텍처 패턴이다.
State를 중심으로 UI를 구성하며 모든 상태 변화는 사용자의 명시적인 Intent를 통해 일어난다.
여기서 Intent는 안드로이드의 Intent와는 달리 사용자의 UI 액션이나 이벤트를 표현하는 객체이다.
- ViewState (Model)
UI에서 표현할 상태 데이터를 의미하며 상태는 불변 객체로 관리된다.
ex)로딩 중 여부, 입력 값, 에러 메시지 등- View
UI를 구성하는 계층으로 ViewState의 변화를 관찰하고 화면을 업데이트한다.
또한, 사용자의 입력을 Intent로 변환해 전달한다.- Intent
사용자 또는 시스템에 의해 발생하는 이벤트 또는 액션을 의미하며 ViewState를 변경하기 위한 트리거로 사용된다.
ex) 버튼 클릭, 텍스트 변경, 스크롤 이벤트 등
- View → Intent
사용자 이벤트를 Intent로 변환해 ViewModel로 전달- Intent → State
ViewModel이 Intent를 처리해 ViewState를 생성- State → View
View는 ViewState를 관찰하고 UI를 갱신
항목 | MVI | MVVM |
---|---|---|
데이터 흐름 | 완전한 단방향 흐름 (Intent → State → View) | 과거엔 양방향 데이터 바인딩도 가능했으나 Compose 기반은 단방향이 대세 |
UI 상태 관리 | 단일 불변 State 객체로 전체 UI 상태를 관리 | 보통 여러 LiveData/StateFlow 사용하며 최근에는 단일 상태 객체 관리 추세 |
변경 추적 | Reducer 함수로 명확하게 상태 변화 관리 | 보통 ViewModel 내부에서 상태 직접 갱신 |
디버깅/예측 가능성 | 높은 예측 가능성 (불변 상태 + 단일 상태 + Intent 기반) | 설계에 따라 다르나 상태가 여러 흐름에 나뉘면 예측과 디버깅 어려울 수 있음 |
복잡도 | 상태가 많아지면 구조가 복잡해질 수 있음 | 상대적으로 단순하고 익숙한 구조 |
대표 사용처 | Jetpack Compose, 리액티브 UI | 전통적인 XML 기반, Compose에도 사용 가능 |
대표 라이브러리/예시 | Orbit MVI, MviKotlin, Redux 스타일 | Jetpack ViewModel, LiveData, StateFlow 등 |
상황 | 설명 |
---|---|
상태(State)가 복잡한 화면 | 여러 UI 요소가 동시에 상태 영향을 받을 때 (로그인, 장바구니, 대시보드 등) |
UI 상태를 명확하게 추적하고 싶을 때 | 모든 상태 변화가 Intent를 통해 발생하므로 디버깅과 로깅에 유리 |
불변 상태 기반의 정제된 설계를 원할 때 | 단일 상태(State)를 기준으로 화면을 구성 |
단방향 흐름이 강하게 요구될 때 | UI 동기화 문제를 방지하고자 할 때 |
상황 | 설명 |
---|---|
화면 구조가 단순하거나 CRUD 중심일 때 | 리스트, 입력 폼, 디테일 페이지 등 |
구현 속도와 생산성이 중요할 때 | Boilerplate 적고 익숙한 패턴으로 빠른 개발 가능 |
구현 복잡도를 낮추고 싶을 때 | MVI보다 학습 비용과 설계 난이도가 낮음 |
기존 프로젝트가 MVVM 기반일 때 | 유지보수성과 팀 내 일관성 고려 |
질문 | 답변 |
---|---|
언제 MVI를 써야 하나요? | 상태가 복잡하고 명확한 상태 추적과 불변 상태 관리가 필요한 화면에 적합 |
언제 MVVM을 써야 하나요? | 단순 UI나 CRUD, 빠른 개발 및 기존 MVVM 프로젝트 유지보수에 적합 |
기능별로 나눠 써도 되나요? | 가능하지만 팀 내 아키텍처 일관성과 합의가 매우 중요 |
전체를 하나로 통일해야 하나요? | 규모가 크고 여러 팀이 함께 작업할 경우, 통일된 아키텍처 유지가 유지보수에 유리 |
Jetpack Compose와의 높은 궁합
Compose는 상태가 곧 UI인 선언적 구조
MVI는 단일 상태와 명확한 단방향 흐름으로 Compose와 잘 맞아 예측 가능한 UI 갱신 가능
단방향 흐름으로 상태 꼬임 최소화
MVVM은 상태 변경 경로가 다양해 복잡한 화면에서 꼬일 수 있지만, MVI는 Intent → Reducer → State 흐름이 명확
덕분에 디버깅과 유지보수가 수월
상태 관리 및 추적이 쉬움
하나의 ViewState로 모든 UI 상태를 통합 관리
상태 저장, 복원, 테스트가 쉬워 복잡한 화면일수록 신뢰성과 유지보수성이 높아짐
실시간 반응형 UI에 적합
실시간 상태 변화가 많은 앱에 유리
상태 흐름을 명확히 모델링할 수 있어 복잡한 UI도 쉽게 관리 가능
아키텍처 일관성과 테스트 용이성
SideEffect(비동기 로직 등) 분리가 자연스러워 비즈니스 로직과 UI 코드가 잘 나뉨
명확한 구조 덕분에 유닛 테스트와 코드 유지보수에 유리
다만, 모든 경우에 MVI가 반드시 우월한 것은 아니므로 화면 복잡성이나 전환 비용에 따라 MVVM과 적절히 선택해야 한다.
사이드 프로젝트를 진행하면서 MVI 패턴을 적용해볼까 고민 중이다.
기존에는 MVVM 패턴만 사용했지만, MVI 패턴도 새롭게 알게 되어 이번 기회에 직접 적용해보며 학습하면 좋을 것 같아 정리해봤다.
Compose + MVI가 좋은 선택일까?
비교적 MVVM보다 초기 설계와 학습에 시간이 더 많이 들고 코드 구조가 복잡해질 수도 있지만..
Compose의 선언적 UI 특성상 상태 기반 렌더링에 최적화되어 있어
MVI의 단방향 데이터 흐름과 단일 불변 상태 관리 방식이 Compose와 잘 어울린다.
덕분에 UI 상태 관리가 훨씬 명확해진다는 점이 큰 장점이다.
그래서 이번 프로젝트에서 MVI를 경험하며 배우는 것이 좋은 선택일 것 같다.