[Android] MVI 너.. 뭔데 ?

JJAE WON·2025년 6월 17일
post-thumbnail

2022년 취업 성공했을 무렵.. 모든 기술 인터뷰에서 등장하는 패턴은 MVVM 이었다.
나도 실제로 MVVM 에 대한 공부를 많이 했었고 MVVM구조와 함께 클린 아키텍처에 대한 공부도 많이 했었다.
물론 회사에서 실무를 할 때도 MVVM 구조에 신경을 많이 쓰며 상태 관리를 했었다.

그러나…..

2025년 퇴사를 한 후 다시 공부를 시작하니 채용 공고에서 MVI가 자주 등장하는 것을 보았다.

사실 종종 MVI 의 존재에 대해서는 듣곤 했었다..
하지만 이미 안락한 회사에 있는 나로써는 그것에 대해 직접적인 탐구를 미루고 있었다.. ( ….조금은… 그래도.. 되잖아요..🥲 )

부랴부랴 급하게 다양한 아티클도 읽어보고 좋은 동료와 같이 프로젝트 진행하며 MVI 이놈 자식을 알아가 보았다.
이 글 마저 조금 늦은것 같지만 배움에 늦음이 어딨냐구요. 어딨냐구요 !!! 🥲


MVVM , MVP.. 이런 아키텍처 모델들은 모두 원활한 유지보수와 협업을 위해 등장했다.

한 파일에 너무 많은 화면과 데이터, 비즈니스 로직들이 들어있으면 관리하기도 힘들고 다양한 사람들과 협업하기도 힘들기 때문에..

나는 늘 일종의 계약서라고 생각했다.


기존 MVVM 동작 방식

그런 관점에서 MVVM은 3개의 계약 항목이 있는 것이다 !

  • View: 사용자에게 보이는 화면 (Activity, Fragment, Compose UI)
  • ViewModel: UI 데이터를 들고 있고, 로직도 담당
  • Model: 실제 데이터를 불러오는 친구들 (Repository, API, DB 등)

실제 동작 방식

🤔 사용자가 좋아요 버튼을 클릭해서 좋아요 수를 보여주는 TextView의 숫자가 1 증가해야 한다면 ?

사용자가 버튼 ‘클릭’ ( View )
→ 현재 좋아요 수 데이터 가져오기 & 업데이트 ( ViewModel → Model )
→ ViewModel 에서 가지고 있는 데이터에 반영
→ 데이터를 바라보고 있던 View에서 화면 업데이트


근데 MVVM 만 써도 충분한거 아냐 ??

이제 문제는 ViewModel 이 할 일이 많다고 찡찡되기 시작한 것.

앱의 규모가 커질수록

  1. ViewModel이 너무 많은 로직을 수행하게 된다.
  2. ViewModel에 있는 화면에 보여지는 데이터들도 점점 많아짐

XML + 양방향 바인딩 !

android:text="@={viewModel.name}"

xml 에서 라이브데이터 쓸 때 사용했던 양방향 바인딩은 편해보였지만..

디버깅이 어렵다는 단점과 어디서 데이터가 바뀐건지 어려워 사이드 이펙트도 많이 생김….

그래서 사실 읽기 전용 변수를 ViewModel에 선언한다던지,

Compose에서는 collectAsState() 또는 remember 들을 사용해서 ‘상태’ 를 관리한다는 개념이 점점 등장하기 시작.


그럼에도 문제점. Multiple State를 가질 수 있게 된다.

  • View와 비즈니스 로직(ViewModel or Presenter) 가 서로 각자 상태를 따로 갖고 있음
  • 그리고 그 상태들을 맞춰주기 위해 Observable, Callback, LiveData.observe() 등등을 써서 서로 맞춰줘야 함
isLoading = true 상태인데 data != null이면?
error != null 인데 isLoading = false이면?


MVI 란 ?

Cycle.js 프레임워크의 단방향성과 Cycle Nature에서 영감을 받은 안드로이드를 위한 최신 아키텍처 패턴.

Model - View - Intent순환형 구조를 가지고 있다.

MVI 는 기존의 아키텍처들과 다르게 단방향 데이터 흐름(Unidirectional Data Flow) 을 가진다.

마치 대화 하듯이 ! 내가 말을 걸면 컴퓨터가 듣고나서 답변을 해주고.. 그리고 또 내가 말하는 것 처럼..

