 Apple Lover Developer & Artist

영속적인 디자인에 현대의 공감을 채워넣는 공방입니다

 Apple/iOS Dev Challenges

[Challenge] 🛠️ iOS 앱 설계 퓨전 레시피 2부 - MVC 디자인 패러다임

singularis7 2023. 2. 19. 21:10
반응형

Overview

어떤 클래스나 구조체를 생성할지 어떻게 결정하는가? 어떤 속성들을 가져야 하는가? 어느 객체가 다른 객체들의 함수를 호출해야 하는가? 소프트웨어 개발자들은 수십 년간 이 질문에 답할 수 있는 패러다임을 고민해 왔다.

MVC

MVC는 오브젝트에 Model View Controller로 책임을 분류하여 할당하고 오브젝트 간의 소통 방식을 정의하는데 도움을 준다. 다음의 그림은 3가지 타입의 오브젝트가 서로 어떤 관계를 맺어서 동작하는지에 관한 Apple 방식의 조감도를 보여준다. 구체적인 소통 메커니즘을 이해하기 위해 개별 타입들이 어떤 책임을 갖고 있는지 살펴본다.

Cocoa MVC - Apple Developers Document

Models

Model Objects Encapsulate Data and Basic Behaviors

모델은 아이템이나 개념을 나타내는데 필요한 데이터를 그룹화한다. 여기서 아이템이나 개념들은 게임의 문자나 할 일 목록의 작업들처럼 앱 속에서만 존재할 수도 있고 사람, 연락처 정보처럼 실물 세계에서도 존재하는 개념일 수 있다.

모델 오브젝트는 보통 클래스나 구조체로 생성할 수 있으며 타입의 특성을 의미하는 프로퍼티들로 구성된다. 때로는 자신의 프로퍼티를 갱신할 수 있는 메서드를 갖기도 한다.

Views

View Objects Present Information to the User

View는 사용자 인터페이스에서 시각적인 부분을 의미한다. 자신이 화면에 어떻게 그려져야 하는지와 사용자의 입력에 어떻게 반응해야 하는지 알고 있다. 주요 목적은 앱의 모델 객체에 대한 데이터를 보여주고 사용자가 데이터를 수정할 수 있도록 하는 것이다.

목적을 달성하기 위해 View는 재사용되거나 재구성될 수 있다. 예를 들어 모델 오브젝트와 맞춰진 상태를 유지하기 위해 update 혹은 configure과 같은 메서드를 구현하게 된다. iOS 앱을 개발할 때, 보통 View 레이어는 인터페이스 빌더를 통해 정의하며 ViewController와 outlet이나 actions를 통해 참조될 수 있다.

Controllers

Controller Objects Tie the Model to the View

Controllers는 View와 Model 객체 간의 메신저 역할을 한다. View와 Model은 재사용성을 향상하기 위해 서로에 의존성을 갖지 않고 Controller를 통해서만 소통한다. 예를 들어, 사용자가 View와 상호작용할 때, View는 ViewController에 메시지를 보낸다. ViewController가 View의 메시지를 받으면 모델을 갱신할 수 있다. 반대로 모델 객체가 수정되었을 때, ViewController는 View를 다시 그리거나 데이터를 갱신하라고 명령할 수 있다.

Controller는 다른 controller들과 협력할 수 있다. 예를 들어 정보를 보여줄 책임이 있는 view controller는 model controller과의 협력을 통해 가져온다. 자료를 불러오기 위해 네트워크 통신이 필요한 경우 network helper controller를 통해 손쉽게 웹서비스에 접근할 수도 있다.

Combining Roles

객체에서 MVC 역할을 결합할 수 있다. 애플 문서에 따르면 일부 애플리케이션에서 역할을 결합하는 것은 수용 가능한 디자인이라고 주장한다. 그럼에도 재사용성을 달성하기 위한 가장 좋은 방법은 기본적으로 역할을 분리하는 것이다.

View Controllers

