Vanilla TS로 만든 Flux와 MVC 패턴

김용현·2024년 4월 12일
6
post-thumbnail

0. 학습 배경

왜 Flux와 MVC 패턴을 만들었나요?

왜 React는 Flux 패턴을 선택했을까? MVC 패턴은 프론트엔드 아키텍쳐로는 활용할 수 없을까? 직접 아키텍쳐를 설계해보고 느껴보자!

vanilla Javascript로 클라이언트 화면을 구성하는 것을 네이버 부스트캠프의 과제로 수행해본 경험이 있습니다. 아직 프론트엔드 라이브러리가 어떤 역할인지도 잘 이해하지 못했던 당시의 저는 "아 MVC 패턴이란 것을 옛날에 Django로 서버 만들때 써본적이 있는데, Frontend도 비슷하지 않을까?"란 그 때의 어설픈 생각으로 Frontend 아키텍쳐를 MVC 비스무리한 것(?)으로 만들어보다 큰 좌절을 겪은 경험이 있었습니다.

그 때 큰 벽으로 다가왔던 프론트엔드 아키텍쳐를 좀 더 공부해보니, 굉장히 다양한 구조들이 있음을 배웠습니다. 특히 그 중에서 제가 주력으로 공부하던 React는 유지/보수/확장의 이유로 MVC 패턴에서 Flux 패턴으로 바꾸었다는 점이 굉장히 흥미로웠습니다. 그들의 발표를 보며 옛날 MVC 패턴의 복잡한 구조에 쓰러졌던 경험 때문인지 Flux를 개발한 이유에 크게 납득을 할 수 있었습니다.

하지만, 단순히 영상만을 보고 Flux를 이해했다고 말하기에는 부족한 부분들이 너무 많았습니다. "그래서 dispatcher가 정확하게 어떻게 동작시켜 주는데?", "Action이 어떻게 전달되고 코드를 실행시켜 주는데?"와 같은 아직 풀리지 않은 의문의 응어리들이 남아있었고, 이를 해결하지 않으면 Flux에 대해 이해했다고 말할 수 없다 판단했습니다. 또, MVC 패턴의 설계의 실패에 대한 설욕을 해야겠다는 의지도 이번 학습의 계기가 되었습니다.

이번 학습으로 무엇을 배우려 했나요?

Vanilla TypeScript를 통해 MVC 패턴과 Flux 패턴을 만들어보자!
직접 만든 아키텍쳐를 통해 동일한 화면을 만들어 보며 그 차이점을 느껴보자!

  1. MVC 패턴에서 각 요소를 정의하고 이를 기반으로 설계하자!
  2. Flux 패턴의 동작 방식을 기반으로 각 요소를 설계하자!
  3. 직접 만든 패턴을 활용하여 코드를 만들고, 각 패턴을 만들때의 차이점을 느껴보자!
  4. 원하는 구조를 설계하고 동작하도록 구현하는 경험을 쌓아보자!

1. 개발 목표

간단하지만, 조금은 복잡한 TodoList를 만들어보자

이번 MVC 패턴, Flux 패턴을 통해 만들어본 것은 조금은 복잡한 구성으로 이루어진 Todo List입니다. 각 패턴의 차이는 Model(혹은 Store)과 View(혹은 Component)의 갯수가 많아져, 각 Model과 View 그리고 사용자의 상호작용이 복잡한 구조를 이룰 때 도드라진다고 생각했습니다.

따라서 이번에 개발할 페이지는 3개의 Model과 3개의 View를 가지도록 Todo List를 구성하고 이를 각 패턴으로 구현해볼 것입니다.

최종 개발 화면

TodoList 동작 화면

개발해야 하는 기능과 조건

총 3개의 기능, 3개의 View(Component)와 3개의 Model(Store)

기능1. TodoList에 Todo를 저장하고 삭제하는 기능

  • TodoList에 Todo를 등록하고, 삭제할 수 있다.
  • TodoList를 저장하는 공간을 생성해야 한다.
  • TodoList를 보여주는 화면 생성해야 한다.

