Software Engineering

MVC Pattern의 본질, GUI, 관심사의 분리, 파생된 아키텍처 패턴 알아보기

남희정 2023. 10. 20. 16:06

이번에 리액트 기초 공부 시작을 위해 수강하게 된 강의에서 MVC패턴을 사용하여 코드를 짜게 되었다. MVC패턴이 무엇인지, 다른 디자인 패턴의 종류도 궁금했고 본질이 궁금하여 알아보게 되었다.


History of MVC 

1979년 MVC의 탄생

1979년, Xerox Parc(Palo Alto Research Center) 연구원들은 현재 우리가 누리고 있는 IT 기술의 여러 원형을 개발, 연구 중이었다. 그 중 TrygveReenskaug 트라이브 린스케이지는 다이나북(Dynabook) 팀에서 일하게 되었다.

 

다이나북은 최초의 태블릿 PC로, 전문 지식의 여부나 남녀노소에 상관없이 모두가 직관적으로 사용할 수 있어야한다는 철학을 내세우고 있었으며 프로그래머들이 쓸 수 있는 CLI가 아닌 일반 사람들의 관점을 위해 최초의 GUI Graphic User Interface를 처음 시도하고 있었다. 트라이브 린스케이지는 GUI개발 중 한 가지 사실을 깨닫게 된다. 

MVC IDEA

저는 1978년 여름부터 1979년 여름까지 제록스에서 방문 연구원으로서 매우 행복하고 고무적인 한 해를 보냈습니다.
그곳은 유저가 관심을 갖는 모든 데이터를 담을 수 있는 휴대용 컴퓨터인 다이나북에 대한 앨런 케이의 비전에 전념했습니다. 매우 중요한 것은 유저가 데이터를 조작하는 데 사용하는 프로그램이 포함되어 있다는 점입니다.
유저는 프로그램을 이해하고 작성할 수 있어야 하며, 이를 통해 컴퓨터에 대한 우위를 점할 수 있어야 합니다.

MVC Pattern은 이런 배경을 통해 읽어야 합니다. 제록스의 모든 연구는 유저를 지원하기 위해 수행되었습니다.
1978년, 제록스에서 최초로 SmallTalk로 MVC를 구현하고 최초의 MVC Idea 를 작성했습니다. 

... (중략) ...
MVC의 본질적인 목적은 인간(유저)의 멘탈 모델과 컴퓨터에 존재하는 디지털 모델 사이의 격차를 해소하는 것입니다. 이상적인 MVC 솔루션은 사용자가 도메인 정보를 직접 보고 조작하는 듯한 착각을 일으킬 수 있도록 지원합니다.

 

비즈니스 로직과 시각적인 유저 인터페이스, 둘을 연결해주는 부분을 코드 안에서 분리하고 역할을 부여해주어야 한다는 생각을 하게 된다.

당시 애플의 CEO였던 스티브 잡스는 이 제록스의 연구소를 방문해서 GUI를 처음 보고 제록스랑 기술적 제휴를 맺고 애플 컴퓨터 2에 도입했다.

MVC ST-80

1988년 Smalltalk-80 

스몰톡을 통해 MVC 아키텍처를 처음 구현했다. Model과 View의 직접적 결합이 있었다. 스몰토크로 디자인 패턴이 당대의 객체지향 개발론 전문가들에게서 언급되고 공유된다. GoF의 디자인 패턴 저술도 이즈음에 시작된다.

 

JSP 모델 1

JSP Model

HTML + JAVA의 형태, 동적 웹페이지를 생성하는 언어.

로직 + 출력 코드가 한 페이지에 삽입되어 처리된다. (뷰 템플릿에서 로직까지 다 처리)

코딩은 쉬우나 유지보수가 어려웠다.

 

JSP 2 모델

JSP Model 2

MVC 패턴을 웹에 적용하기 시작한다.

비즈니스(Model) / 출력(View) 로직이 분리된다.

유지 보수가 용이해졌다. (모델 1과 2의 차이)

뷰, 로직에 대한 분리

 

Apple Cocoa MVC Pattern

CoCoa MVC(Apple MVC) - 현대식 MVC패턴

모델과 뷰의 완전한 분리, 현재 개발자들에게 가장 친숙한 MVC 패턴.

