MVVM은 Model View ViewModel의 약자입니다.

구글에서는 MVP를 메인으로 정의하는 Architecture를 소개하고, Support library에서는 이를 사용 중입니다.

그리고 iOS에서는 MVVM을 많이 다루고 있습니다.

이러한 Architecture

  • View/Model 간의 코드 분리
  • 테스트 가능한 코드 작성

이러한 Architecture 적용으로 얻는 이득은 바로 안정적인 서비스 개발 및 유지 보수가 빠른 코드의 추구입니다.

저는 아직 MVVM을 다루고 있지는 않습니다. MVVM은 저에게는 많이 어렵게 느껴집니다.

아직 적절한 예제도 찾지 못했고요.

그래서 오늘은 MVVM을 어떤 식으로 접근하는 게 좋은 방법인지를 MVP를 통해 정리해보려고 합니다.

꼭 이렇게 해야 한다는 이유는 없지만, 제가 생각하고 있는 개념에 대한 정리 겸으로 MVVM에 대해서 정의해보려고 합니다.


MVVM

MVVM은 Model View ViewModel을 정의하는 것입니다.

MVP랑 유사합니다. View와 Model 사이에 Presenter가 있는 대신 ViewModel이 존재합니다.

MVVM

이러한 ViewModel을 알기 전에 저는 MVP에 대해서 좀 더 알면 좋을 것 같아서 MVP의 단점을 먼저 정리해봤습니다.


MVP의 문제점?

View에서 비즈니스 로직을 분리하는 부분은 성공적입니다.

모델 역시 분할되어 있으니 적용하기 쉽습니다.

하지만 1:1 관계 유지 덕에 몇 가지 단점이 생깁니다.

  • 중복 코드 발생
  • View에 대한 종속성이 강해집니다.

View에 대한 종속성이 강해지고 1:1 관계이므로 중복 코드는 당연히 생길 수밖에 없습니다.


중복 코드?

예를 들어보겠습니다. 모두 맞는 예는 아니겠지만 다음을 생각해보겠습니다.

로그인과 로그아웃은 어떠한 화면에서도 호출될 수 있습니다. 기획상으로 가능하겠죠.

A/B/C/D의 화면이 있는데 언제든 로그인 만 호출할 수 있습니다.

대부분은 로그인 Activity로 이동시키고 이를 구현하면 됩니다.


반대로 로그아웃입니다.

그냥 단순하게 로그아웃한다고 생각해보죠. 로그아웃 역시 A/B/C/D 화면에서 언제든 접근할 수 있습니다.


MVP에서는?

로그인 로그아웃을 처리하는 비즈니스 로직은 A/B/C/D 화면에 종속적인 Presenter 4개에서 모두 호출하게 됩니다. 모델에서 실제 로그인/로그아웃 처리 로직이 있는 부분을 가져다가 사용하게 되겠죠.


여기서부터 공통 코드가 발생합니다.


공통 코드?

MVP에서 공통 코드는 어떻게 해결하는게 좋을까요?

  • Presenter도 상속을 받아서 공통 코드를 해결
  • 별도의 공통 로직을 가지는 새로운 클래스 생성
  • Presenter 분리?

위와 같은 공통 코드를 관리할 수는 있습니다.


MVVM은 View Model 분리의 시작

제가 바로 위에 Presenter 분리라고 적었습니다.

Presenter를 분리하면 MVVM이 됩니다.

View에 대한 모델을 분리하였기 때문에 ViewModel입니다.


제가 생각하는 ViewModel은 View에 대한 모델 분리가 있어야 한다고 생각합니다.

다시 말해 View에서 사용하는 중복적인 Presenter의 코드가 발생하면 이를 ViewModel 하나로 분리해주는 게 가장 이상적이라는 말이 됩니다.

하지만 그간 보았던 MVVM의 예제 코드들은 MVVM이라고 할 수 없다고 생각됩니다.


kickstarter 코드는 MVVM 일까?

kickstarter에서 공개한 Android-oss 코드입니다.

MVVM을 구현했다면서 보았던 코드인데 일단 다음의 조건을 만족합니다.

  • 코드 종속성을 제거(ReactiveX을 이용해서 이를 해결)

MVVM의 기본 조건은 종속성을 제거하고, View에 대한 모델을 정의해야 합니다.

종속성을 제거하기 위해서는 ReactiveX/Data Binding 등을 이용하는 것일 뿐입니다.

그래서 MVVM은

  • 종속성을 제거해야 함
  • View에 대한 Model을 분리해야 함

이라는 가장 기본적인 2가지 규칙을 가지는 경우에만 저는 ViewModel이라고 정의할 수 있다고 봅니다.

하지만 kickstarter의 경우는 MVP의 개념인 1:1 규칙을 따르고 있습니다.

왜 1:1 관계이냐면 아래와 같은 코드 때문이죠.

하나의 Activity/Fragment에서는 아래와 같은 코드를 가지고 있습니다.