View controller는 주로 view 계층에 관심을 두는 controller이다. 인터페이스를 소유하며 인터페이스를 관리하고 모델과 소통하는 책임을 갖는다. 예를 들어 view controller는 하위 view와 협력하여 view 계층을 제어할 수 있다. 또한 view controller 내부에 액션 메서드를 구현하여 하나 이상의 모델 객체로부터 받아온 데이터를 화면에 보여줄 수 있다.

Model Controllers

Model controller는 주로 모델 계층에 관심을 두는 controller이다. 모델을 소유하며 모델을 관리하고 view 객체와 소통하는 책임을 갖고 있다. Model 전체에 적용되는 작업 메서드는 보통 model controller에 구현된다. 크게 model controller와 helper controller로 구분할 수 있다.

model controller

view controller와 유사하게 model controller는 모델 객체를 제어할 수 있도록 도와준다. model controller를 사용해야 하는 주요 이유는 다음과 같다.

  • Multiple objects or scenes need access to the model data.
  • The logic for adding, modifying, or deleting model data is complex.
  • You want to keep the code in your view controllers focused on managing the views.

결합된 역할로 인해 MVC가 Messive view controller라는 별명을 갖기도 한다. 예를 들면 개발자가 하나의 view controller에 다수의 작업을 구현하는 경우이다. view를 관리하는 코드부터 모델을 관리하고 동기화하는 코드까지 하나의 객체에 모두 구현했을 때, 어찌 보면, 위 별명이 통할 수도 있을 것이다.

이럴 때 우리는 주요 논리를 추상화하거나 model controller로 코드를 옮기는 방식의 전략을 활용해 볼 수 있다. 이를 통해 네트워킹이나 모델 관리 등의 역할은 model controller에 맡겨서 view controller가 데이터를 보여주는 역할에 집중할 수 있도록 만들 수 있다.

model controller를 만드는 것이 필수적이지는 않다. 작은 프로젝트에서 자주 사용되는 패턴이 아닐 수도 있다. 하지만 큰 프로젝트에서 다른 개발자들과 협업하기 위해 추상화를 하는 것은 매우 중요하다. 왜냐하면 이를 통해 코드를 단순하고 더 가독성이 좋고 쉽게 관리할 수 있는 개발 환경을 만들 수 있기 때문이다.

helper controller

helper controller는 앱의 다른 객체에서 접근할 수 있도록 연관된 데이터나 기능을 통합하려는 경우 유용하다. 예를 들어 network controller를 통해 앱의 네트워크 요청을 통합적으로 관리할 수 있다.

Compound Design Pattern

디자인 패턴 관점에서 MVC는 기본적인 디자인 패턴으로 구성된 복합 패턴이다. 전통적인 MVC를 통해 기능 분리와 소통 방식을 정의하기 위해 디자인 패턴이 어떻게 적용되었는지 살펴보고 타입의 재사용성을 향상하기 위해 애플의 계량 방식을 살펴본다.

Traditional MVC

전통적인 방식의 MVC은 Composite, Stretegy, Observer 패턴으로 구성되어 있다.

Traditional MVC - Apple Developer

Model은 Observer 패턴을 사용한다. Model을 View와 Controller로부터 독립시키며 일대다 관계를 유지할 수 있게 된다. 동작 메커니즘은 다음과 같이 소개해볼 수 있다.

  1. Observable 한 모델의 상태 변화에 관심이 있는 View 혹은 Controller 객체를 Model의 Observer로 등록한다.
  2. Model은 자신의 상태가 변경되면 자신의 Observer 목록 객체들에게 상태 변동 사항을 안내한다.

