TOC
참고
본 내용은 자바스크립트+리액트 디자인 패턴(링크) 를 읽고 정리한 내용입니다. 책의 내용과 함께 개인적인 의견과 생각을 담아 작성하였습니다.
MVC 패턴
애플리케이션 구조를 개선하기 위해 관심사의 분리를 활용하는 아키텍처 디자인 패턴
- 모델(Model), 뷰(View), 컨트롤러(Controller)로 구성
- 모델을 애플리케이션의 다른 인터페이스에서도 사용할 수 있다.

모델(Model)
- 애플리케이션의 데이터를 관리하는 역할
- 비즈니스 데이터와 주로 관련
- 변경 시 자신의 관찰자 객체에게 알림을 보냄
- 관찰자가 변경된 내용에 알맞게 능동적으로 대응 가능
- 보통은 모델의 속성을 검증하는 기능 지원
뷰(View)
- 사용자 인터페이스를 담당
- 모델의 현재 상태를 표현
- 관찰자 패턴을 사용해 모델이 변경되었을 때 업데이트
- JS의 뷰는 여러 DOM 요소의 집합을 생성/정리
컨트롤러(Controller)
- 모델과 뷰를 연결하는 중재자 역할
- 사용자가 뷰를 조작할 때 모델을 업데이트
MVC 패턴의 장점
- 전반적인 유지보수의 단순화 : 변경사항이 데이터 중심인지, 아니면 단순히 시각적인 변경인지 명확히 구분 가능
- 모델과 뷰의 분리 : 단위테스트의 작성이 훨씬 간편
- 모듈화 : 코어 로직 작업과 UI 작업의 분리로 개발자들이 독립적으로 작업 가능
MVC 패턴의 단점
- 뷰와 컨트롤러 간의 강결합 : 한 곳의 수정이 필요할 때 수정이 동반
- 내재된 복잡성 : 모델, 뷰, 컨트롤러 각각을 별도로 관리해야 함
MVP 패턴
프레젠테이션 로직의 개선에 초점을 맞춘 MVC 패턴의 변형

프레젠터(Presenter)
- 뷰에 대한 UI 비즈니스 로직을 담당
- 뷰에서의 이벤트 호출은 프리젠터로 위임 (MVC 패턴과 달리)
- 뷰와 분리되어 있으며 인터페이스를 통해 뷰와 통신
MVC와 달리?
나의 생각
MVC 패턴도 컨트롤러가 사용자가 뷰를 조작할 때 모델을 변경하는 중재자 역할을 하기 때문에 뷰에서의 이벤트 호출이 위임된다는 개념으로 생각했어요. 그런데 MVP는 'MVC와 달리' 이벤트 호출을 프레젠터로 위임한다고 하니 무슨 차이인지 잘 모르겠더라고요.
'둔한' 수동형 뷰
- MVP 패턴에서는 뷰를 주로 '둔한' 수동형 뷰로 만든다.
- 수동형 뷰는 로직을 거의 가지고 있지 않는다.
- 직접적인 데이터 바인딩의 개념이 없다.
- 이벤트를 구독하여 뷰를 업데이트할 수 있도록 하는 것이 프레젠터의 역할
MVC에서 MVP로의 변화
- 애플리케이션의 테스트 용이성 향상
- 뷰와 모델간의 분리를 더욱 명확하게 구분
- 데이터 바인딩이 지원되지 않아 작업을 별도로 처리해야 하는 비용이 발생
MVP를 활용하면 좋은 경우
- 프레젠테이션 로직을 최대한 재사용해야 하는 엔터프라이즈 수준의 애플리케이션
- 뷰가 매우 복잡하고 사용자와의 상호작용이 많은 애플리케이션
- MVC가 해결하려면 여러 컨트롤러에 크게 의존해야 한다.
- MVP에서는 모든 복잡한 로직을 프레젠터 안에 캡슐화할 수 있어 유지보수가 훨씬 간단
- 단, MVC와 MVP 간의 차이점은 대부분 의미론적인 수준
MVVM 패턴
MVC와 MVP를 기반으로 하는 아키텍처 디자인 패턴
- 선언적 데이터 바인딩을 활용하여 뷰에 대한 작업을 다른 계층과 분리
- 동일한 코드베이스 내에서 UI와 비즈니스 로직을 분리

