MVC, MVP, MVVM 바로알기

서두

이 글에서는 MVC, MVP, MVVM에 대해 제대로 정리해보고자 한다. 이런 구조들이 설명된 기존의 글들을 보면 설명이나 그림들이 꽤나 다르게 되어 있는 곳이 많아서 개인적으로 매우 혼란스러웠다.

특히 개인적으로 잘 이해되지 않았던 부분은 다음과 같다.

  • MVC의 구조와 설명이 너무나도 달라서 어느 것이 맞는 것인지 모르겠다.
    • Input이 View로 인입되는 그림도 있고, Controller인 경우도 있다.
    • View와 Model의 참조와 호출 관계가 제각각이다.
  • MVC와 MVP의 차이점이 무엇인지 명확하지 않다.
    • MVC의 그림이 제각각이어서 더욱 그렇다.
  • MVP와 MVVM은 구조는 같아 보이는데 무엇이 다른 것인가?
    • 단지 Binding과 역할의 차이인 것인가?

수일 간의 조사와 탐독 끝에 그나마 조금 명확해지는 부분들에 대해 정리를 해보고자 한다.

MVC에 대한 오해

서두에서도 얘기했지만 유수의 블로그나 포럼등을 상당히 읽어보았지만 국내, 해외 가릴것 없이 모두들 설명과 그림이 다르고 제각각이었다. 일단 기본적으로 MVC라는 구조 자체에 대한 합의가 되지 않는 느낌이었다.

나부터도 친분이 있던 마기님과 며칠을 토론하고 연구해도 쉽사리 답이 나오지 않고 오히려 개념이나 단어에 오해만 반복되어서 명확히 답을 내리지 못했었다.

마기님은 실습을 통해 나름의 해답을 얻으신 듯 하고 블로그에 훌륭히 정리도 해두셨다. MVC, MVP, MVVM 비교 | 마기의 개발 블로그

주저리

나도 오늘에서야 이 글을 쓰기 직전에 깨우친 사실인데, 마기님은 클라이언트 개발자이고 나는 서버 개발자이다보니 관점과 경험의 차이에서 오는 문제였었다. 아래 글을 전개하다보면 설명이 될 것이다.

물론 구조나 패턴이라는게 답이 있는 것은 아니지만 기본적인 개념부터도 너무나 합일이 되지 않은 설명들이 난무했다. 찾다 찾다 결국은 그래도 공신력이 있다고 볼 수 있는 위키를 보고나서야 조금 감을 잡을 수 있었다. (이럴줄 알았으면 미리 위키를 찾아볼 걸 그랬다.)

일단 아래 한글과 영문 위키를 읽지 않고 대표 그림만 봐도 벌써 이상함이 느껴진다. 무엇이 다른지 차근차근 비교해보자.


모델-뷰-컨트롤러 | 위키백과

MVC 구조를 공부해본 사람이라면 익숙히 보았을 그림이 첫번째일 것이다. 그런데 두번째 그림을 보면 View와 Model이 분리되어 있어서 MVP 구조와 동일해 보인다. 아래를 보면 더더욱 혼란에 빠지게 된다.

Model-view-controller | Wikipedia

영문 위키의 그림은 기존에 익숙히 봐오던 MVC 구조와는 사뭇 다르다. User가 등장하고 정보의 흐름이 단방향 순환구조이다. (어디서 많이 보던 구조인데? Flux/Redux)

TIP

이 그림을 보고 또 다른 인사이트가 발생하여 별도의 글에서 MVC와 Flux/Redux, VIPER 비교에 대해 써보려고 한다.


각설하고 짧게 말하자면 영문 위키가 조금 더 정확한 그림과 설명이라고 볼 수 있다. 한글 위키의 설명은 엄밀히 말하자면 MVC의 웹 기반 변형인 JSP Model 2라고 봐야 한다.

아마도 추측컨대 지난 십수년간 Java와 PHP가 지배해온 한국 SW 산업의 특성상 JSP Model 2가 MVC와 동일시 되어온 결과로 생각된다.