기능2. Todo List의 Todo 상태를 바꾸고, 총 Todo의 갯수와 상태별 갯수를 표시하는 기능

  • TodoList의 상태 버튼을 클릭하면 Todo의 상태를 변경할 수 있다.
  • TodoList의 각 상태별 갯수를 저장하는 공간을 기능 1과는 별도로 생성해야 한다.
    • 기능 1의 Model으로도 해결할 수 있는 부분이지만, 서로 연관 관계가 있는 Model 환경을 구성하기 위해 별도의 Model을 추가로 생성
  • TodoList의 각 상태별 갯수를 보여주는 화면을 생성해야 한다.

기능 3. 선택한 Todo의 상세 화면을 보여주고, 조작할 수 있는 기능

  • 기능 1 화면의 각 Todo를 클릭하여, 상세 화면으로 보여줄 Todo로 선정할 수 있다.
  • 상세 화면으로 보여줄 Todo를 저장하는 공간을 생성해야 한다.
  • 선택한 Todo를 상세 화면으로 보여주어야 한다.
  • 상세 화면에서 Todo의 상태를 바꿀 수 있다.
  • 상세 화면에서 Todo를 삭제할 수 있다.
  • 상세 화면의 Todo가 삭제되었거나 선택한 Todo가 없을 경우, 상세 화면은 "todo를 선택해주세요" 글귀를 보여준다.

2. MVC 패턴 개발하기

구현 전 설계 단계

1. 나의 MVC 패턴 정의하기

MVC 패턴을 설계하기에 앞서 Model, View, Controller가 어떤 역할을 수행해야 하는지를 정하자

일전의 과제로 만든 MVC 패턴의 실패 요인은 MVC가 어떤 역할을 수행해야 하는지에 대한 명확한 이해와 정의 없이 막(?) 만들어 각 아키텍쳐의 역할이 불분명했기 때문입니다. 각 역할을 명확하게 만들지 않았기 때문에 아키텍쳐 각각에 작성해야할 코드들이 여러 곳에 산재하게 되고, 그로 인해 코드들의 흐름을 설계하는 도중 놓쳐버렸던 경험이 있던 저는 가장 먼저 각 파트의 역할을 정하기로 결정했습니다.

Model
클라이언트의 View에서 사용하는 데이터를 저장하고 관리

  • View에서 화면을 완성하기 위해선, 그에 따른 데이터들이 필요합니다. 각 Model은 View가 필요한 데이터들을 가지고 있다가, View의 화면을 구성할 때 이를 꺼내 전달하는 역할을 수행합니다.
  • Model은 데이터의 저장과 동시에 데이터를 조작하는 역할을 수행합니다. 사용자의 상호작용 혹은 별도의 이벤트로 인해 데이터를 변경해야 하는 경우, 미리 작성한 메서드를 통해 값을 변경 시킵니다.

View
데이터를 전달 받아 클라이언트의 화면을 그리는 역할

  • View는 Model로 부터 데이터를 전달 받아 사용자들을 위한 화면을 그리는 역할을 수행합니다.
  • 그와 동시에, 사용자와의 상호작용을 하기 위한 이벤트리스너를 화면의 요소에 등록하는 역할도 함께 담당합니다.

Controller
Model과 View를 연결하는 중재자이자, 사용자와의 상호작용에 따라 Model 안의 데이터를 바꾸고 화면을 변경하는 역할을 담당

  • Model과 View를 중간에 연결하여 Model의 데이터를 View에 전달하는 역할을 통해 Model과 View 사이의 직접적인 의존성을 낮춥니다.
  • 사용자의 상호작용에 맞추어 Model의 값을 바꾸고 View의 화면을 새롭게 갱신하는 역할을 수행합니다.

2. MVC 패턴의 구조를 설계하기

MVC의 구조
설계한 MVC의 구조를 도식화한다면 위와 같은 그림이 되게 됩니다.

  • data : Model안의 데이터는 View로 전달되게 됩니다.
  • sends input or event : Controller는 View로부터 사용자의 상호작용과 input 정보를 전달받습니다.
  • updates : Controller는 전달 받은 사용자 상호작용과 input 정보를 바탕으로 Model의 값을 조작하게 됩니다.
  • manipulates : Controller는 Model의 값을 조작한 이후, View를 업데이트 하여 화면을 새로 그리도록 만듭니다.

