본문 바로가기
Android

[Android] MVC, MVP, MVVM

by 옹구스투스 2022. 7. 12.
반응형

GOAL


MVC에 대한 이해

MVP에 대한 이해

MVVM에 대한 이해


디자인 패턴?

디자인 패턴이란 소프트웨어 공학에서 특정 문맥에 공통적으로 발생하는 문제에 대해 재사용이 가능하게 만들어 놓은 해결책으로,

각각의 장단점이 다르기 때문에 상황에 따라서 맞는 디자인 패턴을 사용할 수 있다.

이러한 디자인 패턴의 종류는 굉장히 많다.

GoF에 의해 생성, 구조, 행위 패턴으로 구분한 디자인 패턴들이 있다. (싱글톤, 옵저버, 어댑터 등이 이에 해당한다.)

객체지향 프로그래밍에서 좋은 애플리케이션 설계를 위해서는 SOLID 원칙, 클린 아키텍처 등 다양한 지식을 요구한다.

오늘은 안드로이드에서 MVC, MVP, MVVM 디자인 패턴(아키텍처 패턴)에 대해서만 정리한다.

내용은 [아키텍처를 알아야 앱 개발이 보인다 - 옥수환] 책을 주로 참고했고, 저자의 블로그인 '찰스의 안드로이드' 블로그에 좋은 글이 많다.

글의 목적은 학습에 대한 정리와 혹시 글을 읽는 사람이 있다면 내가 잘못 이해한 부분을 짚어줬으면 하는 바람이니 따끔하게 지적해 주세요~!

 

안드로이드 앱 특징 및 설계 원칙

  • 하나의 진입점, 하나의 프로세스에서 실행되는 일반적인 애플리케이션과 달리 안드로이드 앱은 액티비티, 프래그먼트, 서비스, 브로드캐스트 리시버, 콘텐츠 프로바이더 등의 컴포넌트로 구성되며, 여러 프로세스로 실행될 수 있고, 진입점 또한 다양하다.
  • 짧은 시간 내에 여러 애플리케이션과 상호 작용하는 경우가 많다
    • SNS 앱에서 카메라 앱 열고 결과물 가지고 SNS 앱으로 돌아오는 경우, 쇼핑몰 앱 결제
    • 이러한 과정에서 전화나 알림, 메모리 부족으로 인해 하던 작업이 방해를 받거나 중단되는 경우?!!?!
    • 기존 데이터가 유지되어야 한다!!!!! 이를 적절히 처리해야 한다.
  • 안드로이드 컴포넌트는 언제든지 실행되고 메모리 부족과 같은 시스템 조건으로 인해 의도치 않게 종료될 수 있다.
  • 처음 안드로이드 개발을 하면 보통 액티비티나 프래그먼트 같은 UI컴포넌트에서 Context, View, 데이터, 시스템 이벤트 등을 쉽게 참조할 수 있기 때문에 대부분의 코드를 액티비티나 프래그먼트에 쑤셔 박는다. 안 그런 사람 있나??
    • 이런 경우 앞에서 말한 기존 데이터 유지 등의 문제에 대응하기 힘들고 코드가 거대해져 가독성이 떨어진다.
  • 그러므로 액티비티와 프래그먼트의 클래스 의존성은 최소화하자!
  • 가장 중요한 것은 관심사 분리이다.
관심사란 어떠한 상태나 데이터에 영향을 미치는 정보의 집합이다.
  • SOLID 원칙과도 많은 부분이 부합되며, 결국 관심사 분리라는 것은 클래스 간의 강한 의존성을 느슨하게 하면서 모듈화 시킨다.
모듈 : 다른 모듈로부터 독립적 영역이며 영역에 따라 다른 역할을 한다는 의미
  • 관심사 분리를 통해 모듈화를 성공적으로 마치면 애플리케이션 설계, 배포, 유닛 테스트와 같은 일부의 관점에서 더 높은 자유도가 생긴다.
  • 코드 또한 단순화되고 유지 보수 측면에서 더 적은 비용이 들어간다.
  • 관심사가 잘 분리될 때 독립적인 개발과 재사용성도 증대하므로, 생산성 또한 향상되는 효과를 누릴 수 있다.
  • 관심사의 분리는 추상화의 일종이다.
  • 대부분의 추상화에서처럼 인터페이스의 추가는 필수이며 실행에 쓰이는 더 순수한 코드가 있는 것이 일반적이다.

