본문 바로가기

Architecture, Pattern

[Pattern] MVC/MVP/MVVM

#What

MVC / MVP / MVVM

널리쓰이는 아키텍처를

안드로이드 관점에서 알아보도록 하겠습니다. 

 

*아키텍처 패턴

아키텍처 패턴은 주어진 문맥 안에서 소프트웨어 아키텍처의 공통적인 발생 문제에 대한 일반적인, 재사용 가능한 해결책을 의미한다. 아키텍처 패턴은 소프트웨어 디자인 패턴과 비슷하지만 더 넓은 범위에 속한다

 

#Preview - 이해하기 전에

MVC  = Model View Controller

MVP = Model View Presenter

MVVM = Model View ViewModel

 

Android 아키텍쳐의 목표

-> 거대해지는 프로젝트를  'UI + 비즈로직+ 데이터 처리' 역할 분리를 통해 '유지보수, 테스트, 재사용' 을 쉽게 하기

 

Model, View는 동일하나, Controller - Presenter - ViewModel로 변화해 왔음을 볼 수 있다

-> 즉 'Controller -Presenter -ViewModel' 에 문제를 느껴 새로운 패턴을 만들었다는 사실

 

xxxModel.java, xxxPresenter.java 처럼 파일명 뒤에 역할명이 붙는다고 생각하지 말 것

-> 구분 위한 카테고리 일 뿐

 

 

# MVC

1) 모델 :  앱의 '데이터 + 상태 + 비즈로직'을 담당  == 데이터 처리 

  • 통신/DB 처리를 담당하는 '데이터 관리' 의 핵심
  • UI 외적인 부분이므로 View와는 완전 분리 필요(뷰에 데이터가 어떻게 보여질지 모델은 모름)

2) 뷰 : 데이터가 보여질 화면/뷰/레이아웃        ex) xml 파일, 'android.view'

  • 어떤 데이터가 어느 로직을 거쳐 뷰에 보여질지 뷰는 모름

3) 컨트롤러 : '뷰'와 '모델'간 중재자/컨트롤러        ex) Activity, Fragment

  • 앱이 어떻게 동작 할 지 모르는 '모델'과 '뷰'를 이어 준다
  • '뷰'로 부터 이벤트가 들어오면 어떤 동작을 취할 지 '모델'의 수행을 결정
  • 반대로 '모델'의 수행 결과를 뷰에 표시 역할도 담당

 

[요약]

  • '모델'과 '뷰 '분리는 확실
  • '모델' 유닛 테스트도 가능(분리가 확실하니)
  • 상대적 간단하고 구현이 쉬움

 

[고려할 점]

Android에서는 그닥 적합하지 않은 이유

  1. 컨트롤러와 뷰의 결합도가 높음
    • Controller(Activity,Fragment)와 View(.xml) 의 완벽한 분리가 불가하기 때문이다.  
    • 뷰 변경에 따라 컨트롤러도 변경해야 하는 경우 발생도 잦음
  2. 컨트롤러가 역할 부담을 많이 지며 비대해지기 쉬움  
    • 어찌됐든 저찌됐든 UI 관련 로직은 Activity, Fragment에서 처리해야 하니까.
    • => Controller 비대 =>  유지보수가 힘들어지고 가독성, 코드 재사용, 확장성 등이 떨어질 수 밖에 없음
  3. 컨트롤러 유닛 테스트가 어려움
    • Controller(Activitiy, Fragmen)는 안드로이드 API이며 대부분 Context를 필요로 하므로 

 

# MVP

1) 모델 : MVC와 동일

 

2) 뷰 : 데이터가 보여질 화면/뷰/레이아웃(MVC와 동일내용) (+ Activity/Fragment)         

  • Activity/Fragment는 View 역할도 하면서 최소한의 Controller역할도 한다
  • 프리젠터에게 interface를 전달 해, 프리젠터로 하여금 전달된 인터페이스로 뷰를 제어하게끔 동작

3) 프리젠터 : 컨트롤러와 비슷해 보이지만 인터페이스를 통해 뷰와 상호작용한다는 점에서 다름(뷰의 기능을 인터페이스 호출을 통해 사용)

 

