안드로이드 아키텍처

Jang Seok Woo·2021년 6월 23일
0

실무

목록 보기
7/136

코드 분석을 위해 안드로이드 아키텍쳐의 종류와 각 아키텍처의 특성을 알아보도록 하자.

1. Android에서 아키텍처 패턴은 왜 필요한가

앱을 만든다는 것은 사용자가 원하는 정보를 화면으로 잘 찾아보고, 잘 입력할 수 있게 하는 소프트웨어를 만드는 것이다. 앱을 만들 때 필요한 요소는 크게 2가지이다. 흔히 비즈니스 로직이라고 하는 “기획적인 요소”와 아이콘 이미지, 레이아웃, UI, UX를 포함한 “디자인적인 요소”가 그것이다.

앱을 만드는 순서는 4단계로 구성된다.
1) View를 배치하는 것
2) View에서 사용자 Action을 감지하는 것(터치, 클릭, 텍스트 입력, 스크롤, 스와이프 등)
3) Action에 따라 알맞은 동작을 수행하게 하는 것(데이터를 서버나 클라이언트에서 처리하는 등)
4) 동작의 결과를 다시 View에 반영하는 것

2. 아키텍처 패턴의 종류

Android에서는 다양한 아키텍처 패턴들이 존재한다. UI개발에서 흔하게 말하는 MVC 패턴도 있고, MVI, 또 우버팀에서 만든 RIBS 아키텍처 등 정말 가지각색의 패턴들이 현존한다. 이 글에서는 Android에서 가장 잘 알려져 있는 MVP, MVVM와 네이버 GitHub 오픈소스인 SVC까지 총 3가지를 서로 비교해 보고 장단점을 분석한다.

MVP 패턴
1990년대 Taligent사(Apple, IBM, HP의 협력 벤처)에서 시작한 패턴으로 알려져 있는 MVP는 dolphin smalltalk, Microsoft .Net 등 다양한 플랫폼에서도 적용된 패턴이다. MVP의 약자는 각각 Model, View, Presenter이고, 구조는 다음과 같다.

MVP에서 주목할 점은 View가 수동적(Passive)이라는 점이다. View는 스스로 데이터를 반영하지 않고 명령을 받는다. 명령을 하는 주체인 Presenter가 View에게 “Data를 보여줘- view.showData(data)” 하고 명령을 하는 형태인 것이다.

View는 클릭이나, 기타 사용자 Action이 발생 시 Presenter를 직접 호출한다. presenter.do()와 같은 형태로 비즈니스 로직이 바로 수행된다. Presenter는 Action과 Lifecycle에 따라서 작업을 수행한다. Model의 데이터를 변형하기도 하고, 필요한 작업을 수행한 뒤에, 결과를 다시 View에게 전달해서 사용자에게 결과 데이터를 보여준다.

Presenter는 Mediator(중재인)으로서 Model과 View 사이에서 필요한 작업들을 수행한다. Mediator의 다른 설명으로는 Supervising Controller(감독 제어기)라고 하기도 하는데, 중간에서 감시·감독한다는 의미로 해석할 수 있다.

MVVM 패턴
2005년 John Gossman이 제안한 패턴이다. MVVM 개념의 기초는 2004년 마틴 파울러가 제안한 PM(Presentation Model)를 기반으로 만들어졌다. PM은 View에 렌더링에 필요한 데이터를 가지고 있는 객체이고, View는 PM의 데이터를 기반으로 렌더링을 한다. PM에서 중요한 포인트는 PM이 들고 있는 데이터와 View는 항상 동기화(synchronization)가 되어야 한다는 것이다. John Gossman은 PM의 개념을 WPF와 Silverlight 플랫폼에 특화시켰고, PM을 ViewModel이라는 이름으로 명명하면서 MVVM이 탄생했다. 더 자세한 내용은 “Model-View-ViewModel 디자인 패턴을 사용한 WPF 응용 프로그램”을 참고한다.
John Gossman이 이 패턴에서 이루려고 한 목적이 2005년 블로그글 서두에 나온다. 전체 작업을 UI 로직 작업과 비즈니스 로직 작업으로 나눌 수 있다. 이렇게 나누어진 작업을 디자인에 특화된 UI 개발자는 UI쪽을 담당하고, 비즈니스 로직에 특화된 개발자는 나머지 부분을 담당할 수 있도록 하기 위해서이다. 이렇게 나누어서 협업을 하는 것은 특히 드림위버, 플래시와 같이 UI개발에 특화된 WYSIWYG 소프트웨어를 개발할때 도움이 된다.
MVVM은 Model, View, ViewModel의 약자이고, 구조는 다음과 같다.