(이 도식 그림은 React가 비교한 MVC 패턴과 다소 다른 형태로 그려졌습니다. React가 발표한 도식의 경우, Model과 View의 양방향 바인드가 되어있어 서로를 직접 컨트롤 할 수 있는 로직으로 짜여졌으며, 이를 커다란 Controller가 관리하는 패턴으로 보입니다.)

기능 구현

완성된 코드를 보면서 읽으시면 더 이해하기 좋습니다

1. 첫번째 기능을 구현하면서 구조를 구현해보자

기능 구현을 위한 첫번째 MVC

첫번째 기능을 구현하기 위해 아래와 같이 구성요소를 생성했습니다.

  • TodoModel
    • TodoList에 Todo를 저장 및 관리하는 모델
  • TodoView
    • TodoModel에 저장한 TodoList를 화면에 그리는 기능을 제공
    • add todo 버튼과 delete 버튼에 이벤트를 등록하는 기능을 제공
  • TodoController
    • TodoModel에서 저장한 TodoList를 TodoView에 전달
    • TodoView의 버튼 요소에 등록할 이벤트 핸들러를 생성하고, TodoView에 전달
    • 이벤트 핸들러에는, TodoModel 내의 TodoList를 조작하고 이를 기반으로 화면을 새롭게 그리도록 합니다.

위의 MVC의 각 컴포넌트는 최초 설계와 같은 형태를 이루게 되었습니다.

1번 기능의 아키텍쳐

구현 화면

MVC 첫번째 기능 1

2. 두번째 기능을 통해 기능을 확장해보자

Todo의 상태를 변경하는 기능을 추가하기

Todo의 상태를 바꾸는 기능이 추가되어야 했습니다. 이를 위해 다음의 과정을 수행해야 했습니다.

  1. TodoView의 State 버튼에 이벤트 핸들러를 등록하기 위한 bindToggleTodoState 메서드를 작성합니다.
  2. TodoModel에서 Todo의 상태를 바꾸는 toggleTodoState 메서드를 작성합니다.
  3. TodoController에서 toggle 상태를 바꾸고 TodoView를 사용해 화면을 새롭게 그리는 handleToggleTodoState를 생성합니다.

기능 구현을 위한 두번째 MVC

두번째 기능을 구현하기 위한 새로운 MVC 구성요소를 생성했습니다.

  • TodoCounterModel : 화면에 표시할 숫자(상태)를 저장하고 관리하는 모델
  • TodoCounterView : Model에서 저장한 상태를 화면에 표시하는 기능
  • TodoCounterController : TodoCounterModel과 View를 연결하고 최종적으로 렌더링을 실행하는 위치

첫번째 MVC와 두번째 MVC를 연결하기

TodoCounterModel은 생성한 Todo의 갯수와 각 State의 갯수를 저장하고 있습니다. 이때, 1번째 기능을 통해 Todo의 상태를 바꾼다면 TodoCounterModel안에 저장한 데이터를 바꾸어고 동시에 TodoCounter의 화면을 새로 그러야 하기 때문에, 첫번째 MVC와 두번째 MVC를 연결해야 했습니다.

MVC를 연결하기 위해, 첫번째 MVC의 Controller는 두번째 MVC의 Model를 참조하고 결과적으로 아래의 도식과 같은 구조를 이루게 되었습니다.

두번째 기능 아키텍쳐

구현 화면
MVC 두번째 기능

3. 마지막 세번째 기능을 추가해보자

기능 구현을 위한 세번째 MVC

마지막 기능을 구현하기 위한 새로운 MVC 구성요소를 생성했습니다.

  • DetailTodoModel : Detail 칸에 표시할 Todo 상태를 저장할 Model
  • DetailTodoView : Detail Todo를 표시하고, 삭제 토글 버튼을 위치
  • DetailTodoController : Model과 View를 연결하고 화면을 송출, 사용자의 상호작용을 다른 Model, View에 적용

첫번째, 두번째 그리고 세번째 MVC의 연결

