[발표자료] 안드로이드 아키텍처 변천사

SSY·2024년 7월 24일
0

Architecture

목록 보기
8/8
post-thumbnail

시작하며

안드로이드 아키텍처는 많은 과정을 거쳐왔습니다. 그 중, 대표적으로 MVC, MVP, MVVM가 있고, 이 아키텍처들의 개념과 장단점과 흐름에 대해 알아보고자 합니다.

(MVI는 시간관계상 제외)

배경지식

아키텍처 변천사를 설명드리기 전, 안드로이드의 기본적인 UI 구성 방식을 알아보고자 합니다. 안드로이드는 기본적으로 아래의 컴포넌트들로 UI를 구성합니다.

  • Activity : 객체 지향 언어로 작성 된 클래스이며 xml ui 스크립트를 참조
  • layout.xml : 마크업 언어로 작성된 스크립트이며, ui를 의미

또한 참조된 컴포넌트는 위 사진과 같은 순서로 동작합니다. 첫 번째로, Activity에서 layout.xml 내, 하나의 View 위젯을 참조합니다. 그 후, 해당 위젯을 통해 onCreate라는 메서드 내에서 해당 컴포넌트 값을 읽어들이거나 변경하는 등의 작업을 합니다.

MVC

MVC패턴은 Model + View + Controller가 합쳐진 말로, 각 어원은 아래와 같습니다.

  • Model : API 통신을 포함한 비즈니스 로직과 이에 사용되는 데이터 모델 컴포넌트
  • View : UI 컴포넌트
  • Controller : Model로부터 상호작용한 결과를 View에 보여주기 위한 중계 컴포넌트

이에 따라, 각 컴포넌트의 의미를 설명드려보자면, 우선, Model에 해당하는 컴포넌트는 원격 또는 로컬 API와 통신하는 비즈니스 로직과 이에 해당하는 데이터 모델입니다.

또한 Controller에 해당하는 컴포넌트는 Activity이며, 이곳에서 ModelView를 중재하여 UI에 데이터를 뿌릴 준비를 합니다.

또한 View의 컴포넌트는 layout.xml이며, Controller로부터 데이터를 받아, 사용자에게 데이터를 보여주게 됩니다.

하지만 MVC아키텍처 패턴의 가장 큰 문제는 데이터를 가공하는 비즈니스 로직과 UI를 바인딩하는 로직이 분리되지 않았다는 점입니다. 작은 앱을 만들 때엔 상관 없겠지만, 큰 앱을 만들 땐 문제가 됩니다. 만약 위와 같은 기능이 점점 늘어난다면, 하나의 화면에 1,000줄은 금방 넘어가기도 합니다.

MVP

따라서 이러한 문제점을 해결하기 위해 마틴 파울러에 의해 MVP패턴이 제시됩니다.

이 패턴은 특정 UI에만 한정되는 비즈니스 로직을 분리하자는 취지로 나왔으며, MainActivity에 해당하는 비즈니스 로직은 MainPresenter, DetailActivity에 해당하는 비즈니스 로직은 DetailPresenter와 같이 각 모듈을 1:1 매핑하는 방식으로, UI의 비즈니스 로직을 분리시킵니다. MVP패턴의 구조를 간단하게 살펴보면 아래와 같습니다.

우선, 기존의 Activity는 위와 동일하게 존재합니다. 다만 차이는 아래와 같이 MainContract 클래스 내, PresenterView라는 인터페이스가 정의된다는 점입니다.

그리고 MainContract.Presenter인터페이스는 MainPresenter에, MainContract.View인터페이스는 MainActivity에 오버라이딩 됩니다.

위와 같이, PresenterView가 분리됨에 따라, 아래와 같이 비즈니스 로직과 UI 로직이 분리된 것을 볼 수 있습니다.

이러한 구조에 따라 MVP패턴의 구조와 흐름은 아래와 같이 묘사할 수 있겠습니다. 말씀드리기 앞서, MVP패턴과 MVC패턴에서 각 컴포넌트들이 포함하고 있는 요소들에 변화가 생기게 됩니다.

우선 View에 해당하는 컴포넌트는 Activity, layout.xml, MainContract.View인터페이스를 포함하고 있으며, Presenter에 해당하는 컴포넌트는 MainContract.Presenter인터페이스를 포함하고 있습니다.

우선, 사용자가 UI에서 MainPresenter로 이벤트를 요청합니다. 그 후, Model컴포넌트에게 API 요청 등의 작업을 통해 필요 데이터를 가져옵니다. 그렇게 가져온 데이터는 MainPresenter에 전달되며, 이는 곧 다시 MainContract.View인터페이스를 통해 Activity로 전달됨과 동시에 UI 로직의 실행 및 UI를 최종적으로 보여주게 됩니다.