먼저 JSP Model 2가 무엇인지 알아보자.

TIP

나와 유사한 생각을 가진 분의 글도 있고 더욱 자세히 설명되어 있으니 참고하면 좋겠다. 아직 2번 3번 글이 올라오지 않았는데 기대중이다. M-V-Whatever 정리 - 1. MVC

JSP Model 2 (Web MVC)

JSP model 2 architecture | Wikipedia

그렇다. 이 그림이 한글 위키의 MVC 그림과 거의 동일하다. 대강 읽어보면 MVC2라는 별칭으로 불리면서 혼란을 가중시킨 것으로 보인다.

이 구조의 특징은 바로 서버사이드 구조라는 점이다. 자체적으로 Active하게 스레드가 가동되는 그런 구조가 아니라, HTTP 요청에 따라 Passive하게 로직이 수행되는 구조이다.

각 부분의 역할을 정리해보자.

  • Model: 단순 데이터 객체.
  • View: Model을 참조하여 화면을 구성한다.
  • Controller: 사용자 입력을 받고, 로직을 수행하고, Model을 변경하고, View에 렌더링을 요청.

흐름을 정리해보자.

  1. 사이트 접속이나 사용자 이벤트로 HTTP 요청이 서버로 전송된다.
  2. Controller가 관련 Model을 수정하고 적절한 View를 골라 렌더링 요청한다.
  3. 해당 View는 관련 Model을 조회하고 HTML로 렌더링하고 브라우저로 응답한다.
  4. 브라우저는 수신한 HTML을 화면에 표시한다.
  5. HTML내에는 Form이 존재하고 사용자 이벤트에 따라 1.로 반복된다.

매우 클래식한 웹 사이트의 동작 방식이다. 요즘 말하는 MPA(Multi Page Architecture)이며, RESTful의 개념도 적용되기 전의 일이다. (JSP Model 2는 90년대이고, RESTful은 2000년에 등장하였다.)

이때는 Thin Client라고 하기도 민망할 정도로, 자바스크립트는 아얘 없거나 화면에서 약간의 움직임을 처리하는 수준이 전부였다.

이후 jQuery가 등장하면서 Fat Client로 점차 변하기 시작했고, 서버는 API 형태로만 존재하게 되며 서블릿이 거의 불필요해지는 형태로 변모하게 된다. (여기서 굳이 다루지 않아도 널리 알려진 역사이니 생략하도록 한다.)

나도 2000년대 중반부터 다루었던 PHP에서 경험해보았기 때문에 매우 익숙한 구조이다. 나 역시도 이게 MVC의 전부라고 여기고 있었으니...

MVC 다시 보기

자, MVC의 영문 위키를 다시 찬찬히 읽어보자.

Model-view-controller | Wikipedia

여기서 설명하는 MVC는 클라이언트 사이드의 구조라고 생각하면 되겠다. 윈도우 MFC 프로그래밍 하시던 분들은 오히려 이게 더 익숙할 수 있겠다.

어느 블로그의 MVC 설명에서 Model이 수정되며 View로 이벤트를 전송한다고 했던 (서버 사이드라면 이해되지 않았을) 설명이 이제서야 이해가 된다.

각 부분의 역할을 정리해보자.

  • Model: 구조의 중심. 동적 데이타 구조이며, UI와 독립적이다. 직접적으로 데이타, 로직, 규칙을 다룬다.
  • View: 정보를 여러가지 형태로 표현할 수 있다. 하나의 정보가 여러 개의 View로 표현될 수 있다.
  • Controller: 사용자 입력을 받아서 Command 패턴 형태로 Model 또는 View에 전달한다.

애매한 부분이 바로 비즈니스 로직이 어디에 위치하느냐이다. 위키에서는 Model이 로직을 포함한다고 되어있는데 Command 패턴 역시 로직을 담고 있을 수 있기 때문이다. 포럼을 찾아보면 보통은 Controller가 포함하고 있는 듯 하다.

