늦었지만 MVVM 디자인 패턴에 대해서 공부하려는 도중에
아키텍처에 대해서 왜 배워야 하고 어떤 것들이 있고 각각의 장점이 무엇인지 살펴보려한다
공통적으로 Model 과 View 를 가지고 있다
프로그램의 Presentation Logic 과 Business Logic들을 구현함에 있어
데이터와 UI는 필수이기 때문에, M-V 사이의 의존성이 생길 수밖에 없다
Presentation Logic
실제 눈에 보이는 GUI 화면을 구성하는 코드Business Logic
데이터를 보여주기 위해서 데이터베이스를 검색하는 코드 및 GUI 화면에서 새롭게 발생된 데이터를 데이터베이스에 저장하는 코드 등 실제 작업하는 코드
앱을 개발할수록 Logic들이 커지고 복잡해짐에 따라 의존성은 더 강해지고,
앱은 유지보수하기 힘들어지게 된다
이러한 문제(의존성이 강해지는 것,etc)들을 해결하기 위해
M-V 사이의 관계를 어떻게 처리하느냐에 따라 패턴들을 구분 지을 수 있다
모든 입력들은 Controller로 전달된다
Controller는 입력에 해당하는 Model을 업데이트한다
업데이트 결과에 따라 View를 선택한다
(1:n 관계로, 여러 개의 View를 관리할 수 있다)
Controller는 View를 선택만할 뿐,
직접 업데이트는 하지 않는다
(View는 Controller를 알지 못하기 때문에)
View를 업데이트하기 위해서는 아래와 같은 방법이 있다
View를 업데이트하기 위해서는 결국 M-V 사이에 의존성이 존재한다
안드로이드는 Activity(or Fragment)가 Controller/View 모두 처리하기 때문에,
한 클래스에서 M-V-C 모두 처리하게 되는 문제점이 발생
모든 입력들은 View로 전달된다
Presenter는 입력에 해당하는 Model을 업데이트한다
Model 업데이트 결과를 기반으로 View를 업데이트한다
Presenter는 해당 View를 참조하고 있다
(View와 Presenter는 1:1 관계)
Presenter는 View와 Model 인스턴스를 가지고, Model과 View 사이의 매개체 역할을 한다
Presenter가 M-V 사이에서 관리를 해주기 때문에,
MVC 패턴과는 달리 M-V 사이의 의존성은 없다
하지만, 앱이 커지거나 복잡해질수록 V-P 간 의존성이 강해지는 문제점 발생
모든 입력들은 View로 전달된다
ViewModel은 입력에 해당하는 Presentation Logic을 처리하여 View에 데이터를 전달한다
ViewModel은 View를 참조하지 않기 때문에 독립적이다
(ViewModel과 View는 1:n 관계)
View는 자신이 이용할 ViewModel을 선택해 바인딩하여 업데이트를 받게 된다
(Command 패턴이나 Data Binding을 이용하여 V-VM 간 의존성을 없앨 수 있다)
Model이 변경되면 해당하는 ViewModel을 이용하는 View가 자동으로 업데이트된다
ViewModel은 View를 나타내주기 위한 Model이자, View의 Presentation Logic을 처리한다
MVP와 마찬가지로 M-V 간의 의존성이 없고, MVP처럼 V-VM이 1:1 관계가 아닌 독립적이기 때문에 이둘 사이의 의존성이 없어서 유지보수하기에 좋지만
ViewModel을 설계하기가 쉽지 않다
Model
애플리케이션의 상태(state)를 나타내는 데이터 모델입니다. 앱의 상태는 불변성(immutable)을 가지며, 사용자 인터페이스를 통해 변경됩니다.
View
사용자에게 정보를 표시하고 사용자의 입력을 받는 부분입니다. View는 상태를 표시하기 위해 Model의 일부를 사용하고, 사용자의 동작을 Intent로 변환하여 Presenter 또는 ViewModel로 전달합니다.
Intent
사용자의 의도를 나타내는 이벤트입니다. 사용자가 앱에서 어떤 작업을 수행하려는지를 나타내는 동작입니다. 예를 들어, 버튼 클릭, 터치 이벤트 등이 Intent로 변환됩니다.
Intent가 User를 관찰하고, Model이 Intent를 관찰하고, View가 Model을 관찰하고,
User가 View를 관찰하는 Reactive 요소로 이루어져 있다
-> RxJava 같은 라이브러리가 필수적이다
-> RxJava 예제
Intent를 이용해 User로부터 입력을 가져온다
(Anroid의 Intent와 다른 개념)
Intent는 Model에서 처리해야 하는 동작(Intended action)을 제공한다
Model은 Intent로부터 동작을 가져온다
(MVI의 Model은 단순 데이터뿐만 아니라, Application 상태(State)와 Business Logic을 관리한다)
Model은 View에 표시할 새로운 모델을 생성한다
View는 Model로부터 새로운 모델을 가져와 표시한다
단방향, 불변성 데이터를 이용해 예측 가능한 상태
서로 간 의존성 ❌
단방향 데이터 흐름
MVI 패턴은 단방향 데이터 흐름을 사용하여 상태 변화를 추적하고 예측하기 쉽습니다
이로 인해 애플리케이션의 상태 관리가 단순화되고 버그를 줄일 수 있습니다
테스트 용이성
Presenter/ViewModel은 비즈니스 로직을 포함하므로 단위 테스트가 용이합니다
View와 Model 간의 인터페이스를 분리하여 각각을 독립적으로 테스트할 수 있습니다
확장성
MVI 패턴은 각 구성 요소가 잘 분리되어 있기 때문에 애플리케이션의 확장성이 높습니다 새로운 기능을 추가하거나 기존 기능을 수정할 때 코드를 변경해야하는 범위가 상대적으로 작아집니다
RxJava와 같은 Observable 한 외부 라이브러리를 이용해야 함
복잡성
다른 아키텍처 패턴에 비해 MVI 패턴은 구현이 상대적으로 복잡할 수 있습니다
데이터 흐름이 단방향이기 때문에 초기 설정 및 상태 전이 관리가 어려울 수 있습니다
러닝 커브
MVI 패턴은 다른 아키텍처 패턴과는 다른 개념과 용어를 사용하기 때문에 처음 접하는 개발자들에게는 학습 곡선이 있을 수 있습니다
Android에서 발생할 수 있는 여러 이슈들(화면 회전, BackStack, Process death)로 인해 코드들이 복잡해지기 쉬운데,
MVI는 단방향 데이터 흐름과 불변성으로 인해 예측 가능한 상태가 만들어지기 때문에
유지보수가 좀 더 용이해진다