본문 바로가기

Client/Front-end

<FE> 프론트엔드 상태 관리와 역사

 

1. 상태관리란

* 소개

 - 프론트엔드하면 상태관리라는 단어를 빼놓을 수 없다. 상태를 효율적으로 관리하고 보여 주는 것이 프론트엔드 역량의 핵심이라 해도 과언이 아닐 것이다.

 

 - 그렇다면 도대체 상태가 무엇이고, 상태가 왜 프론트엔드에서 중요할까. 이러한 필요성들이 어떻게 어떤 목표를 가지고 발전해왔을까. 오늘의 포스팅은 이런 고민에서 시작하게 되었다.

 

* 상태란?

 - 프론트엔드에서 상태란 주로 유저 정보나 UI에 영향을 미치는 동적으로 표현되는 데이터이다. 특정 컴포넌트안에서 관리되는 로컬 상태와 여러 컴포넌트에서 관리되는 전역 상태로 구분지을 수 있다. 말로는 어려우니 아래의 예시를 보자.

 - 위는 필자가 최근 진행했던 프로젝트에서 할일을 보여주는 부분을 캡쳐한 것이다. 회사 내에서 개인이 자신의 개인업무와 팀에서 해야할 일을 한꺼번에 보고 관리하고 있다. 이 때, 위의 할일들이 바로 상태이다.

 

 - 프론트엔드는 상태를 갖고 있음으로써 사용자와 상호작용을 할 수 있다. 위에서 개인 업무만 따로 보고 싶다고 가정하자. 개인 엄무를 클릭하면 PERSONAL 로 표시된 할일들만 보이게 될 것이다. 이는 굳이 백엔드에 요청할 필요없이 데이터를 필터링하여 보여주기만 하면 된다.

 

 - 즉, 상태는 데이터이다. 정리하자면 프론트엔드에서의 상태는 사용자에게 노출시키고 상호작용하기 위한 데이터이다.

 

* 상태관리

 - 위에서 봤듯, 상태를 프론트엔드에서 관리하게 되면 네트워크 통신 횟수를 획기적으로 줄일 수 있다. 그렇다면 이게 다일까? 그렇지않다.

 

 - 현대의 웹 개발은 하나의 페이지에서 데이터를 주고 받는 웹앱 싱글페이지 형태의 UX가 주를 이루고 있다. 그에 따라 필요한 부분만 변경하여 적절하게 클라이언트와 통신할 필요가 있다. 

 

 

 - 위에서 봤던 필터링, 위 사진과 같이 단순이 열고 닫힘상태, 그리고 인풋값, 체크박스, 심지어 로딩 상태나 에러 상태까지도 프론트엔드에서 해야할 필요성이 대두되었다. 이러한 상태는 눈에 보이는 부분뿐만 아니라 보이지 않는 부분들까지 비동기적으로 변하게 되는데, 이러한 상태를 프론트엔드에서 제어해야한다.

 

2. 과거의 상태관리

* 과거의 상태관리

 - 과거 ES6이전, 대 제이쿼리 시대에도 상태는 당연히 필요했다. 이 시기에도 이미 Ajax가 구현되어 비동기적으로 동적화면을 구성하던 시기였다.

 

- 단순히 전역객체를 사용하여 데이터를 관리할 수도 있었지만 전역상태를 오염시킬 수 있었고, 상태를 필요로 하는 요소만 직접 관리하고 싶었다. 그래서 사용한 방식이 HTML의 data 속성이다. 상태가 필요한 태그의 data속성에 상태를 넣음으로써 해당 요소에만 접근하여 상태를 관리할 수 있었다. 

 

* 문제점

 - 하지만 위 방식은 크게 두 가지 문제점으로 복잡성을 키웠다.

 

 - 첫째, DOM으로의 접근이다. DOM에 상태를 저장하고 있으므로, 상태를 관리하기 위해서는 직접 접근을 해야한다. 이를 위해 DOM에 접근하는 코드가 반드시 필요하다. 결과적으로 상태가아니라 DOM 요소를 중심으로 코드가 작성된다. 이는 상태에 대한 접근성을 떨어트리고 복잡성을 키우게 된다.

 

 - 둘째, 상태변화 추적이 어렵다. 상태는 여러 요소에 흩어져있는데 만일 api를 호출하여 업데이트 하는 중 상태가 변경된다면 어떻게 될까. 상태가 올바르게 변경될지도 미지수이고, 버그 발생시 어디서 문제가 생겼는지 추적하기도 어렵다. 이는 코드의 유지보수와 확장을 어렵게하는 대표적인 문제 중 하나이다.

 

 - 이러한 문제들은 2010년 스마트폰의 폭발적인 보급으로 웹의 범위가 확대대면서 더 커지기 시작했다.

 

