MVVM (Model-view-viewmodel).md
 

 

MVVM (Model-view-viewmodel) pattern

MVVM pattern은 Model-View-ViewModel의 약자로 소프트웨어 아키텍쳐 패턴이다. 초기 UI 개발자들은 모든 코드 로직(이벤트 핸들링, 초기화, 데이터 모델)을 뷰에 작성했다. 모든 코드들을 뷰에 작성하다보니 뷰의 크기가 커지고, UI와 데이터 바인딩간의 의존성 문제가 일어나다보니 개발자들의 협업 개발에서 많은 이슈가 일어나고 유지보수, 확장이 어려워졌다. 이를 해결하기 위해 사용자 인터페이스에 해당하는 뷰(View)와 뷰에 표시되는 데이터(Model) 그리고 뷰(View)와 모델(Model) 사이에서 여러 비즈니스 로직을 처리하는 뷰-모델(View-Model)로 분리하여, 유지보수를 쉽게하고 뷰(View) 처리에 다양한 기능을 사용할 수 있게 되었다.

Three key parts in the MVVM pattern

  1. Model (비즈니스 규칙, 데이터 접근, 모델 클래스)
  2. View (사용자 인터페이스)
  3. ViewModel (모델과 뷰 사이의 인터페이스)

뷰모델(ViewModel)은 모델(Model)과 뷰(View)사이에 인터페이스 역할을 한다. 뷰모델은 모델의 데이터를 뷰에 바인딩하고, 명령어를 사용하여 모든 UI의 동작들을 다룬다. 뷰는 뷰모델의 프로퍼티에 제어값을 바인딩하며 차례대로 모델 객체에 있는 데이터를 노출시킨다.

예를 들어 사용자가 뷰에 있는 계산기 프로그램을 사용하여 결과값을 요청하는 버튼을 클릭했을 때, 뷰모델이 요청받은 동작을 수행한다. 뷰모델의 연산 기능을 담당하는 명령어는 연산 후 모델의 데이터 값을 변경시킨다. 만약 뷰모델의 속성값이 변경되면(모델의 데이터 값이 변경되면) 새로운 속성 값들은 데이터 바인딩(data binding)과 알림(notification)을 통해 자동적으로 뷰에 적용된다.

 

MVVM in Vue.js

Vue.js는 위의 설명된 MVVM 패턴에서 ViewModel 계층에 초점을 둔 프레임워크이다. 뷰모델을 통해서 양방향 데이터 바인딩이 가능하게 해주며, 뷰 계층을 좀 더 간단하고 유연하게 디자인하게 해준다.