MVC Model-View-Controller

사용자 인터페이스, 데이터 및 제어 로직을 구현하는 데 일반적으로 사용되는 소프트웨어 설계 패턴Software Architecture Pattern이다. 이 패턴은 소프트웨어의 비즈니스 로직과 디스플레이의 분리를 강조한다. 이런 '관심사 분리'는 더 나은 분업과 향상된 유지보수성을 제공한다. 

MVVM(Model-View-ViewModel), MVP(Model, View, Presenter), MVW(Model, View, Whatever)와 같은 다른 디자인 패턴도 MVC에 기반한다. 이외에도 여러 파생 패턴을 갖고 있다. 

 

MVC 패턴 흐름

1️⃣ 클라이언트는 필요한 기능을 컨트롤러에 요청

2️⃣ 컨트롤러는 알맞은 모델에게 비즈니스 수행을 맡김

3️⃣ 알맞은 뷰 선택

4️⃣ 결과 화면 출력

The three parts of the MVC

MVC Pattern example

1️⃣ Model

데이터와 비즈니스 로직을 관리하는 역할

Model은 애플리케이 션에 포함되어 하는 데이터를 정의한다. 이 데이터의 상태가 변경되면 Model은 일반적으로 View(필요에 따라 디스플레이가 변경될 수 있도록)와 Controller(업데이트된 View를 제어하기 위해 다른 로직이 필요한 경우)에 알림을 보낸다.

 

− DataBase, 초기화된 상수나 값, 변수 등을 뜻한다.

− 사용자가 편집하길 원하는 모든 데이터를 가지고 있어야 한다.

View나 컨트롤러에 대해 어떤 정보도 알지 말아야 한다.

− 변경이 일어나면, 변경 통지에 대한 처리 방법을 구현해야 한다.

2️⃣ VIew

레이아웃과 디스플레이를 처리하는 역할

애플리케이션의 데이터가 표시되는 방식을 정의한다. 쇼핑 목록 앱에서 View는 사용자에게 목록이 표시되는 방식을 정의하고 Model로부터 표시할 데이터를 수신하여 화면에 표시한다. 사용자가 화면에 표시된 내용을 변경하게 되면 Model에게 전달하여 Model을 변경해야 한다.

 

− 사용자에게 보여지는 부분, 즉 유저 인터페이스(User Interface)를 의미한다.

− 여러 개의 View가 존재할 수 있다.

Model에게 전달받은 데이터를 별도로 저장하지 않아야 한다. 

Model이나 컨트롤러와 같이 다른 구성 요소들을 몰라야 된다.

변경이 일어나면 변경통지에 대한 처리방법을 구현해야만 한다.

3️⃣ Controller

명령을 Model 및 View 부분으로 라우팅하는 역할

Controller에는 애플리케이션 사용자의 입력에 대한 응답으로 Model 혹은 View를 업데이트 하는 로직이 포함되어 있다.

Model이나 View는 서로의 존재를 모르고 있다. 변경 사항을 외부로 알리고 수신하는 방법만 있다. Controller는 이를 중재하기 위한 컴포넌트이기에 둘을 알고 있으며 변경 내용을 통지 받았을 때 각 구성 요소에게 통지한다. 사용자가 애플리케이션을 조작하여 발생하는 변경 이벤트들을 처리하는 역할을 수행한다.

 

예를 들어 쇼핑 목록에는 항목을 추가, 삭제하는 입력 양식과 버튼이 있을 수 있다. 이런 작업을 수행하려면 Model을 업데이트해야 하므로 입력이 Controller로 전송되고, Controller는 Model을 적절히 조작한 다음 업데이트된 데이터를 View로 보낸다.

품목 순서를 알파벳순으로 변경하거나 최저가 에서 최고가로 변경하는 등 다른 형식으로 데이터를 표시하도록 View를 업데이트 할 때엔 Model을 업데이트할 필요 없이 직접 처리할 수 있다.

 

Model이나 View에 대해 알고 있어야 한다.

Model이나 View의 변경을 모니터링 해야 한다.

 

Why MVC?

✔️ 도메인(구성요소)의 재사용

✔️ 확장성 증가

✔️ 중복 코딩 제거

✔️ 각 요소들에 집중

 