3. 현대의 상태관리

* 프레임워크 등장

 - 위에서 나온 문제를 해결하기 위해 AngularJS가 등장했다. 뒤이어 React, Vue, Svelte 등의 프레임워크(프레임워크가 아닌 것도 있으나 의미상 프레임워크로 칭하겠다)가 등장한다.

 

 - 앵귤러의 등장으로 상태는 DOM에서 탈출했다. 프론트엔드 개발자는 DOM이 아닌 자바스크립트에서 상태를 관리할 수 있게 되었다. 즉 DOM에 접근하는 로직이 필요없어졌다. 게다가 필요한 상태들을 컨트롤러에 모아서 관리하게 되면서 데이터에 초점을 맞춘 개발이 가능해졌다.

 

 - 상태 데이터 값이 바뀌면 작업이 수행되도록 하여 문제가 생기면 어디서 발생했는지 알 수 있게 되었다. 이 또한 언제 어떻게 발생했는지에 대한 디버깅은 여전히 머리를 아프게했다.

 

* 라이브러리 등장

 - 리덕스와 같은 라이브러리의 등장으로 언제 어떻게 상태가 변화되었는지 제어가 한결 수월해졌다. 리덕스는 flux패턴을 도입하여 단방향 데이터흐름으로 상태를 제어한다. 이를 통해 디버깅이 매우 쉬워졌다.

 

 - 리덕스는 전역 상태 저장소를 제공하고, Props drilling 문제도 해결한다. 특히 react-redux 나 최근 나온 Recoil등은 리액트에서 리렌더를 방지해주는 최적화까지 들어있어 성능이슈까지 해결하고 있다. 전역상태를 필요한 곳에서 관리하기 매우 수월해진 것이다.

 

 - 하지만 또다시 문제가 생겼다. 현대의 웹은 웹앱으로 진화하고 있다. 하나의 페이지에서 여러가지 정보를 실시간으로 동기화할 필요성이 생기면서 out-of-date문제가 생긴다. 뿐만 아니라 전역상태의 경우 필요한 시점이 아닌 최상단에서 데이터 fetch를 하게되면서 데이터 흐름 파악이 힘들어진다.

 

* SWR

 - 위에서 "누가"를 담당하는 어디서 문제가 발생했는지는 프레임워크의 등장으로 쉽게 해결되었다. 하지만 "언제"와 "어떻게"가 애매한 상태이다. 언제 어떻게 "발생"하는지는 알겠으나 데이터를 언제 어떻게 받아오냐가 애매하다.

 

 - 먼저 "언제"를 담당하는 필요한 시점에서의 데이터 로드를 살펴보자. 위에서처럼 최상단에서 데이터 fetch를 하면 불확실성이 커지게 된다. 그렇다면 필요한 요소가 생길 때 메모리에 캐시하면 어떨까. 리액트로 예를 들자면 useEffect를 사용하여 컴포넌트가 마운트 될 때 캐시가 있으면 그것을 사용하고 없으면 Fetch를 하면 된다. 이것으로 데이터를 불러오는 시점과 데이터가 있음에 대한 불확실성을 해결할 수 있다.

 

 - 다음은 out-of-date문제이다. 어떻게 최신임을 보장할 것이고, 어떻게 받아올 수 있을까. 이 때 활용할 수 있는 것이 stale-while-revalidate 컨셉이다. 이를 알아보기 위해 HTTP스펙의 Cache-Control확장을 살펴보자.

 

Cache-Control: max-age=<seconds>, stale-while-revalidate=<seconds>
# ex) Cache-Control: max-age=1, stale-while-revalidate=59

 

 - 위에서 예제가 말하고 있는 바가 무엇일까. 먼저 HTTP 요청이 1초 내에 반복되면 캐시된 값을 반환한다. 만일 1~60초 사이에 반복적으로 발생하면, 캐시된 값은 낡았지만 그래도 반환하고 백그라운드에서 향후 사용을 위해 재검증 요청이 이루어진다. 60초 이후는 다시 서버에 요청을 보낸다.

 

 - 위를 우리가 먼저 얘기했던 캐시 메모리에 적용한다면 out-of-date문제가 해결될 것이다. 이 swr컨셉을 적용한 구현체가 흔히 알고 있는 react-query, swr 등이다. 이들은 서버로부터 데이터를 가져오는 코드와 데이터에 접근하는 인터페이스가 동일하다. 원하는 시점에 데이터를 받아오거나 확인할 수 있어 유지보수에 용이하다. 게다가 주기적으로 revalidate하여 out-of-date문제를 해결하였다.

 

 - 여기서 드는 의문은 그렇다면 전역 상태가 필요없을까? 하는 의문이다. 당연히 필요하다. 컴포넌트 트리 외부에서 노출되는 UI들이 바로 그들이다. 토스트, 모달, 심지어는 다크모드까지 전역에서 관리하여 전체에 영향을 미쳐야한다.

 

