오늘은 iOS의 대표적인 GUI 아키텍처인 MVC에대한 주제를 가져왔습니다
시작은 MVC로 시작하겠지만 종착역은 MVVM일겁니다(아마도말이죠?)
포스팅주제를 MVC에 대한 고찰? 혹은 딥다이브?로 결정을 하고나서 많은 자료를 조사하면서 정리하고 나름의 정의를 내리는데 정말정말 오랜시간이 걸렸습니다. 왜냐면 제가 생각하고있던거랑 좀 많이 달랐기 때문입니다
제가 알게된 모든 내용을 정리해보는 글이 될것같습니다
그리고 분명히 주제자체가 개발자마다 관점이 다를수있기에 피드백이 온다면 계속해서 업데이트해가며 글을 완성시켜볼 예정입니다. 지금쓰는 글은 그런의미에서 초안이 될것같습니다
이번 아티클에서는 UI과 연관된 GUI(graphic user interface)아키텍처를 위주로 서술할 예정입니다(MVC, MVP, MVVM 위주로)
MVC, MVP, MVVM뒤에는 어떤 접두사 붙더라도 아키텍처라고 부릅니다. 그럼 대체 아키텍처가 뭘까를 한번 생각하고 넘어가야합니다
사실 아키텍처라는 단어자체는 건축용어이기때문에 우선 건축에서쓰이는 아키텍처라는 용어를 가져와 봅시다
건축(建築, 영어: architecture)은 건물이나 다른 구조물을 계획하고 설계하고 건설하는 과정과 그 결과물이다(https://ko.wikipedia.org/wiki/시스템_아키텍처)
건물을 하나의 어플리케이션이라고 바꿔본다면 어플리케이션을 설계하고 만들어나가는 과정과 그 결과물이라고 바꿔이야기할 수 있습니다. 하나의 어플리케이션이라는 서비스가 어떻게 구성되어있으며 어떻게 동작하는지를 나타내는 용어정도로 다듬어볼수있겠네요
그리고 그 구성요소의 단위를 하나의 계층혹은 layer으로 보는게 맞다고 저는 생각합니다. 우리가 MVC는 Model과 View와 Controller로 나눠져있다라고 이야기할때 Model계층 View계층 Controller계층으로 나눠져있다라고 보는것과 일맥상통합니다
조금 쉽게이야기해보면 "하나의 어플리케이션을 어떤 계층으로 나눌래?" 혹은 "이 계층들을 어떤식으로 조합할래"에 대한 답이 아키텍처라고 말할수도있을거같습니다
MVC라는 아키텍처는 저는 어플리케이션을 Model, View, Controller라는 계층의 조합으로 설계할래요
라는 뜻이라고 볼 수 있습니다
그래서 MVC라는 아키텍처는 어플리케이션을 만들때 Model, View, Controller라는 계층들의 조합이다라는걸 알게되었습니다. 그런데 헤드퍼스트디자인패턴
이라는 책에서는 MVC를 대표적인 복합패턴이라고 소개합니다
여러 디자인패턴을 함께 사용해서 다양한 디자인 문제를 해결하는 방법을
복합패턴
이라고 부릅니다...중략...패턴 몇개를 결합한다고 무조건 복합패턴이 되는건 아닙니다. 복합패턴이라고 불리려면 여러가지 문제의 일반적인 해결법을 제시해야합니다. 여러 복합패턴을 먼저 살펴본다음에 복합 패턴의 왕이라고 할 수 있는 모델-뷰-컨트롤러(MVC)를 알아보겠습니다
MVC에 대해서 자세히 알기위해서는 디자인패턴에대해서 알아야한다는 말이기도 합니다
책에서 말하는 MVC패턴의 각 계층간의 대화를 하나의 그림으로 만들어봤습니다. 여기서 어떤 디자인패턴이 쓰이는지를 보겠습니다
1. 옵저버패턴
- 모델은 옵저버 패턴을써서 상태가 바뀔때마다 뷰와 컨트롤러에게 연락한다
2. 전략패턴
- 뷰와 컨트롤러는 전략패턴을 사용합니다. 컨트롤러는 뷰의 행동에 해당하며 다른 행동이 필요하면 그냥 다른 컨트롤러로 바뀌면 됩니다
3. 컴포지트패턴
- 뷰 안에는 내부적으로 컴포지트 패턴을 써서 윈도우, 버튼 같은 다양한 구성요소를 관리합니다
여기서 중요한 부분은 총 두가지 입니다.
- 각 계층간의 대화나 관계정의를 디자인패턴을 이용한다는것
- 이 책에서 말하는 MVC는 View와 Model이 옵저버 패턴을 통해서 대화한다는겁니다
그런데 뭔가 위화감이 느껴지지 않나요? 우리가 아는 iOS에서의 MVC랑 여기서 말하는 MVC가 100퍼센트 똑같아보이지는 않습니다. 자연스럽게 이런생각이 듭니다 MVC는 정형화된 아키텍처가 아닌건가???
옵젝씨때의 문서이긴하나 애플공식문서에 MVC에 관한 내용이 있고 첫문단에 이런내용이 있습니다
The Model-View-Controller design pattern (MVC) is quite old. Variations of it have been around at least since the early days of Smalltalk. ...이하생략...
MVC는 매우 오래된 디자인패턴인데 smalltalk부터 다양한 변형이 있었다고 합니다. 그럼 smalltalk가 뭔지를 알아야 이 의문이 해소되겠네요
공식문서 아래쪽으로 내려가보면 전통적인 MVC버전이라는 글과함께 복합디자인패턴으로서의 MVC에대한 설명이 나와있는데요 빨간색 네모를 보면 view는 컴포지트패턴 controller는 전략패턴 model은 옵저버패턴을 사용하고있다고 하고있습니다. 결국 책에서말한 MVC는 전통적인, 그러니까 초기 MVC모델에대한 설명이었다는걸 알 수 있습니다
그리고 애플공식문서는 이때의 Controller는 조정컨트롤러 Coordinating Controller라고 이야기합니다
(이게뭔지는 우선 모르셔도됩니다 뒤에서 설명해드릴예정입니다. 지금은 초기 MVC의 Controller는 Coordinating Controller였구나~정도만 알고 넘어가시면됩니다)
근데 여기서 조금 근본적인 의문이들수도있습니다
애플리케이션을 만들때 레이어들로 나누고 그 레이어의 조합으로 아키텍처를 만드는건 알겠는데 왜 굳이 Model-View-Controller 세개로 나눈걸까요?
MVC 창시자가 말하는, MVC의 본질라는 글을 보면 MVC의 목적은 Model과 View를 분리하는 것
이라고 합니다. 이걸 전문가는 어려운 말로 '관심사의 분리(Separation of Concerns)'라고 하기도 하죠
마틴파울러의 글인 Presentation Domain Separation를 보면
내가 발견하고 따른 가장 유용한 디자인 원칙 중 하나는 프로그램의 표현 측면(사용자 인터페이스)과 나머지 기능(도메인)을 잘 분리하는 것입니다. 수년 동안 이 작업을 수행하면서 저는 다음과 같은 많은 이점을 얻었습니다.
- 프리젠테이션 로직과 도메인 로직을 분리하면 이해하기가 더 쉽습니다.
- 코드를 복제하지 않고도 동일한 기본 프로그램에서 여러 프레젠테이션을 지원할 수 있습니다.
- 사용자 인터페이스는 테스트하기 어렵습니다. 분리하면 더 테스트 가능한 위치에 더 많은 로직이 유지됩니다.
- 스크립팅을 위한 프로그래밍 API를 쉽게 추가하거나 서비스로 노출할 수 있습니다(실제로는 이를 대체 프레젠테이션으로 봅니다).
- 프리젠테이션 코드에는 도메인 코드와 다른 기술과 지식이 필요합니다.
위의 내용을 종합해보면 MVC는 View와 Model을 분리하기위해서였구나라는걸 알 수 있습니다
Model과 View는 분리하려하는데 View와 Controller는 분리하려고하는 시도나 내용이 전혀없는걸보니 View와 Controller의 분리는 크게 중요하지 않나봅니다. 이게 애플공식문서에서도 나온 초기 MVC입니다
자 애플의 공식문서는 단순히 초기 MVC모델에대한 소개만 있지 않습니다
스포를 약간 해보면 지금 우리가 알고있는 애플의 MVC와 초기 MVC가 다르다는건 애플입장에선 초기 MVC의 틀은 가져가되 어떤 근거에 의한 수정된 변형버전으로의 MVC를 사용하게됩니다
그리고 그게 Cocoa MVC라고 불리는 애플의 MVC아키텍처입니다
당연히 MVC라고 불리기때문에 계층은 Model과 View와 Controller세개의 조합입니다
하지만 controller에 전략패턴이외에 mediator패턴이 추가되었다는 점입니다
중재자패턴이라고도 불리는데 중재자패턴에 대한 간단한 설명을 해보면(헤드퍼스트디자인패턴의 내용을 가져와보겠습니다) 서로 관련된 객체 사이의 복잡한 통신과 제어를 한곳으로 집중하고 싶다면 중재자 패턴을 쓰면됩니다
라고 나와있습니다
애플이 초기 MVC버전에서 어떤 부분을 왜 바꿨는지에대한 힌트또한 공식문서에 나와있습니다
However, there is a theoretical problem with this design. View objects and model objects should be the most reusable objects in an application. View objects represent the "look and feel" of an operating system and the applications that system supports; consistency in appearance and behavior is essential, and that requires highly reusable objects. Model objects by definition encapsulate the data associated with a problem domain and perform operations on that data. Design-wise, it's best to keep model and view objects separate from each other, because that enhances their reusability.
영어가 많죠...파파고의 힘을 빌려 해석을 해보면 애플은 초기 MVC에는 중요한 문제가 하나 있다고 봤습니다. 바로 View와 Model이 서로에 대한 참조를 하고있기때문에 두 객체가 재사용측면에서도 좋지않다고 생각했습니다. 즉 두 객체가 계층상으론은 분리를 해놨지만 실제로 객체간의 결합도가 존재하는상황이기에 뷰와 모델이 재사용하는데있어서 어려움을 겪을수있다고 생각했습니다
결국 두 객체가 서로를 관찰하고 있는 구조자체를 바꿔야 했고 view와 model은 서로를 몰라야 재사용성측면에서 강점을 가질수있다고 생각했습니다
이런 상황에서 두 객체가 직접적으로 통신하는 분리된 통신을 한곳으로 집중시키려면 어떻게해야할까요?서로 관련된 객체 사이의 복잡한 통신과 제어를 한곳으로 집중하고 싶다면?
중재자패턴을 쓰면됩니다
view가 model의 정보를 알기위해서는 controller를 거치게하면되고 model이 view에 변화를 알려주기위해서는 controller를 거치가 만든다면 view와 model은 완벽하게 분리되어 재사용성이 좋아집니다
어플리케이션은 다양한 UI를 가져야하고 같은모양의 view를 매번 복붙하거나 똑같이쓰면 시간도 오래걸리고 하나 바꾸려면 모두 바꿔야하는등의 문제가 발생합니다 애플입장에서는 view의 재사용성이 중요하다고생각했던게 아닐까요?
아무튼, 중요한건 애플에서 MVC에서 Controller의 역할을 기존 coordinating controller가 아닌 Mediating controller로 설정했다는겁니다. 이유는 view와 model을 완전히 분리해서 재사용성을 좋게하기 위해서였습니다
Coordinating Controller(조정 컨트롤러)
- 사용자 입력을 받아 해당하는 모델과 뷰를 업데이트하는 역할을 합니다.
- 일반적으로 클라이언트의 요청을 처리하고, 그에 따라 어떤 모델과 뷰를 사용할지 결정합니다.
3.사용자의 액션에 대한 응답으로 모델과 뷰를 적절하게 갱신하고, 애플리케이션의 전반적인 흐름을 조절합니다.Medinating Controller(중재 컨트롤러)
- 여러 컴포넌트 간의 통신이나 상호작용을 중재하고 조정하는 역할을 합니다.
- 다양한 컴포넌트 사이에서 발생하는 이벤트나 행동을 관리하며, 각 컴포넌트 간의 결합을 낮추고 느슨한 결합을 유지하는 데 중점을 둡니다.
- 특정 사용자 액션에 대한 처리보다는 시스템 전체의 조율에 중점을 둡니다.
한줄정리해보면초기 MVC에서 view가 model의 상태를 옵저버패턴을 통해 직접알아내느것이 아닌 무조건 controller를 거치게함으로써 view와 model을 분리하고 재사용성을 높인 애플의 cocoa MVC를 만들어냈다
입니다
애플의 cocoa MVC는 View와 Controller와 Model이라는 계층으로 나누어져있습니다. 그리고 핵심은 View랑 Model을 서로 모르게하자!
가 핵심입니다
그래서그런걸까요 애플이 이렇게생각했을수도있습니다
Model하고 View를 분리하는게 MVC인건 알겠어 그리고 그 의견에 동의해 근데 어디에서도 view와 controller의 분리가 필수라는 말은 없는걸?
그래서 그런건지(아닐확률이 높지만 뇌피셜을 해보자면 그렇습니다) Controller의 역할을 하는 viewcontroller는 view를 가지고있습니다 심지어 UIView는 protocol도 아니고 class이기에 종속관계입니다 재사용이 안되는 강한결합으로 되어있습니다
그리고 실제 model같은 경우도 viewcontroller가 가지고있습니다. 물론 view는 model을 모른다는 핵심은 유지할수있습니다 controller를 통해 model의 변화에 따라 view가 변화되니까요
그래서 실제로 애플의 cocoa MVC는 위와같은 형태입니다
controller의 로직을 테스트하려해도 View와 강하게 결합되어있습니다. UI는 테스트하기 어려울뿐아니라 강하게결합되어있어 Mock UI를 넣을수도없습니다. 순전히 test관점에서보면 controller가 view와 model을 소유하고있는구조는 테스트에 어려움을 겪을수밖에 없습니다
자그러면 여기서 한번쯤은 들어봤을 Massive ViewController에 대한 이야기를 해보려고 합니다.
애플은 cocoa MVC에서 ViewController가 view를 강하게 결합한채로 소유하도록 설계 및 구현을 해놨습니다. 또한 컨트롤러도 조정컨트롤러에서 중재컨트롤러로 바꾸면서 분명히 컨트롤러가 해야할일이 더 많아진다는걸 알았습니다
UIViewController공식문서에는 애플이 중재컨트롤러로서 UIViewController가 해야할 역할을 정의했습니다
UIVewController의 역할
- 데이터가 변경되면 변경된 데이터로 UI를 갱신하는 책임
- view를 통해 user의 input을 처리하는 책임
- UI들을 배치하는 layout에 대한 책임
- 다른객체들과 연계하는책임(화면전환, 데이터전달등)
여기서부터는 제 생각이기때문에 언제든지 태클을 걸어주셔도 괜찮습니다ㅎㅎ
UIViewController가 비대해진다 == 코드가 많다진다
는 아니라고 생각합니다. 왜냐면 만약에 viewcontroller가 아무런 로직없이 진짜 세상에서 제일 복잡한 뷰를 만든다고 생각해볼까요 정말 UI만 구성하는데 viewcontroller에 코드가 1000줄 2000줄이 될수있습니다. 우리는 이걸 viewcontroller가 비대해졌어!
라고 말하지 않습니다.
보통 massive viewcontroller라고 이야기하는 이유는 viewcontroller가 너무 많은 역할을 하기때문입니다. 예를들어서 viewcontroller의 코드가 200줄인데 역할이 10개인것과 역할이 1개인데 코드가 20000줄이면 뭐가 Massive하다고 봐야할까요. 저는 코드의 수는 비대함으로 보기는 조금 애매하다고 생각합니다. viewcontroller가 너무 많은 역할을하고있기때문에 맡은 일이 많은게 비대함
이라고 생각합니다
그런데 애플에서는 viewcontroller의 역할자체는 위 4개로 정의합니다. 그리고 대부분의 프로젝트에서는 위 4개의 역할보다 많은 역할을 viewcontroller에게 맡기지 않을겁니다(물론 viewcontroller에서 네트워크통신코드를 작성하는건 잘못된게맞겠지만 네트워크통신객체를 따로만들어서 함수만 호출하는건 4번 책임이기에 문제가 되지 않습니다)
애플에서는 uiviewcontroller가 위의 4개의 책임을 갖는다고 정의
했습니다. 그런데 우리가 저 4개는 너무 많다고 massive하다고 표현을 하는것이 과연 옳을까라는 의문을 가지고 있습니다.
오히려 코드가 많다고 MVVM을 사용하면 ViewController+ViewModel의 코드의 양이 이전 ViewController의 코드의 양보다 늘어나는 경우도있습니다. 오히려 massive한 viewcontroller를 막겠다고 mvvm을 쓰면 massive한 viewmodel과 마주하게될수도있지않을까요?
MVVM은 MVC의 문제인 Massive함을 해결하기위해 나온 아키텍처다
혹은 MVC로 했더니 너무 ViewController가 Massive해져서 MVVM을 사용했다
라는 이야기를 많이 들었었는데 그건 사용에 대한 결과지 근본적인 선택의 이유라고 말할 수 없다고 생각합니다(MVVM으로 바꾼후 대체로 ViewController자체의 코드가 줄어들기는하니까요)
그렇기 때문에 MVC에서 MVVM의 변경 혹은 선택에는 좀더 명확한 근거가 필요하다고 생각합니다
하나의 글로 마무리가 될줄알았는데 쓰다보니 너무 길어져서 여기서 끊고 다음 글에서 못다한 이야기를 해보려합니다 ㅎㅎ
다음에는 마지막에 했던 이야기에 이어서 MVVM이라는 아키텍처가 등장한 배경을 적어보려합니다. 물론 그전에 MVP에 대한 이야기가 우선되야겠네요
아무래도 이번글을 올리는데 좀 망설여지는 감이 없지않아있습니다. 조사는 열심히 했지만 개발자마다 다른 확신과 개념을 가지고있는 주제인지라 저도 스스로 의문이 드는부분들을 찾아가며 적은 내용이거든요. 100% 확신이라기보다는 조사해보니 이렇더라~
의 뉘양스가 많이 풍기는것같습니다(물론 마지막에 massive viewcontroller에있는 생각은 조금 단호한 의견이긴합니다만 적절한 피드백이 온다면 바뀔수도있겠죠 ㅠㅠ)
그래도 MVC가 왜 등장했는지 애플의 MVC는 왜다른지에대해 알게되어서 아키텍처에대한 이야기를할때 조금더 근거를 가지고 말할수있게되었다는 부분에서는 조사하느라 고생한만큼 뿌듯하긴하네요 ㅎㅎ
아무튼 다음번글에서는 MVC에서 파생된 MVP그리고 MVVM에 대해서 알아보고 최종적으로 iOS에서 자주쓰이는 MVC와 MVVM에 대한 정리를 마지막으로 마무리해보려합니다
그럼 20000!
MVC가 Massive View Controller라는 오명을 얻게 되는 큰 이유 중에 하나는
애매한 로직을 전부 View Controller에 때려 박는 개발 조직이 많기 때문이 아닐까 싶습니다
그리고 현재는 4가지 역할이면 상당히 많다고 인식하는 것도 같습니다
UI에 애니메이션 혹은 동적인 요소가 들어가기 시작하면 UI 관련 코드만 해도 많은데
input output을 관리하고 데이터 관리까지 하라고 하니
개발자들은 ViewController만 수정하게 되고 충돌 나고 해결하느라 시간 쏟고
처음 개발하는 사람은 몇천 줄 되는 View Controller 분석하느라 시간 써야 하니
더 나은(효율적인) 방법 없나? 하고 고민을 하게 되고 MVP, MVVM 더 나아가 VIP, RIBs 등이 나오는 것 같습니다