결국 가리키고 있는 본질은 관심사의 분리(Separation of Concerns)이다. 이 본질이 흐려질 경우 개선해나가는 것이다. 

MVC의 한계 ?

Massive View Controller

MVC를 Massive View Controller라고 말하는 데 MVC에겐 책임이 없다.

MVC is not to blame for your Massive View Controllers..!

 

복잡한 대규모 프로그램의 경우 다수의 뷰와 모델이 컨트롤러를 통해 연결되기 때문에 컨트롤러가 불필요하게 커지는 현상이 발생한다. 이러한 이유로 현대에 많이들 들어본 MVP, MVVM, Flux, Redux 등을 생각해볼 수 있다. 그들은 무엇인지 간단히 알아보자.

 

MVP Pattern

MVP Model-View-Presenter

MVC에서 파생된, Model과 View간의 의존성이 없는 아키텍처 패턴

View와 Presenter가 1:1 관계라 의존성이 커진다. 오직 Presenter를 통해 상태나 변화를 알려준다. 

하지만 여전히 View와 Presenter의 의존성이 커지고 대신 Presenter가 복잡해지는 문제는 여전히 남아있다.

Vue.js의 MVVM 패턴

MVVM Model-View-ViewModel

MVC에서 파생된 Model과 View간의 의존성뿐만 아니라 Controller와 View간의 의존성도 고려하여 각 구성요소가 독립적으로 작성되고 테스트될 수 있도록 설계된 아키텍처 패턴.

M-V사이의 의존성이 없고 V-VM이 1:1관계가 아니라 독립적이다.

Vue.js가 MVVM 패턴을 이용한다. 이중 VM(ViewModel)에 집중한 프레임워크이다.

ViewModel을 통해 Two-way Data Binding을 가능하게 한다.

컴포넌트 간 통신을 기본으로 One-way Data Flow로 한다.

 

구성요소

Model : 사용되는 데이터를 다루는 역할. 비즈니스 로직이 포함

View: 말 그대로 보이는 것, UI를 다루는 역할. 비즈니스 로직이 아닌 UI로직(애니메이션)을 포함

ViewModel: 뷰만을 위한 모델로 뷰가 사용하는 메서드, 필드를 갖고 View에 상태 변화 등을 알리며 뷰가 사용할 수 있도록 데이터를 바인딩한다.

 

ViewModel과 View의 독립을 이룰 수 있었던 이유?

Command 패턴과 Data Binding을 통해 의존을 제거했다. Command 패턴은 객체의 메서드를 클래스로 캡슐화하는 패턴으로 A 객체의 메서드를 B가 사용할 경우 A를 참조하는 의존성을 제거한다.

(인터페이스를 통한 필수 구현 요소 정의 => 이를 구현한 기능 분리된 클래스, 생성자로 객체를 받음 => 객체 구현 => 사용)

뷰에서 필요한 메서드, 필드 등을 모듈화하여 독립적으로 구현할 수 있도록 한다.

Data Binding은 말그대로 View에서 사용할 데이터 및 뷰모델의 기능 등을 결합해주는 것이다.

 

순서

ACTION --> V(action 전달)-> VM(데이터 요청, 데이터 변경 요청)-> M(응답)-> VM(Data Binding)-> V

 

 

Flux Pattern (1)
Flux Pattern (2)

Flux 

페이스북에서 만든어낸 패턴! 데이터가 한 방향으로만 흐르도록 했다. One-way Data Binding

 

구성요소

Action: 애플리케이션에서 일어나는 이벤트를 나타내는 객체, Action Creator 메서드는 새로 발생한 Action의 type과 새로운 데이터(payload)를 묶어 Dispatcher에게 전달한다.

Dispatcher: Action을 받아서 Store에 전달하는 역할을 한다, 모든 데이터의 흐름을 관리하는 중앙 허브. Store의 데이터를 조작하는 것은 오직 Dispatcher만 가능하다.

Store: 애플리케이션의 모든 상태와 로직을 가지고 있다. Store의 state 변경이 완료되면 변경된 상태를 View에 전달한다.

View: Flux의 View는 MVC의 View와는 달리 Store에서 데이터를 가져오는 한편 데이터를 자식 View로 전달하기도 하는 일종의 View-Controller로 보아야 한다. 리액트의 컴포넌트라고 생각하면 된다!

 

