안녕하세요 오늘은 모바일 엔지니어링에 사용되는 아키텍처 패턴에 대해
경험을 통해 얻은 제 생각과 느낀점을 정리해 보려고 합니다.
MVC, MVP, MVVM, VIPER
이렇게 4가지에 대해 다뤄보려고 합니다.
아키텍처 패턴은 왜 사용하는가?
아키텍처 패턴은 시스템의 구조와 그 시스템을 구성하는 요소들 간의 상호작용 방식을 정의하는 패턴입니다.
정형화된 패턴은 작업을 진행하는 사람이 다수인 경우 가독성을 증가시킬 수 있는 장점이 있습니다.
만약, 작업을 하던 사람이 바뀌게 되어도 작업을 그대로 이어나갈 수 있게 됩니다.
또한, 기능에 대한 역할을 각영역에 분배하여 문제가 발생시 빠르게 그 원인을 찾을 수 있습니다.
종합적으로 보았을 때, 아키텍처 패턴은 시스템이 끊임없이 안정적으로 구동하는데 기여한다고 말할 수 있습니다.
아키텍처란 말 자체가 사실 건축에서 나온 말이기도하죠 🤔
핫한 아키텍처는 항상 옳은 선택일까?
예전에 아키텍처 패턴과 관련된 글을 볼때는 뭔가 서두에 등장하는 MVC는 MVVM보다 안 좋은 옛날 패턴이고
어딜가나 MVVM이 핫한 것 같으니 이번 프로젝트는 MVVM으로 만들어봐야지!
이렇게 생각했던 적이 있었습니다.
아키텍처가 요구사항을 앞질러 버리는 일이 생기더군요,,,
하지만 여러 프로젝트를 진행하며, 아키텍처는 목적이 될 수 없음을 느끼고 있습니다.
앞으로 나올 여러 패턴들을 한번 살펴보며 패턴별로 어떤 장단점이 있는지 알아봅시다~!
우선 MVC에 대해 먼저 다뤄보겠습니다.
(해당 글은 iOS개발자 관점에 제작됬습니다.)
MVC
MVC는 Model View Controller의 줄인말 입니다.
우선, 제시된 3가지 개념은 특정한 "뭔가"라기보단 계층이라고 생각하시면 됩니다.
MVC에서 Model이란 애플리케이션에서 데이터 처리와 관련된 계층입니다.
DataSource, DTO, 데이터 관리 로직등이 모두 이 영역에 속합니다.
View는 말그대로 UI를 의미합니다. 유저에게 데이터를 시각적으로 보여주고 유저의 액션을 앱으로 전달합니다.
컨트롤러가 핵심적인데요, 컨트롤러는 View와 Model을 매개합니다.
Model로부터 가져온 데이터를 View에 반영하는 구조로 동작하게 됩니다.
MVC에 장단점에 대해 알아보겠습니다.
우선 장단점이란 뭘까요? 어떤게 장점이고 어떤게 단점인지 판단할까요?
"MVC의 컨트롤러는 테스트하기 어렵다."
참 애매한 말이라고 생각합니다. 왜 어려운지를 알아야겠지요.
우선, 모바일 디자인 패턴에서 지향하는 바가 무엇인지 알아야 합니다.
1. View(UI)는 재사용성이 높이는 것을 지향해야한다.
2. 비즈니스로직을 가진 객체는 테스트가 용이해야한다.
MVC에서 비즈니스 로직을 가진 것은 무엇이 있을까요?
바로 Controller와 Model입니다.
View같은 경우는 재사용성을 높이기 위해 컨트롤러를 모릅니다.
모른다는 것은 컨트롤러 타입과 View타입 사이 의존성이 존재하지 않다는 것을 의미합니다.
Model의 경우도 여러곳에 재사용성을 높이기 위해 컨트롤러를 모릅니다.
컨트롤러는 모델로 부터 받은 데이터를 뷰에 전달하고, 뷰로 부터 받은 액션을 처리해야 하는 역할이 있습니다.
그렇기 때문에 필연적으로 Model과 View를 알고 두 사이를 매개 합니다.
즉, 컨트롤러는 Model, View계층에 모두 의존성을 가진 객체로 테스트가 당연하게 어렵습니다.
Model과 View는 왜 Controller를 알지 못해도 소통가능한가?
모델로 부터 발생하는 비동기 이벤트(ex 네트워크 통신)를 모델이 컨트롤러를 모른채로 어떻게 알 수 있을까요?
앞서 언급했듯, 컨트롤러는 View로부터 액션을 받아 Model을 업데이트 하는 역할도 수행합니다.
View의 액션을 컨트롤러에 전달하려면, 컨트롤러를 알아야 하지 않나요?
iOS에서는 상호작용을 유지하면서도 의존성을 없에기 위해 KVO, Delegate, call back등과 같은 방법을 사용합니다.
아하! 이래서 이 패턴들이 사용되왔던 거군!
iOS에서의 MVC
iOS에서는 ViewController라는 코코아 클래스가 존재합니다.
ViewController의 역할은 MVC의 Controller와 유사하지만, 몇가지 책임을 더 가집니다.
ViewController가 뷰 컨트롤러 계층과 뷰계층의 생명주기를 유지하는 역할이 추가됩니다.
역할이 더 큰 iOS의 ViewController는 테스트하기 더 어렵습니다.
MVC 총평
MVC에서 컨트롤러는 Model과 View를 매개하며 View를 업데이트하고 모델을 호출하는 등, 책임이 매우 큰 객체입니다.
iOS에서는 뷰컨트롤러가 다수의 View를 관리할 경우 Massive View Controller라고 부르기도 하지요.
컨트롤러는 책임이 큰 만큼 테스가 어렵다는 단점이 있습니다. 반면, 독립된 Model과 View에 대한 테스트는 용이합니다.
그리고 모든 주요 로직을 컨트롤러가 관리함으로,
규모가 작은 화면의 경우 다수의 파일및 타입을 생성할 필요 없이 요구사항을 빠르게 구현할 수 있습니다.
다음으로는 MVP를 살펴보겠습니다.
MVP
MVP는 Model View Presenter를 줄인말입니다.
Model의 경우 MVC와 동일합니다.
Presenter는 MVC의 컨트롤러와 달리, View와 1대1로 매칭됩니다.
View의 액션 역시 Prsesenter에서 모두 관리할 수 있습니다.
View는 그래픽적 역할이외에는 어떤 것도 하지 않으며, Thumb라고 합니다. 😆
iOS에서의 MVP
iOS관점에서 살펴보겠습니다.
iOS에서 컨트롤러의 테스트가 더 어려운 이유는 생명주기 관리 역할이 추가됬기 때문입니다.
MVP에서 Presenter는 생명주기로부터 자유롭습니다.
MVP에서 View는 Thumb임으로 단지 View만 아는 Presenter의 경우
MVC의 컨트롤러보다 테스트가 용이하다는 장점이 있습니다.
iOS에서 MVP구조는 다음과 같습니다.
MVP에서는 View재사용성이 떨어지는지?
MVP는 Presenter와 View가 서로를 알고 있다는 점에서 의존성이 발생하게 됩니다.
따라서 뷰 재사용성이 떨어질 수 있습니다.
DIP원칙에 따라 해당문제를 해결할 수 있습니다.
View는 Presenter구체타입을 참조하는 것이 아닌 인터페이스를 참조하도록 설계함으로써
재사용성을 떨어트리지 않을 수 있습니다.
MVP 총평 (iOS 관점)
MVC의 컨트롤러에서 생명주기 관리와 같은 책임을 덜어내어 Presenter의 비즈니스 로직이 MVC의 컨트롤러보다 테스트 하기 용이하다.
MVP의 경우 View가 Presenter에 의존함으로써 재사용성이 떨어진다고 생각할 수 있지만 전혀 그렇지 않다.
Presenter에 의해 ViewController는 모델타입을 몰라도 되는 구조가된다.
그리고 Presenter인터페이스를 통해 원하는 구체 Presenter를 주입받는 구조가 되어 뷰 재사용성은 오히려 올라간다고 표현할 수 있다.
iOS관점에서 Presenter라는 타입을 하나 더 생성해야 한다는 부채가 있지만
책임의 분리를 통해 테스트 용이성및 재사용성을 높인 패턴이다.
MVVM
MVP의 Presenter는 View를 알고있습니다.
ViewModel는 View타입을 알지 못하는 Presenter라고 볼 수 있습니다.
View타입을 모르기에 다수의 View에서 ViewModel을 재활용할 수 있습니다.
즉, Presenter View 1 : 1관계에서 벗어날 수 있습니다.
MVVM의 장점은 View가 ViewModel을 ViewModel은 View를 알지 않아도 된다는 장점이 있습니다.
모델역시 추상화 할 경우 완전한 모듈화를 이룰 수 있습니다.
3개의 계층을 서로 독립적으로 동작하게 함으로써 테스트가 가장 용이한 케이스 입니다.
View와 ViewModel의 무의존 양방향 통신(iOS)
위 그림에서 볼 수 있지만, View와 ViewModel은 양방향 통신을 합니다.
추상 매서드 호출, delegate, callback등 다양한 방법이 있을 수 있지만, 주로 바인딩방법을 사용합니다.
Reactive Programming방식을 사용하여 바인딩 방법을 편하게 구현할 수 있습니다.
RxSwift를 사용하여 MVVM을 구현한 예시 프로젝트 입니다.
https://github.com/J0onYEong/RxUIState
해당 프로젝트에서 ViewModel을 인터페이스로 추상화하지 않았지만, 바인딩이 어떻게 진행되고, 어떤 방식으로 View와 ViewModel이 소통하는지 확인할 수 있습니다.
MVVM 총평
MVP와 달리 ViewModel은 View를 몰라도 됨으로 테스트가 더욱 용이해졌다.
View-VIewModel간 의존성이 없어서 다수의 View에서 ViewModel을 공유하는 것이 가능하다.
View에 직접 접근할 수 없는 만큼
View와 ViewModel사이의 바인딩 코드를 작성해야 한다. 해당 구현은 기술부채로 이어질 수 있다.
VIPER
마지막으로 Viper입니다 여기까지 글을 읽으셨다면 VIPER는 별로 특별하진 않다고 느끼실 수 있습니다.
VIPER는 VIew, Interactor, Entity, Presenter입니다.
VIPER의 Presenter는 MVP와는 조금 다릅니다.
데이터를 바탕으로 View를 업데이트 하는 것은 여전히 View가 전담함으로 MVVM의 ViewModel과 비슷합니다.
이번에는 계층이 5개나 되지만 아래와 같인 그룹화할 수 있습니다.
MVP가 MVP에 비해 책임을 세분화 한듯 VIPER역시 책임을 세분화한 디자인 패턴입니다.
Model은 데이터와 관련된 모든 것에서
앱내에 사용할 수 있는 핵심 타입인 Entity와
Entity를 사용하여 여러 비즈니스로직및 데이터 통신을 관리하는 Interactor 로 책임을 분리하였습니다.
컨트롤은 View와 Interactor를 매개하는 Presenter와
화면전환을 담당하는 Router로 책임을 분리하였습니다.
"하나의 객체는 하나의 역할만을 수행해야 한다!"
VIPER는 Soild원칙중 SRP를 가장 잘 지킨 패턴이라고 말할 수 있습니다.
VIPER.. 는 이미 내안에 있었다..
저는 현재 Coordinate패턴과 MVVM을 섞은 방식으로 프로젝트를 진행하고 있습니다.
ViewModel은 Coordinator를 사용하여 화면 전환을 요청할 수 있는 구조입니다.
아래 사진은 제프로젝트의 구조입니다.
VIPER 총평
VIPER는 책임의 분리가 잘 이루어 졌다는 점에서 테스트 하기 쉽습니다.
여기서 테스트란 유닛 테스트를 작성하는 것을 의미하는 것은 아닙니다.
책임의 분리를 통해 문제가 발생한 부분을 빠르고 정확하게 찝어 내는 것 역시 테스트를 용이하게 한다고 말할 수 있습니다.
책임의 분리는 좋지만, 5개의 타입(+인터페이스들)을 각자만들고 관리해야 한다는 점에서 부채가 큽니다.
아키텍처 패턴들을 둘러보며...!
아직 학생인 나는 아키텍처 패턴의 중요성을 크게 느끼지 못했다.
그저 협업을 함에 있어 코딩하는 방식을 획일화 하는 것이라고 생각했다.
하지만 프로젝트가 고도화 될 수록 아키텍처 패턴이 빛을 바람을 느낄 수 있었다.
계층화를 통해 특정 문제에 대한 책임을 특정 계층에 전담시킬 수 있어
문제가 생기면 빠르게 해결할 수 있고 새로운 기능을 추가할 때도 기존의 기능들을 재사용할 수 있다.
이러한 디자인 패턴을 앱 전반으로 적용한 것이 클린 아키텍처가 아닌가라는 생각을 하게된다.
다음번에는 의존성 주입을 통한 강력한 클린아키텍처의 장점을 글로 다뤄보겠다.
'iOS공통' 카테고리의 다른 글
[iOS] 첫 어플리케이션 배포 심사 회고 (1) | 2024.09.26 |
---|---|
[Swift] 이미지 캐싱을 통한 로딩속도 최적화 (0) | 2024.09.23 |
[RxSwift] subscribe(on:)과 observe(on:)의 차이를 아시나요? (0) | 2024.08.24 |
[자료구조] 해시 테이블(+Swift) (0) | 2024.08.16 |
[Swift] GCD와 Swift concurrency에 대해 (0) | 2024.07.22 |