또한 View와 Model의 의존 관계가 그림마다 제각각인데, 역시 세부 구현에 따라 달라질 것으로 보인다. View가 Model을 Observer 패턴으로 감시하다가 스스로 변경될 수도 있고, Controller의 호출에 의해서 View가 변경될 수도 있겠다. 전자의 경우가 더욱 깔끔해 보인다.

역할과 책임에 따라 어느정도 분리가 되어 있으므로 구조가 없던 시절에 비해 개발팀 구성이나 유지보수에 유리해진다. 다만 부분 간의 결합도가 강한 편이라 테스트 측면에서는 좋지 못한 편이다.

MVP

한글 위키에는 MVP에 대한 페이지가 없다. 하지만 MVP는 특별한 이견 없이 많은 블로그들에 잘 설명되어 있으니 참고하자.

Model-view-presenter | Wikipedia

각 부분의 역할을 정리해보자.

  • Model: 사용자 입력에 대응하거나 보여지기 위한 데이타를 정의하는 인터페이스이다.
  • View: 데이타를 보여주고, 사용자 입력을 수신하는 수동적(passive) 인터페이스이다.
  • Presenter: Model로부터 데이타를 받아 View에 표시하기 위해 가공한다.

설명에 따르면, 극단적인 구조에서 View는 완전히 수동적이며 사용자 입력 이벤트에도 Presenter로 파라미터 등은 전달하지 않는다. 단순히 이벤트가 발생했다는 신호만 전달하며, Presenter가 View의 메소드를 사용해 값을 얻어낸다.

꼭 그래야만 한다는 뜻은 아니지만, 최대한의 로직을 배제하고 View 본연의 임무인 화면 표시에 집중하자는 의미로 받아들여진다.

MVC와 다른점은 Model과 View가 직접적인 참조/호출 관계를 가지지 않는다는 점이다. 그렇다고 일부 블로그 설명처럼 반드시 Model을 분해해서 전달하라는 뜻은 아닐 것이다. 만약 View가 절대 Model을 모르게 하기 위해서, 기본 타입들(string, number등)로 변환하기 어려운 데이타를 굳이 수많은 코드를 써가며 코딩해야 한다면 차라리 절충점을 찾는 것이 나을 것이다.

우리가 필요한 것은 개발/유지보수를 편하게 하는 것이지 이상적인 구조를 바라보며 정신적으로 만족하자는 것은 아닐테니까.

Model과 View가 직접 참조하지 않음으로써 MVC에 비해 테스트가 용이해지는 면이 있다. View에 로직이 거의 사라졌기 때문에 테스트가 간단해진다. 다만 View가 단순해지는 대신 Presenter가 많은 부담을 지게 되므로 Presenter가 비대해지기 쉽고 테스트도 그만큼 어려워진다.

MVVM

MVVM은 그림상으로는 MVP와 동일해 보인다. 차이가 무엇인지 살펴보자.

Model-view-viewmodel | Wikipedia

각 부분의 역할을 정리해보자.

  • Model: 실제 데이타(데이타 지향) 또는 도메인 모델(객체 지향)을 의미한다.
  • View: View model을 화면에 표현하고, 사용자 입력을 View model로 전달한다.
  • View model: public 속성과 메소드를 가지는 추상화된 View 정도로 보면 되겠다.
  • Binder: View와 View model 사이에서 데이타/이벤트 전달을 중개한다.

MVP에서는 표현 로직이 Presenter에 존재했다면, MVVM에서는 MVC처럼 View에 포함된다. View model에서 추상화 되어있는 부분이 실제적으로 표현되기 위한 구현이 어딘가에는 있어야 하고, 실제 Angular 또는 Vue를 보면 템플릿에서 선언적 형태로 View가 구현되어 있다. (MVVM의 원조는 WPF인데, 거기선 어떤 형태인지 정확히 조사해보지 못했다.)

그나마 여기서는 (그림에는 없지만) Binder를 드러내놓고 설명해두었다. 대부분의 MVVM 설명에서는 View와 View model이 그저 Binding 기술로 잘~ 연결되어 있다고 설명해버리고 끝이다. 하지만 알고보면 중간에 Binder라는 기술 또는 코딩이 프레임워크에 내장되어 있어서 MVC나 MVP에서 코딩해야 했던 이벤트 핸들러나 메소드 호출 등의 코드를 상당수 자동화 해준 것 뿐이다.