세번째 기능은 선택한 Todo를 상세 화면에서 보여주고, 여기서 Todo의 상태를 바꾸거나 삭제 할 수 있습니다. 또 반대로 첫번째 기능에서 Todo를 선택하거나, 해당 Todo의 상태를 변경 및 삭제가 가능합니다.

즉, 첫번째 두번째 MVC가 연결된 것 처럼 세번째 MVC도 각각의 MVC와 연결해주었습니다. 각 Controller는 서로 다른 Model과 View를 참조하도록 구현하였고 결과적으로 아래와 같은 복잡한 데이터 흐름을 가지게 되었습니다.

혼돈과 카오스의 세번째 기능을 추가한 MVC 아키텍쳐 도식

MVC 패턴 개발 경험

개발 간의 경험

세가지 기능을 추가하고 확장해가는 경험을 바탕으로 느낀, 나의 MVC의 문제점

직접 설계한 MVC 패턴을 사용해 기능을 추가하고 확장하며 최종적으로 TodoList를 완성한 경험 끝에, 이 방식을 통해 코드를 만드는 것은 굉장히 비효율적임을 느꼈습니다. 개발 효율성과 개발 경험을 저하시키는 요인은 아래와 같았습니다.

1. Controller의 관심사(책임)가 너무 많아진다.

세 가지의 기능을 추가해가는 과정 속에서, Controller는 점차 많은 기능이 생겨나게 되었습니다. 예를 들어, TodoController의 최초 기능은 TodoView에 TodoModel에 저장된 데이터를 전달하여 화면을 구성하고, TodoView의 버튼 요소가 사용자와 상호작용할 수 있도록 하는 비즈니스 로직을 담당했습니다. 하지만 점차 기능이 더해질 수록 첫번째 기능의 화면과 데이터 뿐만 아니라 두번째, 세번째 기능들의 데이터를 관리하고 화면을 새로 그리는 기능을 추가해야 합니다.

이런 이유들 때문에, 연관된 기능이 더해질 수록 각각의 Controller 안에는 더 많은 Model과 View를 관리하는 코드가 만들어질 것이고 크기가 비대해질 것입니다. 이렇게 Controller가 할일이 많아진다면 다른 개발자들이 코드의 흐름을 읽고 이해하는 것에 너무 큰 소요가 들게 될 것입니다. 또, 코드를 유지보수하는 것에서도 많은 애로사항을 유발하는 요인이 될 것이라는 생각이 들었습니다.

2. 기능을 확장하는 것에 굉장히 비효율 적이다.

앞선 기능들을 추가하면서, 반드시 각각의 MVC를 연결하는(Controller에 연관된 View와 Model을 등록하고 관리하는) 과정이 필요합니다. 만약 계속해서 기능들을 추가한다면 연관된 Controller들마다 새로운 View와 Model을 갱신하는 코드들을 계속해서 만들어 주어야 하고, Controller가 늘어날 수록 드는 수요가 굉장히 커질 것입니다. 제가 만든 MVC 패턴은 확장성 관점에서 볼때, 굉장히 규모가 큰 코드를 만들기에는 적합하지 않은 아키텍쳐였습니다.

3. Flux 패턴 개발하기

구현 전

1. 나의 Flux 패턴과 구성 요소 정의하기

Flux 패턴을 만들기 위해, 각각의 기능들이 어떤 역할을 하는지 정의를 내려보고자 했습니다. 이를 기반으로 구조를 설계할 때 역할을 명확히 하고자 했습니다.

Action
사용자의 상호 작용 혹은 별도의 이벤트로 인해 생겨난 신호. 어떤 종류의 상호 작용인지, 상호 작용에 따른 처리를 하기 위한 데이터를 가지고 있다.

  • Action의 구조 : { type, payload }
    • type : Action의 종류를 의미하며 Store는 Action의 종류에 따라 별도의 동작을 수행한다.
    • payload : Store가 Action에 따라 동작할 때 필요한 데이터를 담고 있다.

