본문 바로가기
프로그래밍/Android

안드로이드의 구조 - MVC , MVP , MVVM

by Daniel.kwak 2018. 12. 6.

안드로이드를 처음 접할때 보통 액티비티에 안에 모든 작업을 수행하도록 코드를 짜는 경우가 많을것이다.

가령, 액티비티 내에서 버튼 클릭 이벤트를 만들고, 해당 이벤트안에서 UI변경이나 데이터를 가져와서 넣어주거나 갱신된 데이터를 UI에 표현까지 모두 하나의 액티비티 안에 있는 경우이다. (반성한다.)


당연히 이렇게 코드를 짜다보면 서버와의 통신 부분이 추가되거나, 점차 기능이 추가될수록 가독성도 떨어지고 유지보수가 힘들어지는 코드로 가게 된다.


점점 화면이 복잡해지고 view에 의해 제어되는 로직들이 많아짐에 따라서 이를 분리하려는 노력들이 계속 진행되어왔다


MVC

웹 서비스 개발자들이 가장 먼저 접하는 패턴일 것이다.

Model : 데이터를 다루는 영역이다. 비지니스 로직이 들어있고, 네트워크, 데이터베이스 API를 관리하는 역할이다. 애플리케이션의 두뇌 역할이고, 뷰나 컨트롤러에 종속되지 않기 때문에 독립적으로 재사용이 가능하다.


View : 뷰는 모델의 표현이다. Model로부터 전달받은 데이터를 보여주며 UI를 그리고 사용자가 앱과 상호작용할 때 컨트롤러와 통신하는 책임을 맡는다. 


Controller : 컨트롤러는 앱을 묶어주는 접착제이다. 예를 들어 뷰가 컨트롤러에게 버튼이 눌렸다고 알려주면, 컨트롤러는 상황에 따라 모델과 어떻게 상호작용할지 결정한다. 모델에서 데이터가 변화되는것에 따라, 컨트롤러는 뷰의 상태를 적절하게 업데이트 하도록 결정한다. 안드로이드에서는 주로 액티비티와 프래그먼트로 나타난다. 




예시 그림을 살펴보면 View는 화면에 출력하는 xml , Controller는 xml의 데이터를 받아서 Model과 상호 통신하는 Activity 혹은 Fragment  , 마지막으로 Model은 데이터를 받아서 처리 후 Activity로 돌려준다.


MVC는 모델과 뷰를 훌륭하게 분리해준다. 모델이 어디에도 종속되지 않으며 뷰는 유닛 테스트 레벨에서 그다지 테스트 할 것이 없어서 쉽게모델을 테스트할 수 있다. 하지만 컨트롤러에는 몇 가지 문제점이 있다.

1)테스트 용이성 - 컨트롤러가 안드로이드 API에 깊게 종속되므로 유닛 테스트가 어렵다.

2)모듈화 및 유연성 - 컨트롤러가 뷰에 단단히 결합되며, 뷰의 확장일 수도 있다. 

3)유지보수 - 시간이 지남에 따라 보다 많은 코드가 컨트롤러로 모이면서 비대해지고 문제가 발생. (스파게티 코드 가능성, 복붙 코드, 하나의 클래스에 모든게 담겨있거나)


MVP

MVP는 컨트로럴의 책임에 묶이지 않고 뷰와 액티비티가 자연스럽게 결합하도록 한다.

Model : MVC와 동일하다.


View : 유일한 변화는 액티비티/프래그먼트가 뷰의 일부로 간주된다는 것. 따라서 이들이 서로 연관되는 자연스러운 현상을 굳이 극복할 필요가 없다. 액티비티가 뷰 인터페이스를 구현해서 프리젠터가 코드를 만들 인터페이스를 갖도록 하는것이 좋다. 이렇게 하면 특정 뷰와 결합되지 않고, 가상 뷰를 구현해서 간단한 유닛테스를 실행할 수 있다.


Presenter : 본질적으로 MVC의 컨트롤러와 같지만, 뷰에 연결되는것이 아니라 그냥 인터페이스다. 이에 따라 MVC가 가진 테스트 가능성 문제와 모듈화/유연성 문제도 해결한다. (일부는 프리젠터에 어떤 안드로이드 API도 들어가서는 안된다고 주장)



프레젠터의 코드를 살펴보면, 모델과 뷰를 가지고 있으면서 뷰에게 무언가를 표시하는 방법을 지시하는 대신, 표시할 내용만 전달한다. 

액티비티를 프리제넡에 묶지 않고 이 작업을 수행하려면 액티비티가 구현할 인터페이스를 생성해야 한다. 

그러나 프리젠터 역시 점점 비지니스 로직이 모일 수 있는 단점이 존재한다. 



MVVM

안드로이드 데이터 바인딩을 사용하는 MVVM은 테스트 모듈화가 쉽고 뷰와 모델을 연결하기 위해 사용해야 하는 연결코드를 줄일 수 있는 장점이 있다. 

Model : MVC와 동일하다.

View : View는 ViewModel에 의해 보여지는 Observable 변수와 액션에 유연하게 바인딩 된다.

ViewModel : 뷰모델은 모델을 래핑하고 뷰에 필요한 옵저버블 데이터를 준비. 또한 뷰가 모델이 이벤트를 전달할 수 있도록 Hook을 준비한다. 


뷰에 대한 의존성이 전혀 없으므로 유닛테스트가 쉬워진다. MVP 패턴처럼 테스트를 위한 가상 뷰를 만들 필요 없이 테스트 할 때 모델이 변경되는 시점에 옵저버블 변수가 제대로 설정됐는지만 확인하면 된다. 

그러나 뷰가 변수와 표현식 모두에 바인딩 될 수 있으므로, 시간이 지남에 따라 관계없는 프리젠테이션 로직이 늘어나 XML 코드를 추가하게 될 수 있다.