Binder는 프레임워크들이 제공하기 때문에 자세히는 몰라도 상관 없지만, 내부적으로 이를 위해 Reactive 기술이나 Publish-Subscribe 구조 등이 적용되어 있음을 알고 있는 것이 좋다. 상세하게 MVVM을 설명한 글들에서는 이에 대해 언급하고 있다.

MVVM은 View와 View model이 Binder를 통해 간접적으로 연결되기 때문에 결합도를 매우 낮추어 놓았고 테스트 하기가 더욱 용이해 질 수 있다.

Angular 또는 Vue에서는 조금 이야기가 다른데, View(template)와 View model(property 또는 data)은 떨어뜨리기 어려운 개념이다. 이쪽 세계에서는 최소 단위가 Component이며 단위 테스트 역시 Component를 기준으로 설명되고 있다.

굳이 각자를 테스트 하려면... 실제 해보지는 않았지만 다음과 같이 가능하지 않을까. View model만을 테스트 하기 위해서는 그저 Component를 대상으로 내부 데이타를 읽어서 검증하면 될 것 같다. View를 테스트 하기 위해서는 템플릿을 Mock Component에 부착하여 테스트해보는 방법이 가능할 것 같다.

결론

긴 글이었던 만큼 결론도 난잡하다.

  • 정답이란 없다.
    • 모든 설계 이론이 그렇지만, 정답이나 교본이 존재하지는 않는다.
    • 그런만큼 상황에 맞게, 적절히 응용하여 사용하는 것이 중요하다.
    • 추구하는 기본 개념에 주목하자. 화살표 방향이나 단어에 목메지 말자.
    • 구조의 단위가 화면인지, 컴포넌트인지에 따라서 시각이 달라질 수 있다.
  • 구조란 개발과 유지보수를 용이하게 하기 위함이다.
    • 분업이 가능하고, 테스트가 용이하고, 재사용이 가능하다면 그게 바로 좋은 구조이다.
    • 구조에 따른 오버헤드가 분명 존재한다. Trade off를 고려하자.
  • 공통적으로 Model은 잘 분리되어 있고, 부분 간의 책임을 세분하고 결합도를 낮추는 방향으로 발전하고 있다.
  • Web MVC: 서버사이드에서 렌더링 되는 웹의 초기 MVC 구조. 일반 MVC와 사뭇 다르다.
  • MVC: 데이터, 표현, 처리를 분리했다는 점에서 의미가 있다.
  • MVP: Model과 View의 결합도를 낮추었다.
  • MVVM: View와 View model의 결합도를 낮추었다.

재사용의 관점에서...

  • Model의 재사용은 어떤 구조든지 가능하다.
    • 일단 Model을 재사용 한다는 의미는 동일 서비스를 다른 형태로 개발하는 경우일 것이다.
    • 언어만 동일하다면 구조, 프레임워크, 플랫폼 독립적으로 재사용이 가능하다.
    • Model은 설계나 문서화도 용이한 만큼, 다른 언어로의 포팅도 수월할 것이다.
  • MVP는 디자인 역시 재사용에 유리하다.
    • 디자인을 재사용 한다는 의미는 다른 서비스를 같은 형태로 개발하는 경우이다.
    • 다른 플랫폼에서는 아마도 표현의 형태가 다를 것이기 때문에 재사용이 어려울 것이다.
    • MVP는 View의 로직은 거의 없기 때문에, 코드를 제외한 디자인 레벨의 재사용을 고려하면 될 것이다.
  • MVVM은 디자인과 그 동작까지 재사용하기 유리하다.
    • View와 View model이 결합하여 Component를 구성하며, 이들이 재사용되기는 매우 쉽다.
    • 다만 Binding 기술등이 프레임워크 특화이기 때문에 다른 프레임워크로의 재사용은 어렵다.
최종 수정: 2019-1-3 04:38:52