View는 Composite 패턴을 사용한다. View는 윈도, 레이블, 버튼, 텍스트 등의 GUI 구성 요소로 이루어진 복합 객체이다. GUI 구성 요소들을 동일한 트리 구조에 넣어서 부분-전체 계층 구조를 구현할 수 있을 것이다. View 계층 구조를 동일한 인터페이스를 통해 손쉽게 관리하기 위함이다. 동작 메커니즘은 다음과 같이 소개해볼 수 있다.

  1. GUI 구성 요소들은 트리 구조를 이루는 복합 객체이거나 잎(리프) 노드로 해석할 수 있다.
  2. Controller는 화면 갱신 요청 메시지를 View의 Root 노드에만 보낸다.
  3. 메시지는 리프 노드에 이를 때까지 재귀적 메커니즘을 통해 전파된다.
  4. 전체 View 계층을 손쉽게 관리할 수 있다.

Controller는 Strategy 패턴을 사용한다. 주로 View와 Controller 사이의 관계에서 활용되며 View와 Model의 의존성을 분리하는데 도움을 준다. View 객체는 여러 전략을 구성하여 설정할 수 있는데 Controller는 View에게 전략에 따른 행동을 제공해 준다. 이를 통해 View는 행동을 결정하는 일을 Controller에 위임하여 시각적인 부분을 관리하는 본연의 역할에 집중할 수 있게 된다. 동작 메커니즘은 다음과 같이 소개해볼 수 있다.

  1. View는 사용자의 행동을 처리하는 작업을 Controller에게 위임한다.
  2. 사용자 이벤트가 발생하면 Controller에게 메시지를 전달한다.
  3. Controller는 이벤트에 따라 수행해야 하는 행동을 취한다.
  4. Controller를 바꿔서 전략에 따른 행동을 수정할 수 있다.

Cocoa MVC

애플은 전통적 방식의 MVC에서 View와 Model 사이에 의존 관계가 발생해 재사용성이 떨어지는 문제점을 지적한다. 이를 개선하기 위해 Model과 View를 분리시킨 애플 방식의 MVC를 제안하게 되었다. 디자인 패턴 관점의 차이점을 살펴본다.

Cocoa MVC - Apple Developers Document

Controller는 View와 Model의 Mediator이다. 즉, View와 Model의 복잡한 통신과 제어 흐름을 Controller가 중재하여 두 객체 사이의 의존성을 완전히 분리시킬 수 있다. 제어 로직을 한 곳에 모아 두어서 관리하기에 수월할 수 있지만 디자인을 잘 못하면 중재자 객체가 복잡해질 수 있다. 동작 메커니즘은 다음과 같다.

  1. Model의 상태 변화가 Controller에게 전달된다.
  2. Controller는 보낸 요청에 응답한다. (View를 갱신한다.)

View는 Target-Action 메커니즘의 구현을 통해 Command 패턴을 포함시킬 수 있다. 이해를 위해 View와 Controller가 직접적인 의존 관계에 있는 경우를 가정해 보자. View는 화면에 보이는 방식을 관리하는 것뿐만 아니라 매번 연결된 Controller에 따라 어떤 동작을 실행할지에 관한 정보를 알고 있어야 한다. 이 방식은 SOLID의 OCP를 충족하지 못하는 방식이다.

Command 패턴을 도입하면 작업을 요청하는 View와 작업을 처리하는 Controller를 완전히 분리할 수 있다. 커멘드 객체를 통해 특정 작업 요청을 캡슐화하고 View에서 사용자 이벤트가 발생했을 때 커멘드 객체를 통해 작업을 수행할 수 있게 된다. 애플은 Target-Action 메커니즘을 고안하여 이를 구현하고 있는 것이다.

View에서 발생하는 이벤트의 처리 책임을 Controller 등의 다른 객체에 위임하는 Delegation 패턴도 iOS에서 많이 사용되는 패턴 중 하나이다. 프로토콜을 통한 DIP 메커니즘으로 View와 Controller 간의 의존성을 분리한다.

Reference

[Develop in Swift Data Collections]: https://books.apple.com/kr/book/develop-in-swift-data-collections
[Stanford CS193p: MVC]: https://singularis7.tistory.com/63
[Model-View-Controller]: https://developer.apple.com/library/archive/documentation/General/Conceptual/CocoaEncyclopedia/Model-View-Controller/Model-View-Controller.html "Concepts in Objective-C Programming"

반응형