Advanced iOS App Architecture - Ch5: Architecture: MVVM

MVVM 아키텍처는 Microsoft 사에서 디자인과 개발을 쉽게 할 수 있도록 만들었다. MVVM 이전에는 개발자가 각각의 View마다 코드를 작성하여 View와 비즈니스 로직 간의 커플링이 심했고 이 문제를 해결하기 위해 이 구조를 만들었다. iOS에서는 MVVM을 모델로부터 뷰를 분리시키기 위해 사용한다.

What is it?

MVVM은 “reactive” 한 아키텍처이다. View는 View model의 변화에 반응하며 View model은 Model의 데이터에 따라 그의 상태를 갱신힌다.

MVVM flow

MVVM은 세 가지 레이어로 이루어진다.

  • Model layer: 데이터에 접근하는 객체와 검증 로직을 포함한다. 데이터를 읽고 쓰고 View model에게 데이터의 변경을 알린다.
  • View model layer: View의 상태를 포함하고 유저 인터랙션을 처리하는 로직을 갖는다. Model의 데이터를 읽고 쓰는 메서드를 호출하고 Model의 데이터 변화가 있을 때 View에게 알려준다.
  • View layer: 기기 화면에 표시되는 요소들을 포함하고 비즈니스, 검증 로직을 갖지 않는다. 대신, 비주얼 요소와 View model의 프로퍼티가 바인딩 되어 있다. 또한 유저 입력을 받아들여 View model의 처리 로직을 호출한다.

이러한 결과로 View와 Model은 완전히 decoupled된다.

Model layer

Model 레이어는 모든 CRUD 작업에 책임이 있다. Model 레이어를 설계하는 방법에는 두 가지 널리 알려진 방법이 있다.

  • Push-and-pull: 사용자 측에서 데이터를 요청 후 기다리고(pull), 데이터를 갱신(push)하는 방식
  • Observe-and-push: 사용자 측에서 Model 레이어를 “observe”하고 데이터를 갱신(push)하는 방식

View layer

View 레이어는 화면의 인터페이스이다. MVVM에서 View 레이어는 View model 프로퍼티와의 ‘바인딩’을 통해 변화에 대응한다. One-way 데이터 바인딩을 통해 UI 요소를 View model에 붙이게 되는데, 이 뜻은 View model이 The single source of truth’ 라는 뜻이다. View model의 변화가 있을 때에만 View의 갱신이 이루어진다.

View model layer

이 장의 가장 핵심으로 뷰의 상태, 유저 인터랙션을 처리하고 다양한 UI 요소들의 바인딩을 처리하는 메서드를 포함한다.

View model의 목적은 View로부터 View controller를 떨어뜨리는(decouple) 것이다. View model의 변경없이 전체적인 View를 변경할 수 있고 이는 UI를 신경쓰지 않고 Test가 가능하다는 점도 알려준다.

다음은 View model의 구조이다.

  • View State: View model에 저장된다. public하게 observable한 프로퍼티로 RxCocoa를 통해서 ui를 observable들과 바인딩한다.
  • Task Methods: 유저 인터랙션의 대응하는 작업을 정의한다. 작업이 이루어질 경우 상태를 변경하게 되고, 이것은 observable하기 때문에 새로운 데이터를 방출한다. 그러면 View는 이것을 알게 된다.
  • Dependencies: 초기화 주입을 통해 전달된다. View model은 의존성을 어떻게 사용할 지는 알지만 어떻게 구현되어 있는 지는 알지 못한다.

예시 앱에서 알 수 있었던 것들

  • View model에서는 View의 상태를 Observable 형태로 저장하고 View는 이것을 구독하여 적절한 UI를 보여준다.
  • View model에는 UI 요소가 들어가지 않고 비즈니스 로직만 들어가 UIKit을 import 할 필요가 없다.
  • View model의 초기화 시에 Dependency를 주입해주어 해당 View model이 어떠한 의존성을 가지는 지 쉽게 알 수 있다.
  • 상위 View model이 하위 View model의 생성 시 기존에 가지고 있던 의존성을 주입해주어 Scope 내에서는 해당 의존성이 있다고 가정하고 사용할 수 있다.
  • Pure한 MVVM 구조에서는 어떠한 View를 보여줄 지의 Navigating 로직까지 처리를 한다. (물론 View에 이동 로직은 둔다.)
  • View의 상태는 enum으로 정리한다.
  • View controller의 생성은 Factory 프로토콜을 통해 생성하여 생성 로직을 따로 둔다. 이는 View model이 순수한 비즈니스 로직만 가지게 한다.
  • Rx를 통해서 MVVM의 핵심인 바인딩을 쉽게 적용할 수 있다.

Cons of MVVM

  • RxSwift를 배우는 러닝 커브가 가파르다. (Rx를 사용하는 것을 아예 못 박아두었다.)
  • View model을 같이 사용해야 할 때 메모리 관리나 상태 동기화 등이 어렵다.
  • 비즈니스 로직이 특정 View를 위한 View model 안에 있기 때문에 재사용이 어렵다.
  • iOS에 Apple이 제공하는 바인딩 메커니즘이 없다.
  • UI 업데이트가 메서드 호출이 아니라 바인딩을 통해 이루어지기 때문에 디버깅이 어렵다.
  • View model에는 UI와 Dependency 프로퍼티가 다 있기 때문에 매우 커질 수 있고 상태 관리가 어려워질 수 있다.

Reference

  • Adavanced iOS App Architecture