그림(1)이 Flux 프로그래머를 위한 첫 번째 멘탈 모델이 된다. Action이 발생하면 Dispatcher에서 받아와 해석한 후 Store에서 저장된 정보에 변경을 가하고, 그 결과로 View로 다시 전달되도록 한다.

(2)의 흐름은 웹에서 사용자가 View를 통해 클릭 액션을 발생시키는 상황이다. 어디서든 Action 발생시 Dispatcher를 통해 단방향으로 흘러간다. 특이한 점은 View가 언제나 보여주는 역할만 하는게 아니고, Controller-View라는 존재가 있을 수 있는데 이는 상위에서 하위 View들에게 상태나 Dispatcher 등을 제공하기 위해 하위 View를 감싸는 형태로 존재한다.

 

Redux Pattern
Redux의 동작 원리

Redux

Redux는 Flux의 아이디어를 구현하지만 완전히 다른 방식으로 구현하는 라이브러리이다. Flux 패턴처럼 단방향으로 흐르기 때문에 데이터의 흐름을 예측하기 쉽다. 그래서 관리하기도 훨씬 쉽다. 특히 함수형 프로그래밍을 따르기 때문에 데이터가 불변하여 예측하기도 쉽고 이전 상태로 되돌리기도 쉽다.

 

Redux의 모든 변경 사항은 Reducers라는 순수 함수를 통해 이루어진다. 이는 Flux패턴에는 없는 고유한 개념으로 현재 State와 Action을 인수로 전달받아 'Stores'에 접근하고 전달받은 Action을 참고하려 새로운 State를 만들어 반환한다.

State에 어떠한 변화가 필요할 때 Action을 발생시킴으로써 Reducer에 전달한다.

 

동작

Redux에서 state를 관리하는 작업의 흐름

1. 사용자가 UI를 통해 컴포넌트 내에 존재하는 이벤트를 호출한다.

2. 이벤트와 연결된 액션 생성 함수(Action Creator)가 호출된다.

3. 액션 생성 함수에서 생성된 Action이 호출된다.

4. 호출된 Action이 Reducer로 전달(Dispatch)된다.

5. Reducer에서 Dispatch 된 Action에 따라 state 값을 변경한다.

6. 변경된 state가 렌더링되어 UI에 표시된다.

 

조건

1. 1 애플리케이션 1 Store => 서버로부터 가져온 State의 직렬화Serialization를 위해

2. State는 readonly. 변화를 위해선 오직 Action을 전달하기

3. State의 변화를 일으키는 Reducer는 순수 함수로 작성하기

 

 

 

아키텍처 패턴을 알게 되어 이전에 ???했던 Vue의 양방향, React의 단방향을 이해하게 되었다. 심지어 MVC가 GUI때문에 생긴 패턴이라는 것은 굉장히 흥미로웠다. MVC패턴을 클라이언트에 적용할 수 있는 케이스를 더 공부해서 예제로도 포스팅해보고싶다. 단순히 Massive하다고 하기 보다 실질적으로 로직을 분리하는 관점으로 Function, Class를 분리하는 것부터 전체 설계까지 관심사를 분리하는 최초의 개념이다보니.. 알수록 어려운 거 같기도 하고 공부할 수 있는 부분이 노다지여서 머릿속에서 정리할 시간도 꽤 걸렸다. 특히 코드를 바라보는 관점으로 자연스레 적용하기 위해선 시간이 좀 걸리지 않을까 싶다.


[MVC]

[MVC, MVP, MVVM, MVI]

[MVC(Model, View, Controller) Pattern]

[MVC is not to blame for your Massive View Controllers]

[MVC 창시자가 말하는, MVC의 본질]

[[아키텍처 패턴] MVC 패턴이란?]

[[Architecture] Layered Architecture(feat. MVC 패턴)]

[너의 MVC는 나의 MVC와 다르다]

[우아한 테크 -MVC 패턴 리뷰- [레이어, MVC 패턴, 5레이어]]

[MVC vs Flux vs Redux ]

[Web: React Flux 패턴]

[[디자인패턴] MVC, MVP, MVVM 비교]

[VUE의 MVVM 패턴 이해]

[React Flux 패턴 알아보기]

[Redux 개요]