dispatcher
사용자의 상호작용 혹은 별도의 이벤트로 인해 발생하는 Action을 전달 받고 이를 연관된 모든 Store에 전달하는 역할

  • dispatcher는 Observer 패턴으로 만들어, Action이 dispatcher에 전달되면 이를 관찰하고 있던 Store는 Action에 따라 동작을 수행토록 만들 계획입니다.
  • register
    • Action을 전달받으며 dispatcher에서 관리할 Store의 실행 코드를 저장합니다.
  • dispatch
    • Component에서 dispatcher에 Action를 전달하고, 관리 중인 Store의 실행 코드에 해당 Action을 전달합니다.

Store
화면을 그리기 위한 View마다 하나의 Store를 배정하고, View에 필요한 데이터를 Store가 관리하도록 만들 예정입니다.

Component
Store로부터 데이터를 전달받아 화면을 그리는 역할(View) 입니다. Component는 화면을 그리는 역할을 담당하고, 사용자의 상호작용을 dispatcher에게 Action의 형태로 전달합니다.

2. Flux 패턴의 구조를 설계하기

Flux 패턴 도식화

앞서 정의한 Flux의 구성 요소들의 관계를 도식화하면 위의 그림과 같이 그려지게 됩니다.

  • 전달 : Action이 Dispatcher에 전달되게 됩니다.
  • Action에 따른 상태 변화 : Store는 Dispatcher에 전달된 Action에 따라 각자의 상태값을 바꾸게 됩니다.
  • State 전달 : Component는 Store로 부터 State(상태값)을 전달받아 화면을 그리게 됩니다.
  • Action 생성 : Component는 사용자의 상호작용의 종류에 따라 각각의 Action을 생성하게 됩니다.

기능 구현

완성된 코드와 함께보시면 이해하기 좋습니다.

0. 설계한 Flux 구조 구현하기

dispatcher
저는 하나의 dispatcher가 모든 Store를 관리하는 구조를 생각했습니다. 만일 Store별로 dispatcher를 따로 만들어야 한다면, Component는 Action을 또 모든 dispatcher에 전달해야 하기 때문입니다.

그렇기 때문에 dispatcher의 경우 Class보다는 dispatch와 regist 기능을 가진 단독 객체로 생성하고 다른 객체들이 호출하여 사용하도록 만들었습니다.

const actionHandlers: Function[] = [];

const dispatcher: Dispatcher = Object.create({
  register: function (callback: Function): void {
    actionHandlers.push(callback);
  },
  dispatch: function (action: Action): void {
    actionHandlers.forEach((actionHandler: Function) => {
      actionHandler(action);
    });
  },
});

Action
Action은 type과 payload의 정보를 가지고 있습니다. Action의 경우 동일한 형태의 코드를 빈번하게 생성하지만, 일일이 type과 payload의 구조를 작성하는 것은 개발 효율성이 떨어지기 때문에 Actions을 생성하는 함수를 만들어 관리했습니다.

Store
"초기값"과 Action마다 내부 값을 변경하는 "actionHandler"를 생성 인자로 전달받는 Class 방식을 통해 여러 Store를 쉽게 생성하도록 만들었습니다.

Store는 Observer 패턴으로 만들어, Store의 데이터에 변화가 발생한다면 Component는 이를 관찰하다 화면을 새로 그리는 코드를 자동으로 실행하도록 코드를 구성했습니다.

class Store<S> {
  private state: { data: S };
  private subscribers: Function[];
  private actionHandler: (action: Action, state: { data: S }) => void;

  constructor(
    state: S,
    actionHandler: (action: Action, state: { data: S }) => void
  ) {
    this.state = { data: state };
    this.subscribers = [];
    this.actionHandler = actionHandler;
    dispatcher.register(this.dispatchRegister.bind(this));
  }

  getState() {
    return this.state.data;
  }

  subscribe(callback: Function) {
    this.subscribers.push(callback);
    const id = this.subscribers.length - 1;
    return () => {
      this.subscribers = this.subscribers.filter((_, index) => index !== id);
    };
  }

  notify() {
    this.subscribers.forEach((subscriber) => {
      subscriber();
    });
  }

Component
Component는 각자의 Store를 관찰하고 있으며, Store에 변화가 발생한다면 render 메서드를 통해 새롭게 화면을 그려줍니다.

내부에 화면을 그릴 DivElement, DivElement내에 그려질 내용, 자신의 Store를 생성 인자로 전달받는 Class 방식을 통해 여러 Component를 쉽게 생성하도록 생성했습니다.

class ViewComponent<S> {
  private viewDiv: HTMLDivElement;
  private store: Store<S>;
  private content: (data: S) => HTMLElement[];

