티몬 개발팀이 iOS 앱 구조 패턴을 MVC → MVVM → VIPER 순으로 훑는 연재의 1편이다. Objective-C 코드로 같은 화면(할인율 문구와 성인 여부 이미지 분기)을 MVC 와 MVVM 두 방식으로 써 놓고, ViewController 가 왜 비대해지는지를 눈으로 비교한다.
핵심 포인트- MVC 는 Model 과 View 를 분리하고 Controller 가 중재하는 구조로 Apple 이 권장했고 스탠퍼드 iOS 강의도 이 패턴으로 가르친다.
- 그런데 실제로 개발하면 View 와 Controller 의 경계가 흐려져 Model 과 View+Controller 두 덩어리가 되고, ViewController 가 커진다.
- 로직이 계속 붙으면 Model-View-Controller 가 아니라 Massive-View-Controller 가 된다는 조롱이 나오는 이유가 이것이다.
- MVVM 은 View 로직을 ViewModel 로 옮겨 View(UIViewController)가 ViewModel 의 데이터를 매칭만 하게 만든다.
- 결과적으로 로직 추가·제거가 간단해지고 신규 기능 구현 시 생기는 버그가 줄어든다는 것이 1편의 결론이다.
상세 정리- 문제 제기: 모바일 화면 하나에 코드가 계속 쌓여 정리가 안 되고 스파게티로 변해 가는 상황, 그렇게 쌓인 기술 부채가 줄지 않는다는 인식에서 시작한다.
- MVC 구성 요소를 상품 도메인으로 설명한다. Model 은 가격·할인율·제품 번호 같은 데이터, View 는 UIView·UIButton·UITableView 처럼 UI 로 시작하는 것들, Controller 는 둘의 소유권을 갖고 Model 을 바꾸거나 바뀐 Model 로 View 를 갱신한다.
- 문제를 드러내는 조건: "할인율에 따라 문구가 바뀌고, 성인 여부에 따라 이미지가 바뀐다" 는 요구를 넣는다.
- MVC 코드: `TMDeal` 모델을 두고 UIViewController 안에서 `discountRate` 가 20 초과인지 판별해 "꿀 할인율" 과 "할인율" 문구를 나누고, `isAdult` 로 이미지 이름을 갈아 끼운다. 이 분기들이 전부 컨트롤러에 남는다.
- MVVM 코드: `TMDealViewModel` 이 `TMDeal` 을 받아 초기화 시점에 `discountRateString` 과 `adultImageView` 를 미리 만들어 둔다.
- View 쪽은 `self.discountRateLabel.text = _dealViewModel.discountRateString` 처럼 대입만 남아 두 줄로 줄어든다.
- 정리: MVVM 은 View 와 Model 사이에 ViewModel 을 넣어 View 로직을 전담시키는 구조이며, 그 결과 로직 변경의 영향 범위가 좁아진다.
- 다음 편 예고로 남긴 질문들이 VIPER 로 넘어가는 동기다. API 호출은 어디서 하는가, 화면이 많은 모바일 특성상 화면 전환을 그냥 호출해도 되는가, 여러 곳에서 각자 `navigationController` 에 push 하면 중복 코드가 계속 생기지 않는가.
왜 읽나ViewController 가 감당 못 하게 커진 경험이 있는 iOS 개발자에게 MVC 와 MVVM 의 차이를 같은 코드로 짧게 보여준다.