MVVM은 MVP와는 반대로 View가 능동적(Active)이다. View는 스스로 ViewModel 객체의 어떤 데이터가 필요한지 직접 관찰한다. 관찰하기 위해서는 ViewModel에 있는 데이터가 관찰 가능한 형태여야 한다. Google에서 제공한 LiveData, ObservableField 객체를 쓰거나 Rx Java에서 제공해주는 Observable 객체도 사용 가능하다. 관찰 필드에 변화가 생기면 즉시 View는 알림을 받게 되고, 알맞은 View 렌더링 로직을 수행하게 된다.
View는 클릭이나 기타 사용자 Action이 발생하면 ViewModel을 직접 호출한다.

Google에서 제안한 예제를 보면 2가지 형태로 호출하는데 ViewModel 내부의 메서드를 직접 호출하는 방법과, ViewModel 내부에 있는 CommandObservable 객체를 통해 호출하는 방법이다.

전자의 방법은 MVP와 동일하다. 이 방법을 쓰게되면 ViewModel이 특정 비즈니스 로직과 관련이 깊어질 수 있기 때문에 별도의 인터페이스나 클래스 객체를 만들어서 비즈니스 로직을 위임하는 것이 로직을 분리하는 측면에서 바람직하다. 후자의 방법은 ViewModel에서는 View에서 발생한 Action을 전달만 할 뿐 비즈니스 로직 처리는 해당 CommandObservable을 관찰하는 쪽에서 담당하기 때문에 비즈니스 로직을 좀 더 강제로 분리할 수 있다.

그러나 후자의 방법을 쓰면서 CommandObservable을 관찰하는 객체가 ViewModel 자신이라면 그것은 불필요한 관찰을 하는 것이라고 생각한다. CommandObservable 객체를 차라리 사용하지 않는게 코드 복잡도를 줄이는 길이다. CommandObservable을 쓴다면 ViewModel이 아닌 다른 비즈니스 로직 처리 객체가 관찰을 하도록 설계하는 것이 바람직하다.

MVVM으로 앱을 개발한다면 Databinding 라이브러리를 쓰는 것을 꼭 고려하는게 좋다. View의 디펜던시를 Activity, Fragment 의존에서 xml 의존으로 내릴 수 있다. 그러면 다음의 구조로 표현할 수 있다.

구조는 “그림2”의 형태와 동일하지만 View는 실제 XML로만 존재를 한다. View에 코드로 접근할 일이 있다면 BindingAdapter와 InverseBindingAdapter를 통해서 접근하고 상태값을 통해 View를 갱신한다. ViewModel은 View에 표현할 데이터를 들고 있으면서 MVP의 Presenter와 같이 비즈니스 로직과 View 사이에서 Mediator 역할을 한다.

John Gossman이 이루려고 했던 UI 개발 영역과 비즈니스 영역 개발을 나누어서 협업을 하려면 ViewModel 내부에 observable 필드들을 정의하고, View의 Action을 받을 interface 또는 CommandObservable 객체를 미리 정의하면 된다. ViewModel에서 미리 정의된 값을 xml에서 observing하고 필요한 View의 Action을 호출하도록 만들면 분리된 영역 내에서 서로 부딪히지 않고 작업이 가능하다. UI 담당 개발자는 xml과 BindingAdapter, InverseBindingAdapter만 개발하면 되고, 비즈니스 로직 담당자는 나머지 부분을 개발하면 된다.

그렇다면 MVP에서는 영역 분리가 불가능한가? 실제로 완전히 불가능하다고 할 수는 없지만, 충돌 영역이 조금 생긴다. View는 Presenter를 호출해야하고 Presenter는 View를 호출해야 되기 때문에 작업 영역이 겹치고 여기서 충돌이 발생할 수 있다. 이 부분을 줄이기 위해서 Presenter와 View 인터페이스를 각각 미리 만들면 그 충돌을 줄일 수 있지만 View를 작성하는 입장에서는 사용자 Action을 전달하기 위해 Presenter를 사용해야하는데, Presenter에 public 함수가 40개가 되고, View Action과 관련된 함수가 3개밖에 없다면 40개중에 3개를 찾기 위해서 눈을 부릅떠야하는 불편함이 있다.