이제 이러한 관점을 가지고 MVC, MVP, MVVM을 공부한다면 어떠한 필요성에 의해 사용되고, 차이점 또한 이해하기 쉽다.

MVC(Model-View-Controller)

Model

  • 애플리케이션의 비즈니스 로직과 사용되는 데이터를 다루는 영역
  • SQLite, Room, DBMS등에 관련된 내용

View

  • 사용자에게 표현되는 영역(사용자 인터페이스)
  • 모델로부터 얻은 데이터를 표현
  • 안드로이드에선 Activity, Fragment가 뷰 역할
  • 모델에 의존한다.

Controller

  • 모델과 뷰에 의존한다.
  • 뷰로부터 입력을 받거나 특정 이벤트가 발생할 때 모델 또는 뷰를 변경한다.
  • 안드로이드에선 Activity, Fragment가 컨트롤러 역할도 한다.

Ex) 전화번호부 앱에서 전화번호를 등록한다고 할 때 사용자가 전화번호 및 기타 정보를 뷰로부터 입력받으면 컨트롤러는 해당 데이터를 모델로 전달하여 데이터베이스에 입력. 이때 모델의 상태가 바뀌면 모델은 컨트롤러를 통해 등록된 뷰에 자신의 상태가 바뀌었다는 것을 알리고 뷰는 거기에 맞게 사용자에게 모델의 상태를 보여준다.

특징

  • 모델에서 데이터를 얻어서 뷰에 표현하고 이 모든 것을 컨트롤러가 중개한다.
  • 구조가 단순하고 직관적이라 규모가 작은 앱에 MVC 디자인 패턴을 적용 시 개발 기간이 짧아지고 모든 코드가 액티비티나 프래그먼트 같은 컨트롤러에 작성되는 경향이 있어 코드를 파악하기 쉽다.
  • 하지만 앱의 규모가 커짐에 따라 액티비티나 프래그먼트에서 작성되는 코드가 점진적으로 증가하므로 유지 보수가 어려워진다.
  • 컨트롤러는 뷰와 모델에 의존적이고, 뷰는 모델에 의존적이라 결합도가 높아 유닛 테스트가 거의 불가능하다.
  • 안드로이드를 처음 개발할 때 짠 코드를 보면 이와 비슷한 형태를 가질 것이다.

MVP(Model-View-Presenter)

Model은 MVC와 동일

View

  • 사용자에게 표현되는 영역(사용자 인터페이스)
  • 모델로부터 얻은 데이터를 표현
  • 안드로이드에선 Activity, Fragment가 뷰 역할
  • 모델에 의존한다.
  • 사용자와 상호작용하며 Presenter에 이벤트를 전달하고, Presenter를 통해 사용자가 요청한 데이터를 가져온다.

Presenter

  • View와 Model의 인스턴스를 가지며 이 둘을 연결해주는 역할을 한다.
  • Presenter는 View와 1대1 관계

특징

  • 액티비티와 프래그먼트에만 쑤셔 넣던 코드들이 조금 분리가 되었다! 규모가 크지 않은 프로젝트에선 MVC 패턴보다 충분히 깔끔하다.
  • View와 Model 간의 의존성이 없고, UI와 비즈니스 로직을 분리해 유닛 테스트가 수월해진다.
  • 하지만 View와 Presenter 간의 의존성이 높고, 1대1 관계를 유지해야 하므로 Presenter를 재사용할 수 없어 View가 늘어날 때마다 Presenter도 같이 늘어나 클래스가 많아진다. 또한 애플리케이션의 기능이 추가될수록 Presenter가 거대해진다.

