Image
Android/Architecture

Android MVVM 아키텍처의 등장 배경과 필요성

목적

  • MVVM 아키텍처가 등장하게 된 배경을 이해한다.
  • MVVM 아키텍처의 필요성을 이해한다.

 

MVVM 아키텍처의 등장 배경

안드로이드의 아키텍처는 크게 MVC, MVP, MVVM 3가지로 나뉜다. 아키텍처는 MVC, MVP, MVVM 순서로 나왔는데 각각은 이전 아키텍처를 개선하여 나온 것이다. 어떤 점에서 한계점이 있었고, 어떤점이 개선되었는지 아래에서 각각의 특징을 살펴보자.

 

MVC : View와 Controller를 Activity, Fragment 클래스에서 담당

그림1. MVC 아키텍처 

 각 클래스가 강하게 결합되어 있을 경우, 한 클래스가 변경되면 다른 클래스 또한 같이 변경되어야 하기 때문에 유지보수 하기가 어렵다. 웹에서 널리 사용되었던 MVC 아키텍처에서는 안드로이드에서 사용하기 위해서 View단과 Controller단이 Activity, Fragment에 함께 구현되어 있었기 때문에 매우 강하게 결합되어 있었다. 이 때문에 특정한 기능이 하나가 변경되면, 다른 곳에도 영향을 미쳤으며, 이로 인해 제공하는 서비스가 많아질 수록 유지보수를 하기가 어려워졌다. 

 특히 View가 Controller와 붙어있다 보니 View, Controller에 해당하는 Activity, Fragment 클래스가 Model 클래스에 의존성이 강해 테스트가 어려웠다이러한 Activity와 Fragment의 역할이 거대해지는 한계점을 극복하기 위해 기존의 MVC 아키텍처에서 탈피하여 MVP가 만들어지게 된다.

 

MVP: Presenter와 View 사이의 강한 의존성

그림2. MVP 아키텍처

 MVP에서 View에 해당하는 Activity와 Fragment는 단순히 UI를 보여주고 사용자와 상호작용하는 역할만 한다. 기존 Controller의 역할이 Presenter로 분리되어 Activity, Fragment에서 분리되었다.

 Presenter은 View로부터 입력값을 받고 입력값에 해당하는 동작을 Model에 입력한 후 Model에서 응답값을 받아 View를 업데이트 시켜주는 중개자 역할을 한다. 여전히 MVP의 경우 여전히 View와 Presenter 사이의 강한 의존성이 있어서, View가 바뀌면 Presenter도 변경을 해야하는 한계점이 있었다. 이러한 의존성 문제를 극복하기 위해 나온 것이 바로 MVVM이다.

 

 

MVVM: ViewModel과 View 사이의 의존 관계를 약화

 

그림3. MVVM 아키텍처

 MVP의 View와 Presenter사이의 강한 의존관계를 해결해서, 약한 의존성으로 바꾸기 위해 나온 것이 MVVM 아키텍처이다. MVP에서 Presenter은 View를 조작하는 로직이 있었지만, MVVM 아키텍처에서는 ViewModel에서 UI를 조작하지 않는다. View에서는 ViewModel에서 제공하는 데이터를 관찰하여 UI를 업데이트 시킨다.

 이는 리액티브 프로그래밍 패러다임과도 연관되어 있는데, LiveData라는 Activity 혹은 Fragment의 생명주기를 인식하는 발행자(Publisher)를 통해 View에서는 해당 값을 구독(Subscribe)한다는 점과 데이터가 바뀔 때 그것에 반응하는 메서드를 수행하게 만든다는 점에서 그렇다. 이러한 과정을 통해 받아온 데이터는 보통 View에 binding 된다. 보통 Android Jetpack 구성요소인 DataBinding 라이브러리를 사용한다.

 즉, View와 ViewModel 사이에서 View가 ViewModel에만 의존성을 갖게 하고, ViewModel은 View에 대해 의존성을 제거한 MVVM 아키텍처가 만들어졌다.

 

*LiveData는 Coroutine Flow에 생명주기 인식을 더한 기능으로 이해하면 편하다.

 

 

MVVM 아키텍처의 필요성

