본문 바로가기

프론트엔드

[프론트엔드] 디자인 패턴 (MVC, MVP, MVVM)

디자인 패턴, 혹은 아키텍쳐

프론트엔드의 코드를 살펴보면 충분히 복잡하다. 무작정 페이지 정도만을 구분하고 UI 로직과 비지니스 로직을 혼합하여 코딩을 했던 경험이 있는데, 차후에 수정 사항이 생겼을 때 본인이 짠 코드임에도 불구하고 뒤섞여 있는 코드를 다 살피느라 인지적 부담이 크게 느껴졌고 소요되는 시간이 꽤 아깝게 느껴졌다. 여기에 협업이 추가된다면 더더욱 비효율성이 문제가 된다. 즉, 체계적이지 않은 코드는 유지 보수에 드는 비용 증가시킨다. 이러한 불편함을 해소하고 개발의 효율을 증진하기 위해 지속적으로 관리가 잘 되는 코드에 대한 수요는 항상 있어왔다. 이 수요를 충족시키기 위한 방안으로 코드에도 체계를 적용해 비슷한 것들 끼리 분류하여 잘 설계한 일종의 패턴인 아키텍쳐, 즉 디자인 패턴이 제시되었다.

 

디자인 패턴은 코드의 중복을 피하고 코드간의 결합도를 낮추는 것을 목표로 한다. 앞으로 소개할 보편적으로 사용되는 3가지의 패턴은 코드에 체계를 부여하는데 효과적이다. 이 3가지 패턴은 공통적으로 좋은 구조를 만드는 것은 좋은 분류를 하는 것이라는 생각을 기반으로 하고 있다. 코드의 역할을 기준으로 화면의 버튼 등을 나타내는 UI 로직과 통신을 통해 데이터 처리를 담당하는 비지니스 로직이 분류의 대상이 된다.

 

MVC: Model - View - Controller

MVC 패턴은 가장 먼저 제시된 패턴으로 아직까지도 가장 보편적으로 사용되는 패턴 중 하나이다. UI로직과 비지니스 로직을 분리하고 역할을 부여하는 방식으로 구조를 구성한다. MVC 패턴은 크게 View, Model, Controller의 3가지 영역으로 코드를 분류한다.

  • View
    • 사용자에게 보이는 부분, 화면에 데이터를 표시하고, 사용자와의 인터랙션을 담당한다.
    • Ex) 웹에서는 HTML, CSS로 이루어진 부분
  • Model
    • 어플리케이션에서 사용되는 데이터, 데이터를 저장, 가공하는 부분으로 서버와의 통신도 model 부분에 포함된다.
    • Ex) 서버의 API로부터 받는 데이터, 서버에 있는 DB, 객체
  • Controller
    • View와 model을 연결하는 역할을 한다.
    • 스크롤이나 버튼 터치 등의 사용자의 action(input)을 받아서 처리한다.

MVC 패턴이 작동하는 방식은 아래와 같다.

  1. 사용자의 action이 controller에 들어온다.
  2. controller가 action을 확인한 이후 model 업데이트하여 데이터를 가져온다.
  3. controller가 model을 나타내줄 view 선택한다. (이 때 controller에 대응하는 view는 한개가 아니어도 되며 n개 중에 하나를 선택하게 되는 것이다.)
  4. 선택된 view가 model의 데이터를 이용해 사용자에게 화면을 보여준다.

먼저 MVC 아키텍처를 사용했을 때의 장점으로는, 지금까지 나온 디자인 패턴 중에선 단순한 편에 속한다는 것이다. 그러므로 가장 보편적으로 사용되는 패턴 중 하나이다. 또한, view와 controller가 n:1 대응이므로 여러가지 뷰를 모델에 빌드할 수 있다. UI 로직과 비지니스 로직이 분리되어 있으므로 각각에 집중하여 개발을 진행하고 서로와 상관 없이 테스트를 할 수 있으며 비지니스 로직을 객체지향적 방법으로 구성할 수 있다.

하지만, 단점 역시 명확한데, 구조상 controller는 model과 view의 역할을 제외한 모든 것을 담당해야 해서 앱의 실행 흐름이 오히려 복잡해질 수 있다. 더불어 여전히 분류를 한다고 했지만 view와 model 사이의 의존성이 높은 편이라 뷰와 모델이 양방향 소통을 해야하는 경우 복잡도가 많이 올라가게 되어 컨트롤러가 비대해진다. 그리고 변경사항이 view와 model에 같이 적용되어야하는 경우에는 변경 비용이 오히려 두배로 늘어나면서 비효율적인 면이 있다.

 

MVP: Model - View - Presenter

MVP 패턴은 MVC 패턴의 높은 view와 model 간의 의존성을 낮추기 위해 제시되게 되었다. MVP 패턴에서 바뀐 점은 controller가 view에 포함되고 presenter 영역이 따로 생겼다는 것이다.

  • View
    • controller의 역할이었던 사용자의 action을 받는 것을 view에서 담당한다.
    • MVC 패턴과 동일하게 UI 로직이 포함된다.
  • Model
    • 어플리케이션에서 사용되는 데이터, 데이터를 저장, 가공한다.
  • Presenter
    • view와 model을 연결해주는 다리 역할이다. 
    • view에서 요청한 정보로 model을 가공해 view에 전달한다.view에게는 input으로 무엇을 할지 output을 어떤 것을 내보낼 건지에 대한 권한을 주지 않고 다 presenter 단계에서 처리한다.
    • controller와 다르게 화면(UI)와 어떠한 관련도 가지지 않으며 view 단계에서 action이후 어떻게 화면이 보여졌는 지에 관여하지 않는다.