하나하나 레이어들을 살펴보자 !

1️⃣ Intent

우리가 알고 있는 전달하는 그 Intent 아님 x

유저가 한 행동(버튼 클릭, 텍스트 입력 등)을 나타내는 의도(intent) 를 정의하는 부분

2️⃣ Model

이 친구가 제일 중요하다.

Model은 앱의 ‘상태’ 를 나타낸다.

처음에 이 상태의 개념을 어떻게 잡아서 개발해야 하는지 혼란스러웠는데

‘Model은 View가 화면에 그려야할 것들을 가지고 있는 Entity’

라고 정리 된 글을 보니 개념이 딱 ! 잡혔다.

한 화면 안에 들어있어야할 내용들을 한 곳에 정리해 놓은 정리문서 !

화면 안에 여러 상태(다중 state)가 따로따로 존재하지 않고, 단일한 진짜 상태 한 덩어리로 관리됨

그래서 상태 덩어리는 절대 바뀌지 않음 !! , 필요하다면 새로운 객체로 교체함

3️⃣ View

화면을 구성하는 부분

역할

  • render(viewState: Model) 한 번의 메서드로 현재 상태를 그리기만
  • 사용자의 입력은 Intent로 전환해서 ViewModel에 전달

특징

  • 단순히 읽기만 하는 수동적(observer) 구조


🤔 화면 이동은 ? 토스트 메세지는 ? SideEffects !!

여기에서 추가적으로 알고 있어야 하는 개념이 등장 !

한 화면에서 Model로 가지고 있기 애매한 것들과 ..

안드로이드 앱 개발을 하다보면 어떻게 모~~~든 것이 ‘상태(Model)’로 취급될 수 있나 !
나는 네트워크 체크도 해야하고 !! 화면 밖으로 움직이는 화면 이동도 해야하는데 ?

- 토스트 메세지 
- 화면 이동
- 파일 저장
- 권한 요청

이런 것들은 단순히 한번만 실행하면 되는 것이기 때문에
화면에서 이것들을 가지고 있어야 할 필요가 없음.

그래서 얘네들은 ‘Side Effect’로 분리해서 따로 처리해야한다는 점.


어디까지 상태이고.. 어디까지가 사이드 이펙트인가 ?

하지만 모든 것은 정의하는 관점에 따라 다르기 때문에 개발자가 맞는 판단으로 토의를 통해 정해야하는 부분도 있다고 느껴진다.

토스트 노출을 무조건 사이드이펙트로 볼 것이냐 ? 상태로 볼것이냐 ?

이런 것들을 정의하는 과정이 자연스레 시간이 오래 걸리고. 단점으로 본다면 보여질 수도..

참고하면 좋은 글


장점

  • 상태가 한곳으로 집중되어서 버그 추적이 쉬움
  • 데이터 흐름이 명확해서 예측 가능
  • View는 상태만 그리는 순수한 뷰 → 테스트 쉬움
  • Side Effect를 분리해서 복잡도 줄임

단점

  • 처음 도입할 땐 구조가 살짝 복잡하게 느껴짐
  • 작은 앱에는 과한 구조일 수도 있음
  • Intent, State, Effect 전부 분리하느라 코드가 길어짐

🎯 마무리하며

MVVM 에서부터 Compose .. 그리고 단방향 데이터 흐름을 권장하는 구글 아키텍처까지 모두 고려해보면
자연스레 사용하게 되는 아키텍처라고 생각한다.

클라이언트는 기술 변화가 빠르다는 이야기를 체감하고 내가 그 기술의 변화 과정을 함께하고 있으니
문득 재밌다는 생각도 들었다.

다음 글에서는 실제로 MVI 를 사용하여 개발해본 이야기와 함께 사용해볼 수 있는 라이브러리도 함께 소개해보겠습니당



참고

상태 지향 아키텍처 MVI를 소개합니다- MVI on Android

안드로이드를 위한 MVI (Model-View-Intent) 아키텍쳐 튜토리얼: 시작하기

MVI 아키텍처로 마이그레이션 및 설계 살펴보기

profile
앱개발왕 찐천재가 되고싶다.

1개의 댓글

comment-user-thumbnail
2025년 10월 13일

신규 프로젝트에 MVI를 적용해보려고 하려던 참에 좋은 글 읽고 갑니다!

답글 달기