MVP의 구조적인 단점들이 있기 때문에 이러한 단점을 해결하기 위해 SVC 패턴을 만들었다.

SVC 패턴
SVC의 전체적인 구조는 MVP와 비슷하지만, UI 영역과 비즈니스 영역 사이의 연관성을 끊기 위해서 View는 Presenter를 직접적으로 알지 못하도록 설계되었다. SVC의 약자는 각각 Screen, Views, ControlTower(관제탑)이고 구조는 다음과 같다.

MVP와 핵심적으로 다른 요소는 Views 객체에서 발생하는 이벤트가 ViewsAction 인터페이스를 통해서 전달되고, 이 전달을 통해 ControlTower 객체 함수가 호출 된다는 것이다. 그래서 호출하는 화살표도 점선으로 표시가 되어있다.

SVC에서는 Android의 특성을 고려하여 만든 Screen이라는 interface 객체가 추가되었다. 앱은 여러 가지의 화면 페이지로 구성된다. 한 페이지 전체를 덮는 Activity나, 그 위에 살짝 얹어지는 Dialog가 있고, 화면 영역의 일부를 담당하는 Fragment가 존재한다. 각 Screen 객체는 UI로 표현되는 Views와 ControlTower로 이루어져 있다.

Views 객체의 이름은 Android에서 말하는 View 객체들이 많이 모여있는 집합이라는 뜻에서 복수형으로 ‘s’가 붙었다. Views는 하나의 xml에서 인플레이트된 View들의 집합이고, xml안에 있는 View들을 콘트롤하고 각 View에서 발생하는 이벤트를 viewsAction 객체에게 알려준다(viewsAction.onClickSave()같은 형태로).

ControlTower 객체는 Screen에서 발생하는 모든 이벤트를 제어하는 관제탑이다. Screen의 Lifecycle 이벤트를 감지하고, Views에서 발생하는 이벤트를 viewsAction 인터페이스를 통해 감지한다. Screen에서 일어나는 모든 이벤트를 받고 이에 맞는 로직을 수행한다. 처리 결과를 Views에게 알려주는 방식은 MVP와 동일하다.

MVP와의 차이점 2가지이다. Activity, Fragment를 View가 아닌 Screen이라는 개념으로 뒀다는 것과, View에서 일어나는 사용자 이벤트는 직접적인 비즈니스 로직 호출이 아닌 ViewsAction 인터페이스를 통해 전달된다는 점이다.

SVC는 ViewModel과 함께 사용하는 것도 스펙에 따라서 고려해 보는 것도 좋다. ViewModel과 함께 SVC를 설계한다면 크게 2가지 type으로 설계할 수 있다. 다음은 첫 번째 type의 도식이다.

기본적인 구조는 SVC의 구조를 가져간다. 그러나 ControlTower가 Views에게 렌더링 명령을 내리지 않는다. MVVM에서와 같이 Views에서 ViewModel에 필요한 Observable 데이터를 관찰을 해서 능동적으로 데이터를 View에 반영한다. MVVM과 다른 점은 ViewModel이 Views에 필요한 데이터 보관 객체로서의 역할만 한다는 점이다. Mediator의 역할은 ControlTower가 하기 때문에 필요한 데이터는 Model에서 가져오고, View에 갱신이 필요하다면 ViewModel의 데이터를 변경한다.
다음은 두 번째 타입의 도식이다.

세로로 그려져 있는 도식을 가로로 놓고 보면 MVVM과 거의 흡사한 형태가 된 다. 여기서 ControlTower의 역할은 Views에서 발생하는 ViewsAction을 받아 UI로직과 비즈니스 로직이 섞이지 않게 중개만 해주는 역할을 담당한다. 앱에서 정보를 주로 제공해주는 화면이 많을때 두 번째 타입이 유용하다. Model을 통해 ViewModel에 필요한 데이터 갱신이 잦고, 각 ViewModel과 정보를 제공하는 DB repository가 서로 유형별로 비슷해서 짝지을 수 있는 경우라면 “그림 6”의 형태로 설계하는게 바람직하다.

각 아키텍처 차이점 :
https://medium.com/@bansooknam/android-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EB%B9%84%EA%B5%90-mvp-mvvm-svc-2-7c44ea167d56

출처 : https://medium.com/@bansooknam/android-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EB%B9%84%EA%B5%90-mvp-mvvm-svc-1-f24e5f338523

profile
https://github.com/jsw4215

0개의 댓글