  constructor(
    viewDiv: HTMLDivElement | null,
    store: Store<S>,
    content: (data: S) => HTMLElement[]
  ) {
    if (!viewDiv) throw Error("invalid viewDiv");

    this.viewDiv = viewDiv;
    this.store = store;
    this.content = content;
    this.store.subscribe(this.render.bind(this));

    this.render();
  }

  render() {
    this.viewDiv.innerHTML = "";
    this.viewDiv.append(...this.content(this.store.getState()));
  }
}

1. 첫번째 기능

기능 구현을 위한 첫번째 Flux

위에서 작성한 Flux 구조를 기반으로 첫번째 기능의 Flux 구조를 만들었습니다.

  • todoStore : TodoList를 저장하고 Action에 따라 데이터를 조작하는 객체
  • todoComponent : Todo 화면을 그리고 사용자의 상호작용에 알맞은 Action을 생성하고 dispatch하는 객체

Flux 첫번째 구조

2. 두번째 기능

Todo의 상태를 변경하는 기능을 추가하기

Todo 상태를 바꾸는 기능을 추가하기 위해서 Flux 패턴이 해야할 일은 정말 간단했습니다.

  1. Actions에서 Todo 상태를 바꾸는 Action 타입(Toggle)을 정의하기
  2. TodoStore에 Toggle Action이 들어오면 수행할 ActionHandler 추가하기
  3. TodoComponent의 State 버튼에 Toggle Action을 dispatch하는 이벤트 등록하기

기능 구현을 위한 두번쨰 Flux

두번째 기능을 위해서 두번째 Flux 구조를 추가했고 아래의 관계도와 같은 데이터 흐름이 만들어졌습니다.

  • counterStore : 총 Todo 갯수와 State 상태에 따른 갯수를 관리하는 객체
  • counterComponent : Todo의 개수를 화면으로 표시하는 객체

Flux의 두번째 관계도

3. 세번째 기능

기능 구현을 위한 세번째 MVC

마지막 기능을 구현하기 위한 새로운 Flux 구성요소를 생성했습니다.

  • detailStore : 선택한 Todo를 저장하고 Action에 따라 데이터를 조작하는 객체
  • detailComponent : 선택한 Todo의 데이터를 전달하는 화면을 그리고 사용자의 상호작용에 알맞은 Action을 생성하고 dispatch하는 객체

마지막 Flux의 관계도

Flux 패턴 개발 경험

개발 간의 경험

🎯 정말 편리한 기능 확장과 유지보수

Flux 패턴을 사용하면서 느낀 경험은 기능의 확장의 유지 보수가 정말 쉽고 개발이 빠르다는 점이었습니다.

이벤트 핸들러는 직접 Store에 저장된 상태값을 직접 조작하지 않고 Action을 dispatch하기 때문에 Store와 Component 사이의 의존성을 낮출 수 있었습니다.

이렇게 직접 의존하는 과정이 필요가 없기 때문에, MVC 패턴처럼 새로운 기능을 추가할 때마다 기본의 Component와 Store를 새로운 Component와 Store에 연결하지 않아도 됩니다. Store는 이전 기능의 Component가 기존에 dispatch하는 Action을 받아서 처리하는 코드만 만들면 되기 때문입니다. 덕분에 새로운 코드를 추가하는 경우 기존의 코드들에 영향을 주지 않기에 기능 확장에 굉장히 용이했습니다.

또한 Flux 패턴은 Action으로만 상태값을 바꾸기 때문에, 상태를 조작하는 동안 문제가 발생할 수 있는 영역을 굉장히 작게 지정할 수 있습니다. 덕분에 문제의 원인이 되는 지점을 쉽게 파악하고 수정할 수 있었습니다.

🎯 코드의 흐름을 파악하기 쉬운 선언형 프로그래밍

Flux 방식은 대표적인 선언형 프로그래밍입니다. Flux 패턴은 선언형으로 만들어진 덕분에, 코드의 흐름을 파악하기에 굉장히 편했습니다.

앞선 MVC 패턴은 수많은 "어떻게"를 담당하는 코드들로 구성되어 있었기 때문에, 자칫하면 각 코드들이 왜 만들어지고 쓰이는지를 놓치기 쉬웠습니다.

하지만 Flux 패턴의 경우 미리 "무엇을" 처리하는지에 더 큰 관심을 주었고, "무엇을" 처리하는가에 따라 비즈니스 로직을 분리해서 수행하기 때문에 코드의 흐름을 놓치지 않고 설계할 수 있었습니다. 또 "무엇을" 처리하는지가 명확하게 보이기 때문에 코드의 흐름을 읽는 것도 굉장히 편했습니다.

🤔 다만, 다소 복잡한 초기 설정

하지만 Flux 패턴은 사용하기 위해선 많은 초기 설계가 필요했습니다. dispatcher, dispatcher를 구독하여 Action을 전달받는 Store의 구조 그리고 Action의 종류와 그에 따른 actionHandler의 설계 까지... 실제로 Flux 구조를 이용한 TodoList를 개발하는 시간 중 60 ~ 70%는 설계한 Flux 구조를 구현하는데 쓰였습니다.

만약 정말 간단한 구조의 코드를 빠르게 만들어야 한다면, MVC 구조를 활용하는 것이 더 용이할 수도 있겠다는 생각이 들었습니다.

마무리