MVP 패턴이 작동하는 방식은 아래와 같다.

  1. action이 view를 통해 들어온다.
  2. view가 데이터를 presenter에 요청한다.
  3. presenter는 model에 데이터 요청한다.
  4. model이 데이터를 응답한다.
  5. presenter가 view로 응답한다.
  6. view는 presenter의 응답을 활용해 화면에 보여준다.

MVP 패턴의 장점으로는 view와 model이 반드시 presenter을 통해야만 하게 함으로써 view와 model이 직접적으로 소통하는 것을 막아 view와 model 사이의 의존성을 해결했다는 점에 있다. 그리고 presenter의 코드는 재사용성이 높아 효율적이다.

반면, MVP 패턴의 단점은 view와 model의 의존성을 낮추기 위해 사용된 presenter가 view 굉장히 높은 의존성을 가진다는 점이다. view에서 받아들인 모든 input을 presenter에서 처리해주어야 하기 때문의 view의 개수에 비례해 presenter가 필요한데, 이는 또 다시 코드의 복잡성으로 이어진다.

 

MVVM: Model - View - View Model

MVVM 패턴은 MVP 패턴의 단점인 view와 presenter의 의존성을 낮추는 방향으로 구성되어 있다. MVVM에서는 View Model이라는 영역이 존재한다.

  • Model
  • View
  • View Model
    • view를 위해 만든 model로 view를 나타내기 위한 데이터 처리를 한다.
    • presenter와 차이점으로는, view model은 view에 어떠한 영향력도 끼치지 않다는 점이다. 단지 view를 위한 데이터를 처리할 뿐이라고 생각하면 된다.

MVVM 패턴이 작동하는 방식은 아래와 같다.

  1. 사용자의 action이 view를 통해 들어온다.
  2. view는 command 패턴으로 view model에 action 전달한다.
  3. view model이 model에 데이터 요청한다.
  4. model이 view model로 데이터를 응답한다.
  5. view model은 응답 받은 데이터를 필요한 형태로 가공해서 저장한다.
  6. view는 view model을 지켜보면서 알아서 데이터를 가져와 ui에 반영해준다. 이때 view는 view model과 data binding(두개의 데이터 소스를 연결하고 동기화 상태를 유지 시킴)하여 화면을 나타낸다.

MVVM 패턴의 장점으로는 view와 model 사이의 의존성이 없다는 것이다. 더불어 command 패턴과 data binding 기법을 통해 view와 view model 간의 의존성 역시 없다. 따라서 역할이 명확하게 분리됨에 따라 높은 유지 보수성을 가진다. 여러가지 view에서 하나의 view model을 사용할 수 있다는 점에서 역시 효율성이 올라간다. 또한, view를 추상화 함으로써 비지니스 로직 뒤의 코드가 간결해질 수 있다.

하지만, 꽤 치명적인 단점으로는 view model을 구성하는 것이 어렵다는 것에 있다. 또, 간단한 앱/웹을 만드는데 구조를 심하게 복잡하게 만들 가능성이 있다. 그리고 model과 view model이 데이터를 이중으로 사용하고 있어 메모리 소모양이 꽤 크다는 단점을 가진다.

 

Recently,

현재는 앱/웹의 개발을 할 때 view를 페이지 단위가 아니라 component 단위로 나누어서 개발하는 추세이고, 이로 인해 view는 컴포넌트를 tree구조로 복잡하게 구성되어 있는 경우가 많다. 더불어 하위 컴포넌트에 값을 전달하기 위해 중간 레벨의 컴포넌트들이 모두 props를 가지고 있어야 한다는 props drilling problem이 발생한다. 이에 따라 위에 소개한 3가지 아키텍처의 구조에서 벗어난 FLUX 패턴, 이를 이용한 Redux, Observer-Observable pattern, MVI 등의 다양한 패턴이 나왔다.

현대 프론트엔드 아키텍쳐의 방향은 view와 model의 분리성은 가져가되 props drilling problem은 막는 형태로 계속 진화해 나가고 있다. 완벽한 단 하나의 아키텍쳐는 존재하지 않고 여러 디자인 패턴의 장단점과 개발하고자 하는 서비스의 특성을 고려하여 적절하게, 그리고 유연성 있게 적용하는 것이 중요할 것 같다.

 

참고자료

https://velog.io/@eddy_song/mvc#mvc의-본질-관심사의-분리

https://medium.com/@shinbaek89/프론트엔드-아키텍처-business-logic의-분리-adc10ae881ab

https://velog.io/@teo/프론트엔드에서-MV-아키텍쳐란-무엇인가요

https://beomy.tistory.com/43

https://devowen.com/457