@RequiresActivityViewModel(ActivityFeedViewModel.ViewModel.class)
public final class ActivityFeedActivity extends BaseActivity<ActivityFeedViewModel.ViewModel> {
}

@RequiresFragmentViewModel(DiscoveryFragmentViewModel.class)
public final class DiscoveryFragment extends BaseFragment<DiscoveryFragmentViewModel> {
}

음? 왜 1:1이지?

그런데 생각해보면 모바일 개발에서 얼마나 많은 중복 코드가 생기겠어요.

로그인/로그아웃을 예로 들었지만 생각해보면 아래와 같이 처리합니다.

  • 로그인 페이지로 이동하여 로그인 처리
  • 로그아웃 페이지로 이동하여 로그아웃 처리

위와 같은 코드가 더 많습니다.

그럼 ViewModel이 정말 필요할까요?를 생각해보게 됩니다.


ViewModel이 정말 필요할까?

저는 No라고 하고 싶습니다.

제가 MVP를 근 1년간 해보니 떠오르는 생각 덕분에 이 글을 정리해보게 되었는데요.

MVP의 기본 개념인 1:1 관계 유지에서 벗어나려면 해결 방법은 MVVM 밖에 없더군요.

한때는 헛소리로 MVW를 해야 한다고 했죠…

여하튼 저는 MVVM의 기본 개념이 없는데 MVVM이라고 할 수 있을까라고 생각해봅니다.

  • 역사적으로 보면 MVC > MVP > MVVM의 순서입니다.

그리고 좀 더 이쁜 코드를 만들기 위해서는 최소한 View에 대한 Model은 정의해주어야 한다고 생각합니다.

그렇게 해야 다음과 같은 처리가 가능해집니다.

  • View에 대한 종속성을 줄인다.
    • 종속성을 줄이려면 ReactiveX/data-binding 등을 이용할 수 있다
  • View에 대한 Model 정의가 명확해야 한다
    • 이 ViewModel은 언제든 View에서 가져다 쓰기만 하면 되고, 불필요한 경우 해당 ViewModel만 버릴 수 있어야 한다
  • ViewModel에 대한 테스트가 가능해진다.
    • View에 대한 테스트와 완전하게 분리 가능하여 비즈니스 로직이 아닌 각각의 ViewModel 테스트가 가능해진다.

MVVM이라면 최소한 위와 같이 정의가 가능해야 한다고 생각합니다.


MVVM의 ViewModel 이란?

MVVM은 정말 고민을 많이 해야 하는 구조입니다.(MVP도 고민은 많습니다.)

  • ViewModel 분리가 필요할까?
  • 분리했을 때 얻는 이점은?
  • 종속성은?
    • ReactiveX/Data Binding 등을 이용하면 간단하겠죠?
  • 테스트 코드는?
    • 테스트 코드는 유용해야 합니다.

비즈니스 로직 전체를 테스트하는 것이 아닌 하나의 ViewModel에 해당하는 비즈니스 로직의 테스트가 가능합니다. 이것만 하더라도 엄청난 발전이죠.

그냥 내가 원하는 모델 N 개를 만들어두고 이를 필요한 View에 땠다 붙였다 땠다 붙였다 하는 완전한 모듈 형태가 만들어지는 것이라고 생각합니다.

그렇지 않으면 저는 그냥 .. Presenter에다가 ReactiveX 붙였네 정도라고 생각하겠죠.

MVP에 ReactiveX 붙이더라도 코드는 이뻐지고, 종속성은 사라집니다. 하지만 종속성이 사라지더라도 1:1 관계를 벗어나지 못하면 큰 의미는 없어 보입니다.

그래서 Android에서는 이쁜 코드를 발견하지 못했습니다.

그래서 생각해본 거지만 이런 모델을 만들 수 있을지도 잘 모르겠습니다.

정말 예측 가능한 코드 작성이 가능하다면?

아니면 일단 View에 대한 모델을 모두 분리한다면?

이 경우 저는 후자를 선택해보고 싶습니다.

예를 들면 다음과 같을 것 같습니다.

  • LoginViewModel : 로그인만을 하는 모델
  • LogoutViewModel : 로그아웃만을 하는 모델
  • UserInfoViewModel : 사용자 정보만을 가져와 가공한다


마무리

ViewModel에 대한 정의도 MVP처럼 따라 하기를 만들 수 있을지는 모르겠습니다.

우선은 초짜인 제가 MVP를 통해서 MVVM에 대한 생각을 정리해보았습니다.

이게 맞지는 않겠지만 최소한 ViewModel에 대한 정의는 위와 같아야 한다고 생각합니다.

그렇지 않다면 그냥 MVP 하는 것으로 만족하는 게 좋다고 생각합니다.

MVP도 어렵습니다. 어디까지가 View 인지 어디까지가 비즈니스 로직인지 구분하는 부분만 하더라도 고민이 많아집니다.


Tae-hwan

Android, Kotlin .. Create a content development.