  • Flux와 MVC 패턴을 직접 Vanilla로 만들어본 것은 제 실력에 비해 무척 어려운 과제였습니다. 실제로 Flux를 어떻게 구현하면 좋을지 너무 고민했던 터라 꿈속에서도 "Flux를 어떻게 만들어야 할까?"를 고민하며 1주일을 보냈습니다. 하지만 실제로 이를 제 힘으로 구현해보고 이 글을 마무리 할 수 있다는 점에 큰 성취감을 느낄 수 있었습니다.

  • 제가 만든 것은 개발에 최적화된 MVC 패턴은 아니라고 생각합니다. 실제 Frontend Framework 중 Angular.js는 MVC 패턴의 아키텍쳐를 가지고 있지만 여러 기업과 개발자들이 제품을 만들때 유용하게 사용하고 있습니다. 그렇기에 추후 Angular.js와 같은 MVC 프레임워크는 아키텍쳐를 어떻게 구현했는지를 학습해보고 저의 MVC 구조를 개선해보고자 합니다.

  • Flux 패턴과 MVC 패턴을 직접 만들어보면서 구조를 설계하고 이를 직접 구현하는 실력이 늘어남을 느낄 수 있었습니다. 실제로 처음에 MVC 패턴을 만들 때보다 Flux 패턴을 만들 때 "어떻게 하면 더 쉽게 기능 개발을 할 수 있을까"를 고민했고, Class의 활용이나 코드의 재사용과 같은 부분을 더 신경쓰는 모습을 볼 수 있었습니다. 조그마한 발전이지만, 이런 세세한 것에도 신경을 쓰며 발전해가는 모습을 스스로 지켜보며 뿌듯함을 느끼고 있습니다.

  • 추가로 Redux나 Zustand와 같은 Flux 구조로 만들어진 라이브러리를 직접 살펴보면서, 제 Flux 패턴을 더 개선할 수 있는 부분을 살펴보고자 하는 욕심이 들었습니다. 그리고 이 프로젝트를 더 확장시켜 언젠가 하나의 작은 프레임워크로 만들어봐야겠다는 조그마한 목표를 세워보며 이 글을 마무리 하겠습니다.

깃허브 레포지토리

github 레포지토리 : Flux-MVC-comparison

profile
함께 일하고 싶은 개발자가 되기위해 노력 중입니다.

1개의 댓글

comment-user-thumbnail
2024년 4월 20일

글의 수준이 너무 높아서 당황했네요...! 한글자도 놓치지 않으려고 오랜만에 집중해서 읽었습니다.
정말 큰 자극을 받고 있습니다.

답글 달기