4. 앞으로의 상태관리

* 실시간 & 앱

 - 앞으로의 웹은 더욱더 실시간에 가까워질 것이다. 게시판 성격에서 SNS, 메신저, 방송으로 교환 속도가 점점 더 빨라지고 있다. 그에 따라 실시간으로 데이터를 빠르고 효율적으로 관리해야 한다. 앞으로 메타버스를 향해 나아가면서 그 이상을 해내야하는 상황이다.

 

 - 웹은 현재 앱과의 경계를 허물고 있다. PWA의 등장도 같은 맥락이다. 물론 모바일 앱에 한정되지 않는다. VSCode, MS Office365, 슬랙 등도 웹 기반에서 돌아가는 서비스이다. 이들 모두 새로고침되지 않고 일부 영역만 업데이트 되는 방식이므로 데이터를 제어하는 방식이 더욱 고도화되고 있다.

 

* 서버리스

 - 앞서 봤듯 데이터(상태)를 다루는 로직이 점점 백엔드에서 프론트엔드로 넘어오고 있다. 이를 더 효율적으로 처리하기 위해 프론트엔드는 클라우드를 통해 서버 없이 작업을 하는 형태가 되어가고 있다. 서버리스는 실제 서버가 없다는 의미가 아니라 데이터 처리 로직만 개발하여 클라우드에 올리는 방법을 의미한다.

 

 - 클라우드 컴퓨팅의 등장으로 기업과 개발자는 인프라의 유지관리를 클라우드 공급자에게 맡길 수 있게 되었다. (물론 확장이나 서버 유지 보수는 개발자가 별도로 해야 한다.) 이러한 패러다임 덕에 서버 패치 및 업데이트 관리의 필요성을 제거한 새로운 수준의 추상화가 도입되었다. 서버리스 어플리케이션은 이벤트 드리븐이고, 임시적인 스테이스리스 컴퓨팅 컨테이너에서 실행되어 클라우드 제공자에 의해 완벽하게 관리된다. 이는 프론트엔드가 더욱 더 상태관리에 집중할 수 있는 환경을 제공해 줄 것이다.

 

 

 


참고

 

 

 

프론트엔드 상태관리의 역사 - (1)

프론트엔드 상태관리의 역사를 알아 봅시다.

velog.io

 

프론트엔드의 상태관리란 무엇인가?

최근 회사에서 업무를 하면서 상태관리라는 말을 자주 하게 되었습니다. 제가 ‘상태가 복잡하다’, ‘상태를 추가해야한다’, ‘상태를 관리해서 구현해야한다’ 등의 말을 습관적으로 많이

medium.com

 

전역 상태 관리에 대한 단상 (stale-while-revalidate)

이 글의 부제는 Stop Using Redux for Caching for API Response이다. 한 때 전역 상태 관리 도구로 Redux를 즐겨썼던 개발자로서 이제 더이상 Redux를 사용하지 않게 된 이유와 회고를 담은 글이다. Table of Contents

jbee.io

 

프론트엔드 개발에서의 상태 관리

React가 상태관리를 위한 라이브러리는 아니다.그러나 상태 관리의 주요 원칙을 배우고 이를 따라간다면, 컴포넌트 간 서로 느슨하게 결합된(loose coupled), 구조적으로 아름다운 코드를 작성할 수

velog.io

 

서버리스 컴퓨팅 시대의 풀 스택 개발

서비스형 서버리스는 정해진 일련의 서비스를 제공하면서도 확장성과 가용성에 대한 관리를 포함해 그 어떠한 종류의 서버 유지관리 작업이 필요 없다는 점은 기존의 서버리스와 같지만, 코드

medium.com

 

시니어 개발자가 말하는, 프론트엔드 역사와 미래 | 요즘IT

웹 프론트엔드는 웹 서비스 발전에서 막내 격으로 생긴 포지션입니다. 프론트엔드라는 영역이 갑자기 생겨난것은 아니지만 지금처럼 이렇게 선명하게 프론트엔드와 백엔드가 세분화된 배경에

yozm.wishket.com

 

TECH CONCERT: FRONT END 2019 - 데이터 상태 관리. 그것을 알려주마

NAVER Engineering | 내용 웹프론트엔드 기술의 발달로 웹프론트엔드는 더이상 단순한 페이지 뷰가 아닌 앱의 역할을 충분히 해내고 있습니다. SPA 구조로 웹을 개발하게 되면서 자연스럽게 프론트엔

tv.naver.com