아래 그림은 Vue.js에서 MVVM을 나타낸 그림이다. (출처 : https://012.vuejs.org/images/mvvm.png)

MVVM Concepts

ViewModel in Vue.js

모델과 뷰의 동기화 역할을 하는 객체이다. Vue.js에서 모든 뷰 인스턴스(View instance)는 뷰모델(ViewModel)이다. 이들은 Vue 생성자 혹은 하위 클래스들에 의해 인스턴스화된다.

 

이렇게 초기 객체를 선언해줌으로써 뷰와 모델 사이에서 양방향 데이터 바인딩이 가능하게 해준다. 더 자세한 정보는 The Vue Constructor를 확인하자.

 

View in Vue.js

뷰의 실제 돔(DOM)은 Vue instances에 의해 관리된다.

 

Vue.js는 DOM 기반의 템플릿을 사용한다. 각 뷰 인스턴스는 해당 DOM 요소에 연관된다. 뷰 인스턴스가 생성되면 필요한 데이터 바인딩을 설정하는 동안 루트 요소의 모든 자식 노드를 반복적으로 탐색한다. 뷰가 컴파일이 되면 데이터 변경에 반응할 수 있게 된다.

즉, 해당 HTML 컴포넌트 범위(해당 DOM 요소가 담긴 템플릿)를 Vue instace의 vm.$el에 설정한다. 뷰는 Vue instance가 생성 될 때 컴파일 되며 뷰모델의 다양한 동작 기능들이 바인딩 된다. 그렇게 됨으로써 뷰의 변경이 감지되면 뷰모델이 이를 감지하여 반응할 수 있게된다. 추가적으로 뷰의 변경은 집단적으로, 비동기로 실행되기 때문에 높은 성능을 발휘한다.

 

Model in Vue.js

 

Vue.js에서 모델은 단순히 자바스크립트 객체 혹은 데이터 객체로 표현할 수 있다. 데이터 객체의 프로퍼티를 조작하면 이를 관찰하는 뷰 인스턴스가 변경을 알린다. Vue.js는 ES5 getter/setters로 데이터 객체의 프로퍼티를 변환한다. 그렇기에 뷰를 변경하기 위해 Vue에 명시적으로 신호를 보낼 필요가 없다. 또한 각 뷰 인스턴스는 데이터 객체에 있는 모든 프로퍼티들을 프록시한다.

아래 그림은 Vue.js에서 반응형 업데이트가 구현되는 방식을 보여준다. (출처 : https://012.vuejs.org/images/data.png)

high-level overview of how reactive updates

 

참고 자료

'Vue.js' 카테고리의 다른 글

Vue.js : 새롭게 추가된 Virtual DOM  (4) 2017.12.26
Vue.js : Virtual DOM.md

Vue.js 2.0에 새롭게 추가된 "Virtual DOM"에 대하여...

Vue.js 는 주로 Angular와 React의 장점들을 고루 갖고 있는 특징이 있다.

이번에 Vue.js 2.0 버전의 주요 특징 중 하나로 페이지 변경을 위한 "Virtual DOM" 이 추가되었다.

"Virtual DOM"은 React에서 많이 들어보았을 것이다.

React와 Ember에서 사용하는 이 "가상 돔"은 웹 페이지의 변경 속도를 매우 빠르게 해준다.

 

먼저 가상 돔의 원리를 이해하기 전에 브라우저의 동작 원리DOM에 대한 몇 가지 특징을 알아볼 필요가 있다.

 

 

브라우저의 동작

사용자가 웹 브라우저의 주소 표시줄(사용자 인터페이스)에 URL을 입력하면 브라우저 엔진은 이를 해석하고,

적절한 HTTP Request Message를 만들어 웹 서버에 전달하게 된다. 웹 서버는 요청된 방식에 따라 응답 메시지를 만들

어 클라이언트에게 다시 보내준다. 브라우저의 렌더링 엔진 은 웹 서버에서 응답한 메시지의 콘텐츠를 화면에 표시한다.

( 예를 들어 HTML을 요청하면 HTML과 CSS를 파싱하여 화면에 표시 )

 

렌더링 엔진의 기본적인 동작 과정 ( HTML만을 예시로 들자면 )
DOM 트리 구축을 위한 HTML 파싱 => 렌더 트리 구축 => 렌더 트리 배치 => 렌더 트리 그리기 -> 표시

( 보다 자세한 렌더링 과정은 "브라우저는 어떻게 동작하는가?" 문서를 보길 바란다 )

HTML 파싱 과정에서 DOM 트리가 생성되는데 "DOM" 이 무엇인지 알아보자

 

DOM(Document Object Model)

문서의 객체 모델

- HTML 내에 들어 있는 요소를 구조화 객체 모델로 표현 하는 양식

 

HTML 문서가 아래와 같다면

 

 

DOM 트리 구조는 아래처럼 표현할 수 있다. ( 이미지 출처 - http://d2.naver.com/helloworld/59361 )

 

domtree

 

 

DOM의 특징

  • 위의 그림과 같이 트리의 부모 자식 관계로 형성

  • HTML 요소들(nodes)을 탐색하고 수정할 수 있는 API를 제공

    ex) getElementById, removeChild

     

DOM의 문제점

= "It’s expensive to update the DOM"

 

우리는 스크립팅 언어인 자바스크립트를 사용하여 웹페이지를 동적으로 변경시킨다.

이 때, 브라우저는 목표 DOM 노드들을 찾은 후 원하는 변경 사항에 맞게 조작하기 위해 몇 가지 작업을 한다.

 

 

일반적인 앱에서, DOM에는 수 천개의 노드들이 존재할 수 있고 업데이트를 위해 복잡한 처리 과정이 필요하게 된다.

이로 인해 브라우저의 속도는 느려지게 된다. 상단의 브라우저 동작 원리를 설명한 이유는 이 문제점 속에 있다.

먼저 브라우저에서 페이지를 로드하게 되면 렌더링 트리와 돔 트리를 생성하게 되고 여러 과정을 거쳐서 브라우저에 CSS가 적용된 페이지가 그려지게 된다. 여기서 자바스크립트로 DOM을 조작할 때 렌더링 트리는 각 변경 사항마다 하나씩 해석하여 렌더링을 시키게 되는 구조이다.

그런데 만약 한 번의 상태 변경으로 여러곳의 DOM 변경(노드들의 수정)이 일어난다면 어떻게 될까?

수 천개의 노드들이 변경되어 렌더링 되기까지 적지 않은 시간이 걸릴 것이다.

현재까지 웹에서는 DOM 변경에 맞추어 렌더링도 여러번 하게 되는 구조일 수 밖에 없었다. 그리고 사실 pure JavaScript를 사용해 DOM 객체를 조작하는 비용보다 DOM을 조작했을 때 화면을 다시 그리는 비용(렌더링 계산)이 훨씬 크다.

(https://www.slideshare.net/gyeongseokseo/virtual-dom 참고)

 

이를 해결하기 위해 등장한 것이 "Virtual DOM" 가상 돔이다.

 

가상 돔 (Virtual DOM)

  • 먼저 가상 돔은 리액트에서 나온 개념이 아니다. 하지만 리액트는 무료로 이 개념을 사용하고 사용자들에게 제공한다. Vue.js도 마찬가지이다.

  • 가상 돔은 HTML 돔의 추상화 개념이다. 이것은 가볍고, 브라우저 스펙의 구현체와는 분리되어있다. 사실, 돔은 이미 추상화 개념이기 때문에 가상 돔은 추상화를 또 추상화한 개념이다.

  • DOM의 복사본을 메모리 내에 저장하여 사용

  • 변경 사항을 "가상의" 위치에서 처리하고, "실제 DOM"의 조작을 최소화한다. 즉, DOM트리를 모방한 가벼운 자바스크립트 객체를 통해 직접 DOM을 핸들링 하지 않고 퍼포먼스를 향상시킨다.

     

DOM 노드들은 일반적으로 HTML 문서에서 아래와 같이 표현된다.

 

아마도 아래 코드는 우리가 DOM API를 사용하여 DOM을 변경하는 방법일 것이다.

 

 

가상 DOM 노드들은 이처럼 자바스크립트 객체 형식으로 표현될 수 있다.

 

아마도 아래 코드는 우리가 가상 DOM을 변경하는 방법일 것이다.

 

 

DOM 조작을 위해서 getElementById와 같은 DOM API를 사용한 코드가 아닌 가상 돔을 사용한다면,
코드는 단지 자바스크립트 객체로 변경되는 매우 저렴한 비용이 들 것이다.

 

그런 다음, 아래 코드를 통해 가상 돔 변경 부분과 실제 돔의 동기화 작업이 이루어진다.

 

 

이런 방법으로 한 번의 상태 변경으로 여러곳의 DOM이 변경된다고 해도 가상화된 DOM에서 전부 변경하고
진짜 돔과 비교해서 변경된 부분을 한번에 적용시키는 방식으로 DOM의 렌더링 횟수를 줄이게 된다.

 

Vue.js version 2에서 추가된 가상 돔은 과연 괜찮을까?

 

1. 크기

가상 돔의 추가와 같은 여러 기능을 추가하기 위해서는 코드 패키지에서 많은 수의 라인을 추가하는 것을 의미한다.

그렇지만 Vue.js 2.0은 여전히 작은 파일 크기를 유지한다. (현재 릴리즈는 21.4kb)

2. 메모리

가상 돔의 유지를 위해서는 메모리 내에 DOM의 복사본을 생성한다.

돔의 변경 속도와 메모리 사용을 교환한 것이다.

3. 사용 환경

가상 돔은 많은 수의 변경 사항을 한꺼번에 처리할 때 사용하는 것을 추천한다.

하지만 단일 변경 사항이 드물게 일어난다면? 가상 돔은 돔 변경을 하기위해 무의미한 연산을 할 것이다.

 

그러므로, 만약 프로젝트가 상대적으로 적은 노드 수가 있다면 오히려 가상 돔으로 인해 페이지의 변경 속도가 느려질 것이다.

하지만 대부분의 단일 페이지 애플리케이션에서는 향상된 성능을 가질 것이다.

 


 

Vue.js의 가상 돔의 코드를 확인하고 싶다면 https://github.com/vuejs/vue/tree/dev/src/core/vdom 확인

 


 

Vue.js를 공부하다 나온 "가상 돔"을 이해하기 쉽게 설명드리고 싶었지만 어쩌다보니 구글링한 문서들의 내용들이 짬뽕이 되었습니다.. 아직 확실하게 이해못한 가상돔 개념과 처음으로 시도한 블로그 포스팅이 만나, 매우 부족한 글을 쓰게된 것 같습니다. 너그러운 마음으로 글을 봐주시길 바랍니다! Vue.js를 공부하면서 확실한 개념을 잡아갈 때마다 글을 다시 수정하도록 하겠습니다. 감사합니다.

 


 

참고 링크들

'Vue.js' 카테고리의 다른 글

MVVM(Model-View-ViewModel) in Vue.js  (0) 2018.01.19

+ Recent posts