참조
오늘 글은 테오님의 글을 인용하여 작성하였습니다
덕분에 많은 도움이 되었습니다 :)
https://yozm.wishket.com/magazine/detail/1663/
왜 궁금하게 되었는지?
Vue나 React, Django등을 사용하면서 MVVC, MVC, Flux와 같은 용어들을 접하게 됩니다.
처음에는 그냥 이런 것들이 있구나 하면서 넘어갔지만, 왜 이러한 패턴들이 생겨났고, 왜 사용하게 되었는지, 그래서 어떤 아키텍쳐가 좋은 아키텍쳐인지 궁금해졌습니다.
그래서 오늘은 프론트엔드의 다양한 아키텍쳐에 대해 정리해 보려 합니다.
프론트엔드 트렌드 변천사
1. HTML, CSS, JS의 탄생 : 관심의 분리와 느슨한 결합
2. jQuery까지의 시대 : 일단 DOM을 쉽게 쓰자
3. HTML + JS를 합치는게 더 낫던데? : MVC 컴포넌트 방식의 탄생
4. 선언적으로 만들자 : 데이터 바인딩 + 템플릿 = MVVM 웹 프레임워크
5. 컴포넌트간 데이터 교환이 너무 복잡해 : Container - Presenter 방식
6. Props Drill 문제 해결방법 : FLUX와 Redux
7. 너무 복잡한데? : hooks와 context, Recoil, Zustand, jotai
8. 어차피 대부분 서버 API를 관리하려고 쓰는거 아냐? : React Query, SWR, Redux Query
1. HTML, CSS, JS의 탄생 : 관심의 분리와 느슨한 결합
웹은 HTML과 JS, 그리고 CSS가 순서대로 탄생했고, 각자의 방식대로 성장했습니다. HTML은 서버가 작성하는 영역이었고, JS는 간단한 동작과 CSS는 화면을 관리했습니다.
2. jQuery까지의 시대 : 일단 DOM을 쉽게 쓰자
'에이잭스(Ajax)'의 탄생으로 서버에서는 HTML을 만들지 않고 데이터만 교환이 가능하게 됐습니다. 그래서 JS를 이용해 데이터로 DOM을 조작하는 작업이 중요하게 되었고, 이에따라 jQuery와 같은 Ajax와 DOM을 잘 다룰 수 있는 도구를 통해 개발하게 되었습니다.
3. HTML + JS를 합치는게 더 낫던데? : MVC 컴포넌트 방식의 탄생
그러다보니 HTML과 JS를 함께 다루는 편이 더 나았고 이후 앱을 만들던 MVC 아키텍처를 표방하면서 데이터를 조작하고 DOM을 조작하는 로직을 하나로 관리하려는 움직임이 생겨났습니다. 그러나보니 자연스레 화면 단위가 아니라 컴포넌트 단위로 발전하게 됩니다. 또한 MVC방식으로 화면을 만들고자 하는 backbone.js와 같은 프레임워크도 만들어졌습니다.
4. 선언적으로 만들자 : 데이터 바인딩 + 템플릿 = MVVM 웹 프레임워크
매번 데이터 변경 때마다 템플릿 방식으로 HTML을 작성하는 방안이 연구되었고, 이를 자동화하는 과정에서 knockuot.js, angaulr.js등을 바탕으로 웹서비스를 개발하는 MVVM 아키텍쳐가 만들어집니다. 이후 React, Vue, Angaulr를 비롯한 수많은 프레임워크가 만들어지기 시작합니다.
5. 컴포넌트간 데이터 교환이 너무 복잡해 : Container - Presenter 방식
데이터가 많아지고, 로직이 흩어지면서 컴포넌트는 점점 복잡해집니다. 재사용성이 떨어지면서 데이터를 받아 보여주기만하는 readonly스타일의 'Presenter형 컴포넌트'와 데이터조작을 주로 다루는 'Container형 컴포넌트'분리하게 됩니다. 이후 Container에서 props를 Presenter로 내려주면서 로직을 한군데에 모으고 화면을 다루는 View방식이 재사용 형태의 아키텍쳐 주류가 됩니다.
6. Props Drill 문제 해결방법 : FLUX와 Redux
이런식으로 컴포넌트를 작성하게 되면 상위 props들이 하위로 전달되는 과정에서 중간 컴포넌트를 사용하지 않고 하위에 데이터를 보내기위한 props가 필요해졌습니다. 컴포넌트의 독립과 재사용성을 위해서 컴포넌트를 분리했지만, 중간 컴포넌트로 인해 오히려 상위 컴포넌트와 하위 컴포넌트가 더 단단하게 결합한 셈이 됩니다. 이렇게 상위 props를 하위 컴포넌트로 전달할 때 중간 컴포넌트에서 사용하지 않은 prosp를 추가해야하는 Props Drilling문제가 대두됩니다.
그러다보니 비즈니스 로직을 굳이 컴포넌트 계층구조로 만들 필요가 없는것을 알게 됩니다. View와 비즈니스 로직을 분리해 단방향 데이터구조를 가지는 FLUX패턴이 대두되고, Redux 등을 통해 사용하게 되면서 이러한 형태가 주류 아키텍쳐가 됐습니다.
이때부터 비즈니스 로직을 컴포넌트에서 분리하고, 별도로 관리하는 도구들이 주류가 됐으며, 이러한 개념을 상태관리(State Management)라고 부르게 됩니다.
이후 Redux를 따라 Vuex가 만들어지고 클래스 데코레이터를 이용해 좀 더 쉽게 만든 Mobx도 유행했습니다. Angaulr에서는 Rx.js를 베이스로한 Ngrx가 만들어졌고 이후 API를 좀 더 간소화한 Ngxs도 만들어졌습니다.
7. 너무 복잡한데? : hooks와 context, Recoil, Zustand, jotai
하지만 Redux는 너무 많은 보일러플레이트(최소한의 변경으로 여러곳에서 재사용되며, 반복적으로 비슷한 형태를 띠는 코드)가 필요했습니다. 컨셉과 시도는 좋았지만, 과한 문법 체계를 가지고 있었기에 대형 프로젝트가 아니라면 중소규모에서 대부분은 오버엔지니어링 되었습니다.
이후 React는 조금 더 간결한 문법과 외부에서 데이터를 사용할 수 있도록 Hooks를 통해 외부 비즈니스 로직을 쉽게 연동할 수 있도록 만들었습니다. 또한 Context를 통해 Props Drilling없이도 상위 props를 하위로 전달할 방법을 제공하면서 Redux는 사용하기 싫은 기술이 되었습니다.
그렇지만 hook API만으로 전역적인 상태관리가 용이하진 않았습니다. 그래서 Atom이라는 전역객체를 이용해 데이터를 기록하고 변경감지를 통해 View로 전달하는 Recoil이나 Zustands, Jotai같은 방식이 최근 새로운 대안으로 제시되고 있습니다.
8. 어차피 대부분 서버 API를 관리하려고 쓰는거 아냐? : React Query, SWR, Redux Query
대부분 프론트엔드에서 전역적인 상태관리가 필요한 이유는 서버와 API에 있습니다. 웹의 특성상 데이터의 보관과 조회, 수정이 서버에서 이루어져야하고 그렇기에 비즈니스 로직이 대부분 백엔드에 보관되기 때문입니다.
그렇다면 View는 서버 데이터를 보여주고 서버에 Action을 전달만하는 경우가 대부분이었습니다. 그러자 백엔드와 직접 연동해 기존 상태관리에서 로딩, 캐싱, 무효화, 업데이트 등 복잡하게 진행하던 로직들을 단순하게 만들어주는 방식도 생겨났습니다. 이러한 방식을 통해 많은 부분을 차지하고 있던 'API를 통한 전역 상태관리'가 단순해지는 결과가 나왔습니다.
눈여겨볼 상태관리 도구
Vue가 3.0이 되면서 Proxy를 바탕으로 하는 Composition API를 제공했습니다. 이를 통해 웹에서 사용하던 연산자나 함수를 그대로 사용해 로컬에서 데이터 변경감지를 할 수 있는 전력 관리 기능도 생겼습니다. 이러한 방식에 영감받아 React에서는 Valtio라는 라이브러리도 생겼습니다.
이런 변천사가 있는줄 모르고 Redux만쓰면 좋은건줄 알았네요! 앞으로 이런 흐름을 파악하며 신기술들을 학습하는 자세를 가져야할 것 같습니다.
다음에 이어 프론트엔드 트렌드 변화에 대해 작성해보겠습니다! 도움이 되셨으면 좋겠습니다!