안녕하세요. 중곰입니다.
오늘은 MVVM과 MVI 패턴에 대한 생각을 정리하며,
그 내용을 정리해보려고 글을 써봅니다.
저의 생각을 정리하기 전에
간단하게 MVVM 패턴, MVI 패턴이란? 무엇이고, 데이터 흐름은 어떤지 간단하게 보고
생각을 말해봅니다.
## 간단 요약 ##
* MVVM 패턴 ?!
- Model-View-ViewModel 패턴으로, 안드로이드에서 UI 로직과 비즈니스 로직을 분리하는 목적으로 설계된 패턴
* MVI 패턴 ?!
- Model-View-Intent 패턴으로, 단방향 데이터 흐름과 불변 상태에 중점으로 설계된 패턴
## 데이터 흐름 ##
* MVVM
- View: 사용자 입력을 ViewModel에 전달
- ViewModel: 비즈니스 로직 실행, Model에 데이터 요청/업데이트
- Model: 데이터 처리 후 ViewModel에 결과 반환
- ViewModel: 상태 업데이트
- View: 상태 관찰하여 UI 갱신
* MVI
- Intent: 사용자 액션이 Intent로 변환되어 ViewModel에 전달됨
- Processing: ViewModel이 Intent를 처리하고 상태 업데이트 또는 부작용 실행
- State: 상태가 업데이트되면 View에 전파되어 UI가 갱신됨
- Effect: 일회성 이벤트(토스트, 네비게이션 등)는 별도 채널로 처리
Jetpack Compose 를 쓰다보니
Compose UI를 도입한다면 MVI 패턴이 더 효율적으로 사용 할 수 있다는 것을 다시 한번 느끼게 되었고,
그렇게 도입되어 사용한다는 것을 정리하다보니 생각하게 되었습니다.
그 이유를 조금 더 이야기 하자면,
1. 선언적으로 UI 패러다임이 일치
// Compose의 선언적 UI 모델
@Composable
fun UserScreen(state: UserState, onEvent: (UserEvent) -> Unit) {
// 상태에 따른 UI 선언 (MVI 철학과 일치)
if (state.isLoading) {
LoadingIndicator()
} else {
UserContent(
user = state.user,
onRefreshClick = { onEvent(UserEvent.RefreshRequested) }
)
}
}
2. 단방향 데이터 흐름 일치
* Compose : 상태 -> UI
* MVI : 상태 -> 랜더링
* 둘 다 예측 가능한 단방향 흐름을 촉진
3. 불변 상태 모델 공유
* Compose : 불변 상태 기반 리컴포지션
* MVI : 불변 상태 기반 상태 관리
* 버그 발생 가능성을 줄임
이렇게 정리해볼 수 있습니다.
즉, Compose가 이벤트에 따른 리컴포지션이 일어나는데 단방향성이 있는 MVI 패턴을 가진다면,
예측이 가능하여 부수효과를 가지고 제어하고 여러번 리컴포지션이 일어나는 버그 확률을 줄 일 수 있다라고 볼 수 있기 때문입니다.
조금 예제 설명을 함께하여 MVVM 패턴과 MVI 패턴의 예시를 보여보겠습니다.
// MVVM 방식 (복잡한 상태 업데이트 시)
class UserViewModel : ViewModel() {
// 여러 상태 스트림
val userName = MutableStateFlow("")
val isLoading = MutableStateFlow(false)
val errorMessage = MutableStateFlow<String?>(null)
// 컴포저블에서 각각 수집 필요
fun updateUserName(name: String) {
userName.value = name
// 다른 상태에 미치는 영향이 명확하지 않음
}
}
// MVI 방식 (통합된 상태 관리)
class UserViewModel : ViewModel() {
// 단일 상태 객체
private val _state = MutableStateFlow(UserState())
val state = _state.asStateFlow()
// 명확한 이벤트 처리
fun handleIntent(intent: UserIntent) {
when (intent) {
is UserIntent.UpdateName -> {
// 전체 상태 업데이트가 명시적
_state.update { it.copy(userName = intent.name) }
}
}
}
}
예시를 보면,
MVVM 으로 하게 되면 여러 상태를 가지게 되고, 개별 StateFlow로 인해 불필요한 리컴포지션이 발생됩니다.
이 부분으로 인해 동일한 화면을 한번만 업데이틀 하면되는데 여러번 업데이트 되는 불상사가 발생했었습니다.
추가로, 상태 업데이트 로직 자체가 여러 메서드에 분산되다보니 디버깅 하기에도 어려운 점이 있었습니다.
MVI 를 보면 UserState로 통합 상태로 관리하여 필요한 부분만 명시적 update 를 하여 원하는 부분만 리컴포지션할 수 있고,
모든 상태 변환을 관리하여 업데이트 포인트가 현저하게 줄어들어 디버깅 하기에 수월하게 되었습니다.
그래서 MVI 패턴이 Compose 도입에서 더 수월하게 관리할 수 있다는 것을
끝으로 마지막 저의 생각을 정리해봅니다.
'기타' 카테고리의 다른 글
[Android] 안드로이드 권장 아키텍처에 대한 생각 (2) | 2025.03.07 |
---|---|
[GitHub] 개인용 엑세스 토큰 관리 (0) | 2025.02.17 |
[ PHP ] Ubuntu 16.04에 Apache 2.4.29 + MySQL 5.7.20 + PHP 7.1.13 설치하기 (1) | 2021.07.26 |
[ VirtualBox ] Ubuntu 가상머신 이미지 파일 다운로드 및 VirtualBox에 설정 (4) | 2021.07.26 |