상태 데이터 저장 위치

 보통의 앱이라 하면 프로그램 런처의 단일 진입점이 있고, 해당 진입점(디렉터리)만을 사용하여 애플리케이션이 구축된다. 대표적인 예로는 자바 WAR 파일 Rails 또는 NodeJS 코드의 단일 디렉토리 구조가 있다. 하지만 안드로이드 앱은 4대 컴포넌트라 불리는 Activity, Service, Content Provider, Broadcast Receiver을 비롯하여 Fragment 등의 구성요소가 있으며, 각 구성요소의 진입지점을 통해 앱으로 진입이 가능하다. 예를 들어 Activity 시작으로 앱에 진입할 수 있고, Broadcast Receiver에서 Broadcast Intent를 호출받아 앱으로 진입이 가능하다. 

 

 또한 구성요소가 계속해서 살아있는 웹앱과는 다르게, 모바일에서 사용할 수 있는 리소스의 한계로 인해 운영체제가 언제든지 앱 구성요소를 제거할 수 있으며, 사용자도 자신이 수행하는 어플리케이션에 대한 강제 종료가 가능하다. 이러한 강제 종료로 인해 Activity나 Fragment에서 보여지던 데이터가 언제든지 사라질 수 있었으며, 이러한 데이터의 복구를 위해 Activity와 Fragment의 Lifecycle에서는 데이터를 저장하고 복구하는 로직을 수행할 수 있는 객체를 두고 있다. 하지만, 최선의 방법은 앱 구성요소는 언제든지 제거될 수 있으므로 앱 구성요소에 앱 데이터나 상태를 저장하는 것을 피하는 것이다. 

 

 MVVM아키텍처에서는 이를 해결하여 View(Activity, Fragment) 의 Lifecycle 보다 긴 Lifecycle을 가지는 ViewModel에 데이터를 저장하고 Model과 통신하는 ViewModel을 계층을 만들어내어 ViewModel에 데이터를 저장한다. 이러한 과정을 통해 View가 파괴(Destroy)되고 다시 생성(Create) 되더라도 View에서 보여지던 데이터는 날아가지 않는다. 

그림4. ViewModel의 Lifecycle 출처: 안드로이드 공식 문서

 

유지 보수 용이성

 

  유지보수에서의 핵심은 각 부분이 독립적이 되어 한 부분의 변경이 다른 부분에 영향을 미치지 않는 것이다. 하나의 클래스를 예를 들면 특정한 메서드 내부에서만 사용하는 변수를 지역변수로 선언하지 않고 전역변수로 선언할 경우 해당 변수는 클래스와 강하게 결합된다(의존성이 생긴다). 반대로 지역 변수로 선언할 경우 클래스와 의존성이 없어진다.

 

 작은 부분인 클래스를 예로 들었지만, 프로그램의 관점에서도 똑같은 현상이 일어난다. A클래스가 B클래스에 강하게 결합되어 있을 경우 B클래스를 초기화 시켜 넣어주여야 A클래스의 테스트가 가능하기 때문에 프로그램을 유지 보수하기가 어려워지며, B클래스에 변경 사항이 있을 경우에 A클래스도 변경이 일어나야 하기 때문에 유지보수가 어려워진다. 

 

 MVVM 아키텍처에서는 ViewModel단에서 View와 Model 사이의 의존 관계를 끊어주었다. 또한 ViewModel이 View에 대한 의존성을 갖지 않는다. 이로 인해 테스트를 작성하기가 용이해졌으며, 각 부분이 다른 부분에 독립적이 되어 한 부분을 변경하더라도 다른 부분에 영향을 미치는 것이 줄어들었다. 

 

 유지 보수의 핵심은 아키텍처 각 부분의 결합도를 약하게 만드는 것이다. MVVM에서는 1차적으로 아키텍처단에서 결합도를 약하게 만듦으로써 유지 보수를 쉽게 해줬다. 이 외에도 의존성을 약하게 만들어주기 위해, 의존성을 외부에서 주입하는 Dagger-Hilt와 같은 라이브러리들이 사용되고 있다. 


참고

앱 아키텍처 가이드 - developer.android.com/jetpack/guide?hl=ko  

 

그림 출처

그림 1 ~ 그림 3. 직접제작 : 저작권은 글 작성자에게 있습니다. 

그림 4. 안드로이드 공식 문서 ViewModel 

반응형

 

이 글의 저작권은 '조세영의 Kotlin World' 에 있습니다. 글, 이미지 무단 재배포 및 변경을 금지합니다.

 

 

Kotlin, Android, Spring 사용자 오픈 카톡

오셔서 궁금한 점을 질문해보세요!
비밀번호 : kotlin22

open.kakao.com