안드로이드에서 앱을 설계할 때, 사용할 수 있는 다양한 패턴이 존재한다.
- MVC (Model - View - Controller)
- MVP (Model - View - Presenter)
- MVVM (Model - View - ViewModel)
- MVI (Model - View - Intent)
- etc
해당 패턴을 사용하는 이유는 여러가지 로직의 다분화와 클래스간의 의존성을 낮추는데에 있으며, 해당 과정을 통해 유지보수성과 테스트 가능성을 높히고, 더 나아가 지속가능한 개발에 목적을 가지고 있다.
UI 계층(MVx)의 대원칙
- 어떤 경우든 Model은 분리되어야 한다. Model은 데이터를 다루는 모든 비즈니스 로직을 처리하는 계층
- View의 역할을 할 수 있는 한 최대한 분리시켜야 한다.
- Android에서 발생할 수 있는 특수한 상황을 잘 처리할 수 있어야 한다.
- Context의 처리
- 생명 주기 이벤트 처리
- Configuration Change
- 가능한 많은 부분이 테스트 가능하도록 구성해야 한다.
1. MVC
- Model 계층은 비즈니스 로직을, View는 UI 로직을 수행한다.
- Controller는 View를 선택하며, Model로 부터 데이터를 받아 수행한다.
- View는 Controller에서 받은 데이터를 화면에 그리는 작업을 한다.
아래와 같은 이유로 MVC 패턴은 Android 환경에서 제대로 동작하지 않는다.
모바일 환경의 문제
- 알림, 전화와 같은 제 3의 이벤트가 발생할 수 있음.
- 복잡한 라이프 사이클 처리
- UI 로직 분리의 어려움. HTML의 경우 선언형으로 리스트를 독립적으로 구현할 수 있으나, Android의 경우 RecyclerView와 Adapter의 경우로 UI와 독립적으로 구현할 수 없음.
Activity와 Fragment
- View와 Controller의 기능을 모두 담고 있어, 분리가 어렵다.
- XML의 경우 기본 레이아웃만을 제공, UI 로직이 들어갈 여지가 없다. (ex : 리스트 구현)
Fat Activity && Fat Fragment
- Activity와 Fragment에 많은 로직이 들어가, Unit Test를 만들기 어렵다. (대부분 테스트 케이스에 Context가 필요하게 됨)
해당 문제를 해결하기 위한 방법
View의 다중 분리
- XML의 <include> 태그를 사용하여 XML 정의를 여러 개로 분리하기
- 분리한 View를 A & F가 아닌 별도의 Controller를 통해 제어한다.
ViewController 생성
- Activity & Fragment는 View도 Controller도 아니도록 처리하며 (상태 초기화, 라이프 사이클 처리와 같은 최소한의 로직만 수행)
- 각 View마다 ViewController를 만들어 View의 동작에 관련된 동작 및 컨트롤러 로직을 ViewController로 위임한다.
- 설정 변경 및 3자 이벤트에 따라 종료되지 않도록 구현한다.
그래도 해결할 수 없는 문제
- 사용자 이벤트 및 외부 이벤트의 효과적인 처리가 어렵다.
- Context 이슈
- ViewController가 Context를 가져야 하는 작업이 존재
- 테스트의 어려움 : 테스트 케이스에 Context가 필요하므로, 테스트 작성도 어렵고 실행도 느리다.
2. MVP (Model - View - Presenter)
View 계층
- 비즈니스 로직을 분리하고, UI 관련 비즈니스 로직은 Presenter로 옮긴다.
- View는 Presenter의 요청에 의해 수동적(Passive)으로 UI 로직을 처리한다.
Presenter 계층
- View에게 표시할 데이터를 전달하며, View 선택은 View가 담당한다.
- Presenter는 Model과 View의 매개체이다.
Model
- 데이터 관련 비즈니스 로직을 수행하며, 다른 계층과 독립적인 계층이다.
개방-폐쇄 원칙
- View보다 더 높은 수준의 요소인 Presenter를 View의 변경으로부터 보호한다.
- View와 Presenter는 interface를 통해 각자를 참조하도록 함으로 의존성 역전의 원칙이 적용된다.
MVP의 단점
- View가 Presenter를 기본적으로 참조하며, 잘못된 프레젠터 인터페이스 사용을 막기는 어렵다.
- 애플리케이션이 복잡해질 수록 View와 Presenter 사이의 의존성이 강해진다.
MVP의 장점
- 로직을 분리하여, Fat Activity & Fragment를 방지할 수 있다.
- 플랫폼의 의존적인 UI 처리는 View에 몰아 넣어, Presenter 로직은 쉽게 테스트가 가능하다.
MVP의 주의사항
- 기본적으로 Presenter에서 View로 데이터를 전달하고 받을 때 비동기 방식을 기본으로 한다.
- 설정의 변경으로 UI 상태가 혼재할 수 있음.
- View의 사용자 입력을 Presenter에 전송할 때, Presenter도 가지고 있지만, View 역시도 UI state를 가지고 있음.
MVC와 MVP 둘다 러닝커브가 높지 않은 패턴으로, 비즈니스 로직과 UI 로직을 분리하여 작업하여 패턴을 가지지 않고 개발하는 것보다 확장 가능성 및 오류를 수정하는 측면에서 장점을 가지고 있다.