[요약]

  • '모델'과 '뷰 '분리 보다 더 확실(Activity와 모델 사이에 프리젠터 개념이 추가 됐으므로)
  • '모델' 유닛 테스트가 용이(분리가 확실하니)
  • '프리젠터'가 Android API에 연결 되지 않아서 유닛테스트 가능(인터페이스를 이용해 Mock 뷰 객체 생성 가능) New

[고려할 점]

  • 프리젠터 역시 컨트롤러처럼 역할 부담을 많이 지며 비대해지기 쉬움 
  • View는 어찌됐든 presenter를 참조 할 수 밖에 없음
  • Configuration 변경 시 등의 UI 데이터 보존을 위한 처리를 고려 해야 한다는 점 등의 문제가남아 있음

 

         

# MVVM

1) 모델 : MVC와 동일

 

2) 뷰 : 데이터가 보여질 화면/뷰/레이아웃 + Activity/Fragment (MVP와 동일내용)  + Observe Data

  • ViewModel의 데이터를 관찰해서 UI를 갱신. MVC/MVP와 달리 '뷰'가 능동적으로 바뀜.  ('뷰'가 뷰모델이 가진 데이터를 observe 하고 있을 테니 변경하려면 변경해!!)
  • 관찰 방식으로는  LiveData,Observable, Flow 등이 있다

3) 뷰모델 : UI에 표시할 데이터를 가지고 있다 (뷰가 observe 할 데이터를)

 

 

[요약]

  • View에 표시할 데이터니 UI 상태값 등은 ViewModel이 관리하고, View는 그것을 관찰한다
  • View가 관찰하면서 알아서 UI 업데이트를 하니, ViewModel은 View에 데이터 셋을 신경 안써도 되므로 부담이 줄어듦(ViewModel 입장에서는 어떤 View가 데이터 가져다 쓰는지 전혀 모르는 상태)
  • 다시 말해, View는 관찰 및 UI 업데이트에만 집중하며 UI 상태값이나 데이터 정보는 관리하지 않는다
    • => So, 극단 적인 예로는 잘 만든 ViewModel 하나로  휴대폰과 네비게이션 화면에서 동일 데이터를 다른 View로 보여주기가 가능해지는 것
  • 앞서 모델을 '데이터 관리' 의 핵심이라고 했던 것 처럼, ViewModel 의 이름의 뜻을' View에 대한 데이터 관리' 라고 생각하면 좋을 듯 하다
  • View와의 결합도가 낮으므로 ViewModel 재사용성 UP!

 

[고려할 점]

  • 설계가 상대적으로 어려움
  • 기본적으로 LiveData나 Coroutine-StateFlow와 같은 개념 학습이 필요
  • ViewModel이 커질 위험성 고려 

 


 

# 번외 - MVVM에서의 ViewModel vs AAC의 ViewModel 

Q : 두 ViewModel은 같은 ViewModel일까?

 

AAC-ViewModel은 화면회전, 글자 크기 변경 처럼 Configuration 변경에 따른 Activity 재생성 시 ViewModel은 영향을 받지 않기 때문에(생명 주기가 다름) 가지고 있던 데이터를 재생성된 Activity에게 다시 제공해줄 수 있다.

 

그리고 무엇보다 AAC-ViewModel은 androidx.lifecycle.ViewModel API를 상속 받아야 함(Context 필요 시 AndroidViewModel)

 

A : 결론은 다른 의미의 ViewModel이지만, AAC-ViewModelMVVM-ViewModel 패턴에 적용해서 쓰기 적절하니까 

     구글에서도 이렇게 쓰라고 동일하게 작명하지 않았을까...

 

 

 

# 기타

  • 각각의 패턴의 범위에 대한 개발자들의 생각은 다양하며,  암묵적으로 합의를 만들어가는 과정 인 듯 
  • 패턴 각각의 장단점을 파악해 필요한 부분을 적용해야 할 듯 

 


참고 사이트 - https://academy.realm.io/kr/posts/eric-maxwell-mvc-mvp-and-mvvm-on-android/

 

 

문제 있을시 알려 주세요.

 

좋은 하루 되세요!