이 장을 읽기 전에
결합도와 응집도의 낮은 결합도 기준과 옵저버 패턴의 Subject-Observer 구조를 안다고 가정한다. 이 챕터는 그 개념들이 화면(UI) 계층에서 어떻게 구체적인 아키텍처 패턴으로 나타나는지를 다룬다. 난이도는 초급–중급이며, 특정 프레임워크(React, Vue, WPF 등)의 구현 세부사항이나 상태 관리 라이브러리(Redux 등) 비교는 다루지 않는다.
화면과 데이터가 뒤섞이면 생기는 문제
버튼 클릭 이벤트 처리 코드 안에 곧바로 데이터 계산 로직과 화면 갱신 코드를 함께 작성하는 방식은 작은 프로그램에서는 문제가 없다. 하지만 같은 데이터를 여러 화면(모바일 앱과 웹 대시보드)에서 보여줘야 하거나, 화면 없이 데이터 로직만 테스트하고 싶을 때 문제가 드러난다. 데이터 계산 로직이 특정 UI 프레임워크의 위젯 객체와 뒤섞여 있으면, 로직만 따로 떼어 재사용하거나 테스트할 수 없다.
**MVC(Model-View-Controller)**와 **MVVM(Model-View-ViewModel)**은 모두 화면(View)과 데이터(Model)를 분리한다는 공통 목표를 가진 UI 아키텍처 패턴이다. Model은 데이터와 비즈니스 로직을 담당하고, View는 사용자에게 보여지는 화면을 담당한다. 이 둘을 직접 연결하지 않고 중간에 중재자를 두는 것이 두 패턴의 공통점이며, 그 중재자가 무엇을 하는지가 두 패턴의 차이를 만든다.
MVC: Controller가 입력을 받아 Model과 View를 갱신한다
MVC는 1970년대 후반 트리그브 린스카우그(Trygve Reenskaug)가 스몰토크(Smalltalk) 환경에서 처음 고안한 패턴이다. Controller는 사용자의 입력(버튼 클릭, 폼 제출)을 받아 Model을 갱신하고, 그 결과를 반영하도록 View에 명시적으로 지시한다.
| |
이 구조에서 Model은 View나 Controller의 존재를 전혀 모른다 — 결합도와 응집도의 낮은 결합도가 유지된다. 다만 handle_add에서 보듯, Model이 바뀔 때마다 “View를 어떻게 갱신할지"를 Controller가 명시적인 코드(self.view.render(...))로 지시해야 한다는 점이 핵심이다.
MVVM: ViewModel과 데이터 바인딩
MVVM은 마이크로소프트가 2005년경 WPF(Windows Presentation Foundation)와 함께 도입한 패턴이다. ViewModel은 Model의 데이터를 View가 표시하기 좋은 형태로 가공해 노출하고, View는 이 ViewModel의 상태를 관찰한다. 여기서 핵심 차이가 **데이터 바인딩(Data Binding)**이다 — View는 ViewModel의 속성이 바뀌면 프레임워크가 자동으로 화면을 갱신해주는 구독 관계를 맺는다. 이 구조는 옵저버 패턴의 Subject(ViewModel)-Observer(View) 관계와 본질적으로 같다 — ViewModel이 상태 변화를 통지하면, 구독 중인 View가 자동으로 반응한다.
| |
MVC의 Controller가 self.view.render(...)처럼 View 갱신을 명령형으로 직접 호출했던 것과 달리, MVVM에서는 ViewModel이 상태 변화를 통지하기만 하고 View가 그 통지를 구독해 스스로 갱신한다. 실제 프레임워크(WPF, Vue, Android Jetpack)에서는 이 구독·통지 과정을 프레임워크가 자동으로 처리해주므로, 개발자가 “View의 특정 텍스트 필드를 갱신하라"는 코드를 명시적으로 쓸 필요가 없다 — 이것이 데이터 바인딩이 Controller의 명시적 갱신 코드를 줄여주는 방식이다.
sequenceDiagram
participant U as "사용자"
participant C as "Controller"
participant M as "Model"
participant V as "View"
U->>C: "입력 (버튼 클릭)"
C->>M: "add_item()"
C->>V: "render() 명시적 호출"
sequenceDiagram
participant U as "사용자"
participant VM as "ViewModel"
participant M as "Model"
participant V as "View (구독자)"
U->>VM: "입력 (버튼 클릭)"
VM->>M: "add_item()"
VM->>V: "상태 변화 통지 (구독 기반)"
Note over V: "View가 스스로 갱신, ViewModel은 View를 모름"
비교: MVC vs MVVM
| 특성 | MVC | MVVM |
|---|---|---|
| 중재자 | Controller | ViewModel |
| View 갱신 방식 | Controller가 View 메서드를 명령형으로 직접 호출 | View가 ViewModel의 상태 변화를 구독(데이터 바인딩)해 자동 갱신 |
| View와 중재자의 관계 | Controller가 View 구현체를 알아야 함 | ViewModel은 View를 몰라도 됨(상태만 노출) |
| 테스트 용이성 | Controller 테스트 시 View 목 객체 필요할 수 있음 | ViewModel은 View 없이도 상태·로직만 독립적으로 테스트 가능 |
| 대표 사용 사례 | 전통적인 서버 사이드 웹 프레임워크(Ruby on Rails, Django) | 데이터 바인딩을 지원하는 클라이언트 프레임워크(WPF, Vue, Android) |
흔한 오개념
“MVVM이 MVC보다 항상 더 나은 상위 호환이다” — MVVM의 데이터 바인딩은 프레임워크의 바인딩 엔진이 필요하고, 바인딩 관계가 복잡해지면 “어떤 상태 변화가 어떤 화면 갱신을 유발하는지” 추적하기 어려워질 수 있다. 반면 MVC의 명시적 호출은 코드를 그대로 따라가면 흐름을 파악할 수 있다는 장점이 있다.
언제 MVC를, 언제 MVVM을 선택할 것인가
선택 기준은 크게 세 가지다. 첫째, 프레임워크가 네이티브 바인딩을 지원하는가다. Vue·WPF·Android Jetpack처럼 데이터 바인딩이 프레임워크에 내장돼 있다면 MVVM이 자연스럽고, 서버 사이드 렌더링 프레임워크(Ruby on Rails, Django)처럼 매 요청마다 화면을 새로 그리는 구조라면 바인딩을 유지할 상태 자체가 없어 MVC가 적합하다. 둘째, View의 상태가 얼마나 자주, 세밀하게 바뀌는가다. 입력값에 따라 여러 UI 요소가 실시간으로 갱신되는 화면(폼 유효성 검사, 실시간 계산기)은 MVVM의 자동 갱신이 유리하고, 페이지 전체를 한 번에 다시 그리는 것으로 충분한 화면은 MVC의 단순함으로도 충분하다. 셋째, 팀이 바인딩 디버깅에 익숙한가다. 바인딩 관계가 프레임워크 내부에 숨어 있어 추적이 어려운 만큼, 팀이 해당 프레임워크의 바인딩 디버깅 도구에 익숙하지 않다면 처음에는 MVC의 명시적 흐름으로 시작하는 편이 안전하다.
“Model이 View나 Controller/ViewModel을 알아도 된다” — 두 패턴 모두 Model이 View나 중재자를 참조하는 것을 금지한다. 위 예시에서 TodoModel은 TodoView나 TodoViewModel을 전혀 import하지 않는다. Model이 View를 알게 되면, 화면 없이 데이터 로직만 테스트하거나 다른 화면에서 재사용하는 것이 불가능해져 두 패턴이 추구하는 분리 목표 자체가 무너진다.
다른 개념과의 연결
MVVM의 데이터 바인딩은 옵저버 패턴의 Subject-Observer 구조가 UI 프레임워크 수준에 적용된 구체적인 사례다. 다음 챕터에서는 옵저버 패턴을 클래스 수준을 넘어 서로 다른 서비스 사이의 통신 구조로 확장한 이벤트 드리븐 아키텍처를 다룬다.
평가 기준
이 챕터를 읽은 후에는 다음을 할 수 있어야 한다. MVC의 Controller와 MVVM의 ViewModel이 각각 View를 어떻게 갱신하는지 그 방식의 차이를 설명할 수 있다. 데이터 바인딩이 옵저버 패턴과 어떤 관계인지 설명할 수 있다. 주어진 코드에서 Model이 View를 직접 참조하는 위반 사례를 찾아낼 수 있다.
참고 자료
Reenskaug, T. (1979). “THING-MODEL-VIEW-EDITOR: an Example from a planningsystem.” Xerox PARC technical note.
- Martin Fowler: GUI Architectures — MVC부터 MVVM까지 UI 아키텍처 패턴의 계보를 정리한 글
- Microsoft Learn: The MVVM Pattern — MVVM과 데이터 바인딩의 실무 적용 문서
![Featured image of post [Computer Terms] MVC와 MVVM (Model-View-Controller/ViewModel)](/post/computerterms/mvc-and-mvvm/wordcloud_hu_de5edf1547413499.webp)
![[Computer Terms] 팩토리 패턴 (Factory Pattern)](/post/computerterms/factory-pattern/wordcloud_hu_83b1a9c294d2589e.webp)
![[Computer Terms] 헥사고날 아키텍처 (Hexagonal Architecture)](/post/computerterms/hexagonal-architecture/wordcloud_hu_8dd03fd283046d54.webp)
![[Computer Terms] MVC와 MVVM (Model-View-Controller/ViewModel)](/post/computerterms/mvc-and-mvvm/wordcloud_hu_84c97e745273b4ae.webp)
![[Computer Terms] 이벤트 드리븐 아키텍처 (Event-Driven Architecture)](/post/computerterms/event-driven-architecture/wordcloud_hu_99bb70b885c09d08.webp)
![[Computer Terms] 가비지 컬렉션 (Garbage Collection)](/post/computerterms/garbage-collection/wordcloud_hu_22d0f6f1dc2ef90e.webp)
![[Tutorial] Learn Prompting - 프롬프트 엔지니어링 무료 가이드 정리](/post/2022-12-30-learn-prompting/wordcloud_hu_6a9d105de4834753.webp)
![[Hardware] LattePanda Alpha에 Ubuntu 16.04 LTS 설치 가이드](/post/2018-12-06-install-ubuntu-16.04-on-lattepanda/wordcloud_hu_fc536f8de2cbd4bf.webp)
![[Computer Terms] 옵저버 패턴 (Observer Pattern)](/post/computerterms/observer-pattern/wordcloud_hu_3e87990cdaad88f4.webp)
![[Rust] Comprehensive Rust 무료 강의 정리 및 코스 구조](/post/2022-12-30-comprehensive-rust/wordcloud_hu_d1420ff38434cdb6.webp)
![[OOP] 디미터의 법칙(Law of Demeter)과 결합도 낮추기](/post/2022-05-19-law-of-demeter/wordcloud_hu_ab8d5de33b6278d6.webp)