위시켓 요즘IT에 프론트엔드 개발에 관한 좋은 글이 올라와서 스크랩 해둡니다.
- 글쓴이: 테오의 프론트엔드
아래 모든 내용은 위 글에서 요약하여 가져왔습니다. (글쓴이에게 감사)
1. 프론트엔드 아키텍처 변화
MVC -> MVP -> MVVM -> MVI 아키텍처
1) 프론트엔드 트렌드 변천사 8줄 요약
- HTML, CSS, JS 의 탄생: 관심의 분리와 느슨한 결합
- 서버가 View 를 전달
- jQuery 까지의 시대: 일단 DOM 을 쉽게 쓰자
- Ajax 의 탄생, 데이터 교환 (API)
- HTML + JS 를 합치는게 더 낫던데?: MVC 컴포넌트 방식의 탄생
- 컴포넌트(HTML+JS) 단위로 View, Model 관리, ex) backbone.js
- 선언적으로 만들자: 데이터 바인딩 + 템플릿 = MVVM 웹프레임워크 전국시대
- 템플릿 방식으로 HTML 작성 자동화, ex) Angular, Vue, React, …
- 컴포넌트간 데이터 교환이 너무 복잡해: Container - Presenter 방식
- 상태관리 로직이 흩어지고 컴포넌트가 복잡해짐, 재사용성도 떨어짐
- 컴포넌트를 나누자!
- readonly 스타일의 ‘Present 타입 컴포넌트’
- 데이터 조작을 주로 다루는 ‘Container 타입 컴포넌트’ - Container => (props) => Presenters (View, 재사용성)
- 최상위에 Application State (API)
- Service 컴포넌트가 로직을 담고, View 컴포넌트는 상태변화를 관리
- View 컴포넌트는 (조립된) 여러 하위 readonly 컴포넌트로 구성
- Props Drill 문제 어떻게 할거야?: FLUX 와 Redux
- 하위 컴포넌트까지의 props(상태값 묶음) 전달 경로가 길어짐
- 너무 복잡한데?: hooks 와 context, Recoil, Zustand, jotai
- 더 간결한 문법과 외부 비즈니스 로직과의 쉬운 연동 필요
- Recoil: 전역객체(Atom)로 상태 저장과 변경감지로 데이터 전달
- 그 밖에 Zustands, Jotai 등 …
- 어차피 대부분 서버 API 를 관리하려고 쓰는거 아니야?
- API 를 통한 전역 상태관리로 View 컴포넌트에 바로 전달
- Composition API (Vue 3.0), Valtio (React), Hookstate 등 …
2) 프론트엔드 상태관리의 변화 3줄 요약
- 컴포넌트의 계층구조가 데이터의 계층구조와 다르고 더 복잡해짐
=> 컴포넌트 간 데이터 교환이 어려워짐 - 컴포넌트와 비즈니스 로직의 분리
=> 상태관리의 등장 - 상태관리의 3가지 방향성
- 고도화된 상태관리
- 간단한 전역 스토어
- 서버(API) 기반 상태관리
2. MVI 패턴 (MVVM 이후)
1) 특징
- 앱 전체, 컴포넌트 전체에 적용되는 패턴이라는 점에서 큰 변화점
- 데이터가 단방향으로 연결되고 전역적으로 구성됨
- 컴포넌트 계층구조를 따라 전달하지 않음 => 일관성 있는 상태관리
<그림> MVI cyclic flow representation - 테오의 프론트엔드 |
2) 아키텍처 방향성
- 비즈니스 로직을 분리
- Model: 데이터를 관장
- Intent: 사용자 행동을 데이터 변화로 매핑
- Model 도 분리
- 변화를 감지하고 변경사항을 전파하는 영역
- 데이터를 변화하는 로직 (Command)
- View 에서는 Query 와 Command 를 조립해서 사용 (CQRS 패턴)
- Query: Model 로부터 데이터 조회
- Command: 데이터 변화
3) Intent 와 Reducer
- AS-IS
- Model 과 View 간의 의존성 발생
1
2
3
4
5
6
7
8
// View 에서 직접 여러가지 값들의 변화를 기술한다.
// 흔한 코드 (MVC)
const onClick = () => {
setVisible(!visible)
setCount(count + 1) // 데이터 변화
setTodos([...todos, {title: "할일 추가"}]) // 의도
}
- TO-BE
- View 에서는 의도만을 전달하도록 하고
- 데이터 변환은 모델에서만 처리하도록 한다
4) MVI 패턴의 의사코드 예제
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Action
export const _INCREASE = action("_INCREASE")
export const _DECREASE = action("_DECREASE")
export const _RESET = action("_RESET")
// input(state): Intent => Model
// Model
export const store = createStore({count: 0}, state => {
on(_INCREASE, (value) => state.count += value)
on(_DECREASE, (value) => state.count -= value)
on(_RESET, (value) => state.count = 0)
})
// load(state): Model => View
// Component
export const App = (props) => {
// Query
const count = SELECT(store.count)
// Computed Value
const doubledCount = count * 2
// Intent
const onClick = () => dispatch(_INCREASE(+1))
// View
return (
<button onClick={onClick}>
{count}
</button>
);
}
// display(state): View => User
9. Review
- View 컴포넌트가 비대해진다면, 상태관리 라이브러리를 도입하자.
- 덩치 큰 View 컴포넌트가 다 처리하는 방식은 MVC 패턴이다.
- Service 컴포넌트는 API 만 담당하는게 아니다. (Action 기술)
- React 는 현재 전세계적으로 가장 많이 사용되는 프론트 개발 기술이다.
- MVI 상태관리 라이브러리를 검색하면 안드로이드 분야가 많이 나온다.
- 외국어 문서를 검색하고 싶다면 ‘CQRS’ 키워드를 사용하자.
참고문서
- Cycle.js - Basic examples
- Atomic Design Pattern의 Best Practice 여정기 - velog
- NGXS is a state management pattern + library for Angular
- Recoil is an experimental state management framework for React
끝! 읽어주셔서 감사합니다.