-
Notifications
You must be signed in to change notification settings - Fork 0
프론트엔드 디자인 변천사
옵저버 패턴은 왜 프론트엔드 디자인 패턴에서 많이 사용되는가?
왜 프론트엔드에서 상태관리가 중요해 졌는가?
왜 컴포넌트 단위로 어플리케이션을 관리하게 되었을까?
프론트엔드의 디자인 패턴에서 가장 많이 사용되는 개념 중 하나는 옵저버 패턴입니다. 현재 프론트엔드에서 쓰이는 수많은 라이브러리에는 옵저버 패턴이 쓰이고 있습니다. (React, Redux, MobX, Vue 등등)
어째서 다른 무수히 많은 패턴들 중 옵저버 패턴이 현재 채택되어 가용되고 있을까요? 그것을 이해하기 위해서는 프론트엔드 디자인 변천사를 살펴볼 필요가 있습니다.
프론트엔드의 변천사를 보면, 어플리케이션이 점점 더 복잡해짐에 따라 데이터와 UI 사이의 의존성을 낮추는 방향으로 변화해왔음을 알 수 있습니다. 이는 관심사의 분리를 통해 복잡한 애플리케이션의 유지보수를 쉽게 만들기 위한 것입니다. 상태관리와 컴포넌트 역시 이를 위한 흐름 사이에서 등장하게 된 개념입니다.
이 흐름을 따라가며, 프론트엔드에서 어떻게 의존성을 분리하고, 상태와 UI를 효율적으로 관리할 수 있게 되었는지 살펴보겠습니다.
[관심사의 분리가 중요한 이유]
인간은 한번에 여러개의 관점을 동시에 처리하기 어려워합니다.
따라서 각 요소가 구분가능한 하나의 명확한 역할만을 수행하도록 설계함으로써,
코드의 가독성과 유지보수성을 향상시키고자 하는 행위인 것이죠.
초기의 웹 애플리케이션은 주로 SR (Server Rendering) 방식을 사용했습니다. 이 방식은 서버가 html을 랜더링 한 뒤 클라이언트에 전달하며, 클라이언트는 이를 보여주는 역할만 했습니다. 서버가 렌더링을 처리하는 건 효율적이었지만. 사용자가 매번 상호작용할때마다 페이지를 새로고침해야 했기에 불편했습니다.
이때 MVC (Model-View-Controller) 패턴을 사용하여, 애플리케이션의 데이터(Model), UI(View), 상호작용(Controller) 을 분리하려 했습니다. 하지만 실제로는 뷰(View)와 컨트롤러(Controller)가 밀접하게 결합되어 있어 의존성 분리가 어렵고, 유지보수가 힘들었습니다.
- 클라이언트가 요청을 보냄
- 서버가 요청을 처리하고 HTML을 생성
- 클라이언트에 생성된 HTML을 반환
- 클라이언트에서 페이지가 새로 고침됨
웹 페이지가 서버에서 HTML로 렌더링되어 브라우저로 전달
-
Model
: 데이터 관리 -
View
: 사용자에게 보이는 부분- 템플릿 엔진 : 동적으로 HTML을 생성하고 데이터를 렌더링
-
Controller
: 사용자와 애플리케이션의 상호작용을 처리
클라이언트와 서버 통신이 점점 많아졌는데,
그때마다 매번 새로고침을 해야 하는 문제는 사용자 경험에 매우 부정적인 영향을 미쳤습니다.
이 문제를 해결하기 위해 **SPA(Single Page Application)**가 등장했습니다. SPA는 클라이언트에서 데이터를 관리하면서 비동기적으로 데이터를 서버에 요청하고, 클라이언트에서 UI를 업데이트합니다. 이런 방식을 채택함으로서 페이지 리랜더링 없이, 필요한 부분의 UI만 업데이트 할 수 있게 되었습니다.
SPA에서 클라이언트가 데이터를 관리하게 되면서, 상태 관리의 중요도가 커졌습니다. 애플리케이션이 점점 복잡해짐에 따라, 데이터를 어떻게 관리하고 언제 업데이트할지 정의하는것이 점점 어려워졌습니다.
[SPA 특징]
- 사용자가 처음 접속시 애플리케이션을 한번에 로드
- 초기 로딩으로 public 파일(html, css, js) 받아옴
- 페이지 이동없이 **필요한 부분만 업데이트**
- 새로운 페이지를 서버에 요청하는 대신 클라이언트 측에서 렌더링 작업
- 서버는 필요한 데이터만을 반환
- 클라이언트에서 데이터를 이용해 DOM을 수정
어플리케이션이 점점 커지고 복잡해지네, UI와 로직이 얽혀 있어 재사용성과 유지보수가 어려워.
컴포넌트 기반 아키텍처는 이러한 문제를 해결하기 위해 UI와 비즈니스 로직을 독립적으로 관리하는 방식입니다.
특정 기능이나 UI 요소를 구현하기 위한 모든 요소 HTML 구조, CSS 스타일, JavaScript 동작를 하나의 단위로 묶어 다루기에 재사용성이 증가하며, 기능 중심의 모듈화가 가능합니다.
이로써 애플리케이션을 작은 단위로 분리하고, 각 컴포넌트가 독립적으로 동작하면서 재사용성과 유지보수성을 크게 향상시켰습니다.
상태가 많고, 변화가 점점 복잡해지네….
컴포넌트간의 의존성(props drilling)이 높아졌고, 관리가 너무 어려워.
컴포넌트 기반 방식은 기능 단위로 모듈화할 수 있게 했지만, 한 컴포넌트 안에 데이터 관리, 표현 로직, 비즈니스 로직이 모두 들어있어 복잡해졌고, 컴포넌트 간 결합도가 높아지면서 관리가 다시 어려워졌습니다.
이에 따라 컴포넌트 내부에서 다시 계층을 분리하려는 시도가 이루어졌고, 그중 하나가 바로 상태 관리입니다. 컴포넌트는 view의 역할만 수행하고, 상태를 분리하려는 시도가 이어졌습니다.
여기서 옵저버 패턴은 분산된 상태를 중앙에서 관리하고, 이 데이터(상태)를 관찰하는 방식을 채택하여 상태 관리를 더 수월하게 했습니다.
상태에 변화가 일어나면, 이를 구독하고 있는 view가 자동으로 업데이트됩니다. 이는 데이터와 UI 간 의존성을 분리하고, 애플리케이션을 더 유연하고 확장성 있게 만듭니다.
**기본적인 Flux/Redux 흐름**
1. Action이 발생
2. Dispatcher가 Action을 해석 & 로직 수행
3. Dispatcher가 Store내 state를 변경
4. 변경된 state 정보가 view로 전달
5. view에서 action 발생시 dispatcher로 전달
- https://velog.io/@teo/separation-of-concerns-of-frontend
- https://velog.io/@alsgud8311/expresspug%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%9C%84%EC%9E%84-%EC%BD%9C%EB%9D%BC%EB%B3%B4%EC%9D%98-SSR-CSR-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0
- https://velog.io/@fru1t/Something-Side-Rendering
- https://velog.io/@baegyeong/MVC-%ED%8C%A8%ED%84%B4%EC%9D%84-%EC%99%9C-%EC%A0%81%EC%9A%A9%ED%96%88%EC%9D%84%EA%B9%8C
- https://jskdev.vercel.app/docs/dev/StateManagement/2024-10-22-Redux-deepdive/