구현

  • 이 부분은 직접 구현해 보면 이해가 쉽다.
  • Contract Class 만들기
    • 구성 요소의 역할과 관계를 정의한다.
    • 보통 View와 Presenter를 정의하여 Contract 클래스에 인터페이스로 두고, Model은 보통 Repository패턴으로 따로 정의하여 Presenter를 구현할 때 포함한다.
  • View (액티비티, 프래그먼트) 만들기
    • Contract Class의 View 인터페이스에 정의된 메서드를 재정의하여 데이터를 화면에 나타낸다.
    • Presenter에 생명 주기 또는 클릭 이벤트에 대한 내용을 통지한다.
  • Presenter Class 만들기
    • View와 Model에 대한 인스턴스를 갖고, Contract Class의 Presenter 인터페이스에 정의된 메서드를 재정의하여, 뷰와 모델이 상호작용할 수 있게 연결해 준다.

MVVM(Model-View-ViewModel)

Model은 동일

View

  • 사용자에게 표현되는 영역(사용자 인터페이스)
  • 모델로부터 얻은 데이터를 표현
  • 안드로이드에선 Activity, Fragment가 뷰 역할
  • ViewModel에 데이터를 구독 요청하여 화면에 나타내게 한다.

ViewModel

  • View에 표현할 데이터를 관찰 가능한 Observable 타입으로 관리한다.
  • ViewModel과 View는 1:N 관계
  • ViewModel이 View에 대해 의존성을 갖지 않고 느슨하게 연결(View와 관련된 코드들은 참조하지 않는다.)

특징

  • MVP 패턴에서는 Presenter가 View에 어떤 일을 요청하는지 명백하게 확인할 수 있었지만 Presenter와 View가 강하게 결합되어 있다는 문제가 있었다. MVVM 패턴에서는 데이터 바인딩 및 LiveData 또는 RxJava와 같은 Observable 타입을 이용하여 Presenter와 View 사이에서 강하게 연결되었던 점을 끊는 데 집중한다.
  • 생명 주기 또는 사용자와의 상호 작용 등을 통해 ViewModel은 Model에 데이터를 요청한다. Model로부터 받은 데이터를 가공하여 Observable한 타입의 형태로 ViewModel에 저장한다. View와 ViewModel은 Data Binding이 이루어져야 하며, 데이터의 상태가 변경되면 해당 데이터를 구독하는 View들에 변경 사항을 통지하여 View가 갱신될 수 있도록 한다.
  • MVVM의 VIewModel을 AAC ViewModel로 많이 만들곤 한다.
    • MVVM의 ViewModel은 View와 Model 사이에서 데이터를 관리해주고 바인딩 해주는 것이 주 목적
    • AAC ViewModel은 수명 주기를 고려하여 UI 관련 데이터를 저장하고 관리하는 것이 주 목적
    • 즉, MVVM의 ViewModel은 데이터를 관리하는데, 안드로이드 앱에서의 예상치 못한 화면 작업 중단이 일어나는 경우 AAC-ViewModel을 이용하면 기존 데이터 유지를 편리하게 할 수 있다.

정리

MVC
  • 모델의 데이터를 뷰에 표현하고, 이 모든 것을 컨트롤러가 중개함, 구조가 단순하고 직관적이라 규모가 작은 앱에 적용
  • 안드로이드에서 뷰의 영역인 액티비티와 프래그먼트는 컨트롤러의 역할도 하기 때문에 코드를 파악하기 쉽지만, 앱의 규모가 커짐에 따라 유지 보수가 힘들어지고, 뷰와 모델의 결합도가 높아 유닛 테스트가 힘듦.
MVP
  • 이러한 단점을 보완하기 위해 Presenter에서 뷰와 모델의 인스턴스를 갖고 둘을 연결
  • 뷰와 모델의 의존성이 없애고 UI와 비즈니스 로직을 분리하여 유닛 테스트가 용이
  • 하지만 View와 Presenter는 1대1 관계를 유지해야 하고, 앱의 기능이 추가됨에 따라 Presenter의 코드가 거대해짐
MVVM
  • ViewModel에서 View에 관한 코드를 갖는 대신 데이터를 관찰 가능한 형태로 가지고, View에서 이를 관찰함으로써 MVP의 Presenter와 View의 강한 결합을 해결

 

Next

  1. Android 구글 권장 아키텍처 (feat. MVVM)
  2. 클린 아키텍처

References​

아키텍처를 알아야 앱 개발이 보인다 - 옥수환

반응형

댓글