저는 todo-list
를 만드는 과제를 하던 중 처음에는 한 파일에 모두 작성하고 모듈화를 진행하는 과정에서 어떤 기준으로 모듈화를 할지 고민하던 중 이미 대중적으로 사용되고 있는 MVC 디자인 패턴과 FLUX를 알게 되었는데 추상적인 개념을 글로써 정리하며 명확하게 하고자 이 글을 쓰게 되었습니다.
우선 MVC패턴이란 프론트엔드 측에서 나온 개념이 아닌 백엔드에서 나온 개념이기에 프론트엔드측에 바로 적용시키기에는 완전히 들어맞지는 않는다는 것을 염두해두자
MVC패턴 자체는 추상적인 개념이기에 각각이 어떤 역할을 하는지 먼저 알 필요가 있다.
Model은 데이터와 관련된 모든 것이라고 할 수 있다.
조금 더 자세히 말하면 데이터 자체, 편집하고자 하는 모든 것, 데이터 상태를 조작하는 행동 등등 데이터와 관련된 모든 것들을 Model에서 관리한다고 볼 수 있다.
View는 화면에 시각적으로 출력하는 것이다.
MVC패턴 자체가 명확한 구분을 위해 나온 패턴이기 때문에 각각의 기능들은 최대한 단순한 작업만 하도록 설계했기 때문에 View의 역할은 화면에 시각적으로 출력하는 것이 전부이다.
Controller는 Model과 View를 연결하는 중개인이다.
MVC 세가지 기능 중 가장 복합적인 역할을 담당하는 기능이다.
Controller는 사용자에게 입력받은 상태에 대한 변경을 Model에게 알리는 역할을 하고
Model에게 전달받은 데이터를 View에게 전달하는 역할을 담당하는 기능이다.
MVC패턴으로 Todo-List의 js파일을 모듈화 하기 전 구분하기 용이하도록 Todo-List의 js파일을 내 생각대로 정리해보았다.
- State : 상태(데이터)
- DOM Nodes : 이벤트핸들러를 바인딩하고 DOM 조작을 위한 DOM 요소노드
- State Function : 상태를 참조하는 기능
- State Change Function : 상태를 조작하는 기능
- Render Function : 시각적인 출력을 담당하는 기능
- Event Handler : 사용자의 요청(이벤트)을 받아 수행하는 기능
아래의 그림은 내 생각을 토대로 구현한 Todo-List의 MVC 모델을 그림으로 표현한 것이다.
위 그림은 내 생각대로 모듈화한 그림이기 때문에 이 그림을 정형화된 MVC패턴으로 받아들이지는 말자.
이처럼 MVC 패턴을 사용하면 Todo-List 같은 간단한 애플리케이션은 모듈화를 좀 더 체계적으로 작성할 수 있다.
Flux패턴이란 MVC의 양방향 데이터 바인딩의 단점을 해결하고자 페이스북에서 고안한 단방향 데이터 바인딩 방식의 디자인 패턴이다.
Flux패턴의 설명을 용이하게 하기 위해 Flux패턴이란 무엇인지 정의를 하고 시작했다.
정의한 내용을 보면 MVC 패턴이 양방향 데이터 바인딩이라는 단점을 가지고 있다고 했는데 어떤 상황에서 이러한 단점이 부각될까?
위의 Todo-List같은 경우는 관리해야 할 Model과 View가 하나인 케이스이기 때문에 흐름도 나름 명확하게 볼 수 있고 복잡해 보이지 않을 수 있다. 하지만 관리해야할 Model이 늘어나고 서로 의존관계를 가지며 보여줘야 할 View도 늘어난다면 어떨까?
일부러 복잡하게 그린 감도 없잖아 있지만 관리해야할 Model과 View가 하나씩만 늘어나도 당장 데이터 흐름을 파악하기가 힘들고 디버깅이 힘들어진다.
대표적인 그림으로는 아래와 같은 그림이 있다.
이러한 문제 때문에 Facebook이 겪었던 가장 큰 문제는 알림버그였다.
Facebook에 로그인 했을 때 메시지 아이콘에 알림이 떠있지만 실제로는 아무 메시지가 없었던 경험이 다들 있었을 것이다.
Facebook은 이러한 문제를 해결하기 위해 버그를 수정하는 과정을 여러번 거쳤지만 업데이트를 하다보면 다시 버그가 발생하는 사이클이 반복되었다.
때문에 Facebook은 이 사이클을 완전히 벗어나고자 MVC패턴이 아닌 단방향 데이터 흐름을 가지는 새로운 디자인 패턴을 만들었는데 이 디자인 패턴이 바로 Flux이다.
당장 위의 그림으로는 어떤 방식으로 단방향 데이터 흐름을 제어하는지 알기 어려우니 참고사이트2에서 소개하는 역할별 소개를 인용하여 설명하도록 하겠다.
액션 생성자는 모든 변경사항과 사용자와의 상호작용이 거쳐가야하는 액션의 생성을 담당하고 있다. 언제든 애플리케이션의 상태를 변경하거나 뷰를 업데이트하고 싶다면 액션을 생성해야만 한다.
당장 Flux 디자인 패턴을 사용해본적 없는 사람이라면 받아들이기 어려울 수 있다, 조금 쉽게 설명하면 사용자는 데이터를 변경하고자 할 때 특정 action을 통해 애플리케이션에게 상호작용을 해야하는데 이 때 모든 action들은 액션 생성자라는 헬퍼 함수에서 관리하여 디스패치로 즉 디스패쳐에게 전달하는 역할을 담당하고 있다.
디스패쳐는 기본적으로 콜백이 등록되어있는 곳이다.
디스패쳐는 액션을 보낼 필요가 있는 모든 스토어를 가지고 있고 액션 생성자로부터 액션이 넘어오면 여러 스토어에 액션을 보낸다.
필자는 모든 스토어를 가지고 있다는 말과 액션을 여러 스토어에게 보내는 부분이 어떻게 이루어지고 어떻게 관리되고 있는지 너무 추상적으로 해석되어 이해하는데에 어려움을 겪었다.
조금 명시적으로 풀어보자면 모든 데이터는 중앙 허브인 dispatcher
를 통해 흐르는데 action
은 dispatcher
에게 액션 생성자 메서드를 제공하는데 대부분의 action
은 view
에서의 사용자 상호작용에서 발생한다.
dispatcher
는 store
를 등록하기 위한 콜백을 실행한 이후에 action
을 모든 store
로 전달한다.
등록된 콜백을 활용해 store
는 관리하고 있는 상태 중 어떤 액션이라도 관련이 있다면 전달해준다.
dispatcher
는 Flux 디자인 패턴에서 가장 중요한 파트이기 때문에 정리하기가 어려우나 역할을 정의하자면 store
간에 의존성을 특정적인 순서로 callback
을 실행하는 과정으로 관리하는 역할을 담당한다.
모든 상태변경은 반드시 스토어에 의해 결정되어야하고 상태변경을 위한 요청을 스토어에 직접 보낼 수는 없다.
즉, 반드시 액션 생성자 > 디스패쳐 파이프라인을 거쳐서 액션을 보내야만 한다.
역할에만 집중한 설명이다보니 이 역시 명시적으로 풀어보자면 store
는 어플리케이션의 상태와 로직을 포함하고 있다.
store
의 역할은 MVC
패턴의 Model
과 유사하지만 store
는 단순히 ORM(Object Relational Mapping)
스타일의 객체 컬랙션을 관리하는 것을 넘어 애플리케이션 내의 개별적인 도메인에서 애플리케이션의 상태를 관리하는 역할을 한다.
컨트롤러 뷰는 store
와 view
사이의 중간관리자 같은 역할이다.
상태가 변경되었을 때 store
가 컨트롤러 뷰에게 알려주면 컨트롤러 뷰는 자신의 아래에 있는 모든 view
에게 새로운 상태를 넘겨준다.
뷰는 애플리케이션 내부에 대해서는 알 필요가 없다.
하지만 받은 데이터를 처리해서 사람들이 이해할 수 있는 포맷으로 어떻게 바꾸는지 알고 있다.
우선 사용자에 의해 action
이 발생했다는 전제에서 데이터 흐름은 시작한다.
action
은 view
에서 사용자와의 상호작용에서 발생한다.action
이 발생하면 action creator
메서드를 dispatcher
에게 제공하고 dispatcher
는 store
를 등록하기 위한 콜백을 실행한 후 action
을 모든 store
에게 전달한다.store
는 관리하고 있는 상태 중 어떤 action
이라도 관련이 있다면 controller-views
에게 전달해준다.store
는 change
이벤트를 controller-views
에게 알려주고 그 결과로 데이터 변화가 일어난다.controller-views
는 이 이벤트를 듣고 있다가 이벤트 핸들러가 있는 store
에서 데이터를 다시 가져온다.controller-views
는 스스로의 setState()
메서드를 호출하고 자식 노드 모두를 다시 렌더링하게 한다.Flux 디자인패턴이 당장 이해하기에 난해할 수 있지만 애플리케이션의 volume
이 커진다고 생각하면 Flux 디자인패턴의 단방향 데이터 흐름이 큰 도움이 될 것이라고 생각한다.
하지만 당장 익숙치 않다면 MVC 패턴을 연습해보며 데이터흐름을 어떻게 제어할 것인지에 대해 고민하는 시간을 가져본다면 Flux를 이해하는 것에 조금 더 도움이 될 것같다.