뷰(View)
MVVM의 뷰는 MVC와 MVP의 뷰와 달리 능동적 뷰로 구성
수동적 뷰
- 단순히 화면을 출력할 뿐 사용자의 입력을 받아들이지 않음
- 애플리케이션의 모델에 대한 구체적인 정보를 가지고 있지 않을 수 있다.
- 프레젠터에 의해 조작되는 뷰
능동적 뷰
- 데이터 바인딩, 이벤트, 동작들을 포함하기 때문에 뷰모델에 대한 이해를 필요로 한다.
- 뷰모델로부터 발생한 이벤트를 처리하는 책임은 여전히 뷰에 있다.
- 뷰는 상태를 관리할 책임이 없다. : 뷰는 뷰모델과 정보 또는 상태를 항상 동기화된 상태로 유지하기 때문
뷰모델(ViewModel)
뷰모델은 UI 계층의 뒤쪽에 위치한다.
- 데이터 변환 : 모델의 정보를 뷰가 사용할 수 있는 형태로 변환
- 데이터 바인딩 : 뷰와 모델 사이의 데이터 동기화
- 이벤트 처리 : 뷰에서 발생한 명령을 모델로 전달
- 뷰의 디스플레이 로직 대부분을 처리
- 뷰의 상태를 유지하고, 뷰에서 발생한 동작에 기반해 모델을 업데이트
- 뷰에 이벤트를 발생시키는 등의 기능을 수행하기 위한 메서드를 제공
뷰와 뷰모델
- 뷰와 뷰모델은 데이터 바인딩과 이벤트를 통해 소통
- 뷰는 자체 UI 이벤트를 처리
- 필요에 따라 뷰모델에 연결
- 모델과 뷰모델의 속성은 양방향 데이터 바인딩을 통해 동기화 및 업데이트
뷰모델 vs 모델
- 뷰모델은 모델에 대해 전적인 책임을 진다.
- 뷰모델은 데이터 바인딩을 위해 모델 또는 모델의 속성을 가져올 수 있다.
- 뷰에 제공되는 속성을 가져오거나 조작하기 위한 인터페이스를 포함할 수 있다.
MVVM 패턴의 장점
- 뷰와 뷰모델의 분리 : 뷰와 뷰모델은 서로 독립적으로 테스트 가능
- 뷰의 추상화 : 뷰의 뒤에 작성되는 비즈니스 로직의 양 감소
- 테스트 용이성 : 뷰모델은 모델에 가까워 UI 고려 없이 테스트 가능
MVVM 패턴의 단점
- 과도한 코드량 : 단순한 UI의 경우, 과도한 구현이 될 가능성 높음
- 데이터 바인딩과 테스트 : 단순히 중단점을 설정하는 명령형 코드에 비해 디버깅이 어려울 수 있음
- 데이터 바인딩의 복잡성 : 데이터 바인딩이 상당한 관리 부담을 만들어낼 수 있음
MVC vs MVP vs MVVM
MVC와 두 파생 패턴들 사이의 핵심 차이 : 계층간 의존성과 연결 강도
MVC
- 뷰가 아키텍처의 최상단에 위치하고 그 옆에 컨트롤러가 위치
- 뷰가 모델에 직접 접근할 수 있다.
- 전체 모델을 뷰에 노출시키면 애플리케이션의 복잡도가 증가할 수 있다.
- 심하면 보안 및 성능 문제가 발생할 수 있다.
- MVVM은 이를 해결하기 위한 패턴
MVP
- 컨트롤러의 역할이 프레젠터로 대체
- 프레젠터는 뷰와 동일한 계층에 존재
- 뷰와 모델 양쪽에서 발생하는 이벤트를 수신하고 양측의 동작을 조정
- 뷰와 뷰모델을 바인딩하는 메커니즘을 제공하지 않음
- 각 뷰는 프레젠터가 뷰와 상호작용할 수 있도록 인터페이스 구현
MVVM
- 상태와 로직 정보를 포함할 수 있는 뷰와 관련된 모델 일부를 생성 가능
- 전체 모델을 뷰에 노출하는 것을 방지 가능
- 뷰모델이 뷰를 참조할 필요가 없음
- 뷰는 뷰모델의 속성을 바인딩하여 모델과 동기화
- 뷰가 추상화되어 뷰에 필요한 로직의 양이 줄어듦
최신 MV* 패턴
Vue.js
MVVM 패턴을 기반으로 하는 프레임워크
- Vue 인스턴스 : 뷰와 뷰모델을 생성
- 데이터 바인딩 : 뷰와 뷰모델 사이의 데이터 동기화
- 이벤트 처리 : 뷰에서 발생한 명령을 뷰모델로 전달
- 컴포넌트 : 뷰와 뷰모델을 재사용 가능한 단위로 분리
React
뷰 계층을 원하는대로 구성하게 해주는 렌더링 라이브러리
- 선언형 프로그래밍 방식
- '뷰'가 아닌 '데이터'를 제공하는 라이브러리
- 서버가 브라우저에 '뷰'를 직접 제공하지 않고, '데이터'를 제공
- 기존 MVC처럼 중앙 제어 역할을 하는 컨트롤러, 혹은 라우터가 없음
- 브라우저에서 데이터를 받아 뷰를 생성
- 전통적인 MVC로 분류하기 어려움
- 수직 분할형 컴포넌트
- MVC를 기술에 따른 수평적 분할 하는 것이 아니라, 관심사에 따라 수직적으로 분할
- 상태(모델), 렌더링(뷰), 제어 흐름 로직(소규모 지역화 컨트롤러)을 담는 수직 분할형 MVC
총평
그동안 MVC, MVVM 패턴에 대해서 많이 들어봤음에도 각각의 요소들이 뭘 의미하는지 정확히 알지는 못했어요. 그런데 각 구성 요소들을 하나하나 파헤쳐보고 아키텍처 패턴마다 차이점을 시각적 다이어그램과 설명을 통해 파악하니 조금은 머리에 들어온다는 생각이 들었어요.
하지만 구조의 개념적인 부분이어서 코드 레벨로 구현된 예시 코드가 없다보니 실제로 활용한다면 어떻게 활용해야 할 지 조금은 막막하다는 생각이 들어요. 그래서 간단하게 정리해볼 수 있는 예시 코드를 발견한다면 추가해봐도 좋을 것 같네요.