오늘은 MVVM 패턴에 대한 이해를 빠르게 가져보고 MVVM 패턴을 고찰해 보는 시간을 가져 보겠습니다.
MVVM 패턴이란?
MVVM 패턴은 모델-뷰-뷰 모델(Model-View-Viewmodel, MVVM) 아키텍처 패턴으로 마이크로소프트의 켄 쿠퍼(Ken Cooper)와 테드 피터스(Ted Peters)에 의해 만들어졌습니다. 이는 모델-뷰-바인더(model-view-binder)의 일종입니다. 다른 아키텍처 패턴으로 MVC(Model-View-Controller), MVP(Mode-View-Presenter)가 있고, 최근에 MVU(Model-View-Update) 패턴을 살펴볼 수 있습니다.
MVVM 패턴에서 뷰모델
은 특이한 포지션을 가지는데, 모델
을 뷰
에 노출하는 역할을 합니다. 모델을 어떻게 뷰에 "전달"하는가에 대한 모든 책임을 지게 됩니다.
출처:위키백과
MVVM 패턴의 구성 요소
모델(Model) : 도메인 모델 또는 데이터 모델 도메인 모델은 행위과 상태를 모두 가지는 추상화 모델입니다. 일반적으로 객체지향의 객체라 이해할 수 있습니다. 데이터 모델은 데이터의 상태에 집중하는 방식으로 데이터 접근 레이어(Data Access Layer, DAL)를 통해 속성으로만 구성되는 객체입니다. 대표적인 예로 ORM의 모델이 됩니다.
뷰(View) : 사용자 화면에 보여지는 구조, 배치, 외관 뷰는 곧 사용자 유저 인터페이스 입니다. 하지만 MVVM 패턴의 뷰는 어떻게 "동작"하느냐가 아니라 어떻게 "보여지느냐"만 담당합니다. 뷰의 동작은 뷰모델에서 처리됩니다.
뷰모델(View Model) : 뷰의 추상화 모델(화면이 없는 뷰) 뷰모델은 "화면이 없는 뷰"입니다. 뷰모델이 뷰가 "동작"하도록 만듭니다. 뷰모델이 뷰를 동작하도록 만들기 위한 메커니즘으로
바인딩
을 사용합니다. 그렇기 때문에 MVVM을 MVB(Model-View-Binder)라고도 합니다.
MVVM 고찰
MVVM 구성요소
뷰(View)
MVVM에서 뷰는 오직 어떻게 "보여지느냐"에만 집중해야 합니다. 어떻게 "동작하느냐"는 것은 모두 뷰모델에서 처리되어야 합니다. 이는 뷰는 단위테스트를 자동화 할 수 없기 때문에 중요합니다.
뷰의 동작을 뷰모델에 위임하는 방법은 바인딩
입니다. 바인딩이란 뷰모델의 값이 변경되거나, 바인딩된 뷰의 컨트롤에서 해당 값을 변경했을 때 상호 작용이 일어나는 것을 말합니다. 바인딩을 통해 뷰모델의 값을 변경하는 것으로 뷰의 동작을 제어할 수 있게 됩니다.
이때 중요한 것은 뷰모델이 뷰에 대한 의존성이 없어야 하는데 있을 경우 단위테스트를 진행할 수 없게 되기 때문입니다. 또한 의존성이 발생하면 잘 구현된 뷰모델을 다른 뷰에 적용할 수 없게 됩니다.
뷰모델(View Model)
일반적으로 뷰모델을 MVC의 컨트롤러 정도로 생각하는 경향이 있는데 아닙니다. 뷰모델은 추상화된 뷰
로 보이지 않는 뷰의 완전한 동작을 구현해야 합니다. 하지만 뷰모델은 보여지지 않는 상태로 구성되므로 이를 뷰의 모델(View Model)이라 합니다.
만약 뷰모델이 뷰가 어떻게 "동작하는지"를 달성했다면 뷰모델의 단위테스트를 통해 MVVM 패턴을 적용한 어플리케이션의 뷰의 동작을 단위테스트 할 수 있게 됩니다.
실제로 마이크로소프트에서 제공하는 컨트롤은 뷰모델에 해당하는 객체를 통해 단위테스트를 수행하고 있습니다.
모델(Model)
모델은 도메인 모델 및 데이터 모델이 대상이 될 수 있으며 정보를 제공하는 모든 대상이 모델이 될 수 있습니다. 일반적으로 화면과 관련 없는 비즈니스 로직이 모델이 됩니다. 화면 동작에 관련 있는 비즈니스 로직은 뷰모델에 배치될 수 있습니다. 하지만 뷰모델 또한 모델이므로 뷰모델이 뷰모델을 모델로 사용할 수 도 있습니다.
뷰-뷰모델-모델의 의존관계
뷰-뷰모델의 의존 관계
- 뷰는 뷰모델의 속성을 바인딩하여 이용하므로 뷰모델과 의존 관계를 가집니다.
- 뷰모델은 단지 바인딩할 수 있도록 속성을 노출할 뿐이므로 뷰와 의존 관계를 가지지 않습니다.
뷰-모델의 의존 관계
- 뷰는 뷰모델에서 제공하는 모델을 사용하므로 모델과 의존 관계를 가집니다.
- 모델은 어떤 뷰를 사용하는지 알지 못하므로(알 필요가 없으므로) 뷰와 의존 관계를 가지지 않습니다.
뷰모델-모델의 의존 관계
- 뷰모델은 모델을 이용하므로 모델과 의존 관계를 가집니다.
- 모델은 어떤 뷰모델이 모델을 사용하는지 알 필요가 없으므로 뷰모델과 의존 관계를 가지지 않습니다.
뷰모델이 뷰의 요소를 참조할 필요가 있을 경우
이런 경우를 생각해봅시다. 가령 F2 단축키를 눌렀을 때 선택된 요소에 텍스트 박스가 활성화 되어 텍스트를 입력할 수 있어야 하며 입력이 완료되면 입력된 값이 선택된 요소에 반영되어야 한다고 가정해 봅시다. 이는 뷰모델의 바인딩된 속성에 따라 뷰에서 적절히 텍스트 박스를 보이게 하고 관련처리를 진행할 수 있지만 뷰모델이 뷰의 텍스트 박스에 접근할 수만 있다면 좀 더 간단한 로직으로 로직이 구성될 수 도 있습니다. 이처럼 다양한 이유로 뷰모델이 뷰의 요소에 접근해야 하는 이유가 있습니다. 이때 의존성을 해치지 않으면서 뷰모델이 뷰의 요소에 접근하는 방법은 객체지향 설계 SOLID원칙 중 의존관계 역전 원칙을 적용 하는 것입니다. 이는 MVVM 패턴처럼 각 구성요소가 명확히 구분된 의존 관계를 역전할 수 있게 합니다.
뷰에서 제공하는 기능을 IView
인터페이스로 노출하고 뷰모델은 뷰가 아닌 IView
를 참조하는 방식입니다. 뷰의 구성요소 또한 이렇게 인터페이스로 뷰 모델에 노출할 수 있고 인터페이스로 추상화 및 캡슐화 되므로 뷰모델이 뷰를 직접 참조하지 않아도 뷰의 요소에 접근할 수 있게 됩니다.
정리
간략히 MVVM 패턴에 대해 정리해 보았습니다. MVVM 뿐만 아니라 MVU등 최신 트랜드에 맞는 다양한 아키텍쳐 패턴이 있으니 두루 살펴보면 좋을 것 같습니다.