[중복 비즈니스 로직의 문제점]
다만, 이는 단점이 존재합니다. MVP패턴은 UI에 해당하는 비즈니스 로직을 각각의 Presenter로 분리한다는 장점을 가졌지만, 앱이 커짐에 따라, MainContract내부가 방대해지고 관리가 어려워진다는 점이 있습니다. 또한 MainContract는 UI와 1:1매핑관계이기 때문에 해당 Presenter를 재활용할 수 없어 비즈니스 중복코드가 늘어난다는 단점이 존재합니다.

[비즈니스 로직 단위 테스팅의 문제점]
또한 비즈니스 로직 단위 테스트를 진행할 때에도 문제입니다. 단위 테스트 진행을 위해선 UI 의존성이 없어야 하는데요. MainPresenter내부를 보면 MainContract.View를 의존하고 있는걸 알 수 있고, 이는 비즈니스 로직이 UI에 의존한다는 문제가 존재합니다. 즉, 순수 비즈니스 로직 테스트를 진행하는데 있어, UI에 의존적이라는 의미고 이로 인해 단위 테스팅이 어렵게 됩니다.

만약, 단위 테스팅을 진행할 시의 코드 형상은 아래 그림과 같이 나오게 됩니다. 즉, 테스트 시작 지점과 결과 수신 지점이 달라지게 되고, 이로 인해 코드 추적이 어려워 집니다. 코드 추적을 위해선 결국, 내부 구현이 어떤지까지 타고 들어가야하는 문제가 발생합니다.

MVVM


비즈니스 로직의 중복과 단위 테스팅이 MVP패턴의 문제라는 점을 알아봤습니다. 이에, MVVP패턴은 이러한 단점을 보완하기 위해 나온 아키텍처 패턴입니다.

[비즈니스 로직 중복 문제의 개선]
이전 MVP패턴은 MainContract라는 모듈을 통해, PresenterView를 내부에 사전 정의해야 했습니다. 이로 인해 1:1 관계가 매핑되었죠. 하지만 MVVM패턴은 이러한 작업을 진행시키지 않아도 됩니다. 그 핵심은 바로, 옵저버 패턴의 UI 상태 관리 모듈에 있습니다.

이 패턴을 알기 위해선 MVP패턴의 UI갱신 방식이 함수의 호출(=명령형)이었다는 점을 상기할 필요가 있겠습니다. MainPresenter 내에서 MainContract.View에 정의 된 객체를 직접 참조해서 메서드를 호출하고 있었습니다.

하지만 MVVM패턴은 옵저버 패턴의 상태 관리 모듈을 사용하여 UI를 관찰하는 방식으로 갱신합니다. 우선 Activity내에 ViewModel을 정의합니다. 그 후, ViewModel의 메서드를 호출하게 되면, 내부적으로 API를 호출하고 결과 값 수신 시, ViewModel내부에 정의 된 상태 관리 모듈인 StateFlow에 값을 업데이트하고 있음을 알 수 있습니다. 이때, layout.xml은 이러한 상태 관리 모듈을 사용하여 값을 통지받기를 기다리고 있습니다. 이에, 상태 관리 모듈에 값이 할당되면, 옵저버 패턴방식으로 값을 최종적으로 layout.xml로 값을 전달해주고 이를 통해 순수 UI로직을 실행시켜주게 됩니다.

이를 통해 알 수 있는 점은 ViewModel은 View를 참조하지 않는다는 점입니다. 따라서 ViewModel은 View로부터 자유로우며, 이를 통해 알 수 있는 점은 View와 ViewModel은 1:N 관계라는 점입니다. 그러므로 만약 비즈니스 로직의 중복 문제가 발생한다면, ViewModel을 여러 View에서 재활용 함으로써 비즈니스 로직의 중복을 줄일 수 있게 됩니다.

[비즈니스 로직 단위 테스팅의 문제점]
ViewModel은 View로부터 자유롭다고 말씀드렸는데요. 이는 ViewModel이 View에 의존도가 없기 때문에 ViewModel만 똑 떼어서 단위 테스트를 진행하기가 더 수월해지게 됩니다. 또한 ViewModel은 View에 정의 된 메서드와도 독립적이기 때문에 추가적인 메서드 오버라이딩이 필요 없으며, 하나의 메서드 안에 기능 테스트를 진행할 수 있게 됩니다.

profile
불가능보다 가능함에 몰입할 수 있는 개발자가 되기 위해 노력합니다.

0개의 댓글