redux 는 HMR 때문에 만들어졌다

우현민·2023년 8월 3일
4

React

목록 보기
6/11
post-thumbnail

이 글은 크게 의미있는 지식을 가져다주진 않지만, 알아두면 언젠가 쓸모있을지도요

리덕스는 왜 만들어졌나요?

리덕스를 사용하는 이유, 리덕스의 탄생 배경 등을 검색하면 대부분의 정보들이 Flux전역상태, prop drilling 해결, 렌더 최적화 등을 예시로 듭니다. 하지만 리덕스가 진짜 처음에 "왜" 만들어졌는지에 대한 내용은 나오지 않습니다. 그렇다 보니 리덕스가 만들어진 이유가 flux나 prop drilling 때문이라고도 알려져 있습니다.

요즘 리덕스를 왜 쓰는지, 리덕스가 왜 널리 사용되었는지를 차치하고, 리덕스를 만든 사람이 리덕스를 왜 만들었어? 라고 물어본다면,

정답은 HMR입니다.

HMR (Hot Module Reloading): 개발 환경에서, 내가 수정한 코드가 내가 보고 있는 브라우저 화면에 바로 반영되는 것을 말합니다. 따라서 코드를 수정한 다음 브라우저를 새로고침 하지 않아도 수정된 화면을 바로 확인할 수 있습니다.

이 기능은 개발자에게 매우 중요하기 때문에, 대부분의 라이브러리 / 프레임워크 / 번들러들이 이를 지원하고 있습니다. 최근 프론트엔드 개발자들에게는 프레임워크를 셋업할 때부터 숨쉬듯이 당연하게 존재하는 기능이지만, 과거에는 HMR을 쓰고 싶으면 따로 코드를 수정해서 세팅해줘야 했습니다.



댄 아브라모브

댄 아브라모브는 현재 리액트 개발팀으로 일하고 있으며, 2023.08.03 오늘 기준 깃허브 팔로워 순위 전체 3등에 랭크되어 있는 스타 개발자입니다. 그리고 오늘 설명할 redux 를 처음 만든 사람이기도 합니다.

댄 아브라모브의 블로그 글인 My Decade In Review 에서 리덕스가 탄생하기 전의 재밌는 일화들을 볼 수 있는데요, 그는 2010년 여름에 처음으로 개발자가 된 뒤 2014년에 리액트를 만나고 react-router 에 컨트리뷰트하는 등 네임드 개발자가 되어 가고 있었습니다.

그렇게 그는 2015년에 있을 리액트 컨퍼런스에 참가 신청을 했고, 주제는 Live React: Hot Reloading with Time Travel 였습니다. 그리고 그걸 어떻게 구현할지는 아무 생각이 없는 상태였죠. 결혼도 하고 별 생각 없이 지내다 보니 데드라인이 다가왔고, HMR은 이미 최근 리액트 컨퍼런스에서 다뤄진 주제였기에 HMR 이야기만 한다면 재미가 없을 거라고 생각했습니다.

사실 당시에도 이미 전역 상태 관리 라이브러리들 (flux libraries) 이 존재했습니다. 가령 리액트 창시자인 Andrew Clark 가 만든 Flummox와 같은 것들이 있었습니다.

그래서 "redux 가 prop drilling 을 해결하려고 만들어졌다" 라거나 "flux 를 위해 만들어졌다" 라는 말은 애매하다고 생각합니다. 리덕스가 처음이 아니니까요.

이들의 치명적인 단점은 바로 HMR이 안 된다는 것이었습니다. 여기에 더해서 아브라모브가 이전에도 가지고 있던 아이디어들을 결합해서, reducer 패턴으로 flux 라이브러리를 만들면 HMR이 되는 전역 상태 관리 라이브러리를 만들 수 있을 거라고 판단했습니다.

그렇게 빠르게 redux 를 만들고 오픈한 다음, 스타트업에서 일하는 디자이너 친구에게 ppt를 예쁘게 만들어달라고 부탁하고, 파리로 날아갔습니다. 여기서도 발표 당일 아침에 댄의 노트북이 프로젝터에 연결이 안 되어서, Christopher Chedeau 의 노트북으로 발표를 진행했다고 합니다. (그래서 발표 영상을 보면 sublime text 구매 팝업이 뜨는 걸 볼 수 있습니다 🤣)



리덕스 발표

이 발표의 원본 영상은 한번씩 보시는 걸 추천드립니다. 사실 "redux 가 왜 만들어졌을까?" 에 대한 해답은 해당 영상에 모두 들어 있습니다.

컴포넌트의 HMR은 state를 유지해줬다

당시의 react는 클래스 컴포넌트였고, render() 함수는 side effect 가 없는 선언적인 순수함수였습니다.

class Component() extends React.Component {
  // render 는 순수함수이다.
  render() { 
    return <div>{this.state.count}</div> 
  }
}

따라서 외부 모듈이 변경되었을 때 render 만 다시 수행해준 다음 해당 부분을 갈아끼우면 되었습니다.

Flux 라이브러리의 HMR은 state를 유지할 수 없었다

이게 당시의 flux 라이브러리들에게는 해당되지 않았습니다.

let state = { todos: [] }; // state가 여기 저장된다

export function TodoStore() {
  return {
    addTodo: (todo) => state.todos.push(todo);
  }
}

export default TodoStore;

컴포넌트와는 다르게, state가 로컬 변수로 지정되어 있습니다. 즉 이 친구들에게는 state 를 주입할 수 없는 것이었습니다. 그러니 HMR이 될 때 이전 state를 주입해줄 수 없고, 당연히 state가 날아갈 수밖에 없죠. 이 문제를 해결하려면 store가 state를 직접 선언하지 말고, state 를 외부에서 주입받도록 형태로 해야 합니다.

export function TodoStore() {
  return {
    addTodo: (state, todo) => { // 이렇게 state를 주입받고
      return {
        todos: state.todos.concat(todo),
      };
    },
  }
}

export default TodoStore;

이렇게 만들고 보니, addTodo 함수는 우리가 아는 리듀서의 형태가 되었습니다! 이제 store는 state를 주입받을 수 있고, HMR이 되어도 상태를 유지할 수 있었습니다.

그렇게 reducer + flux = redux 가 되어 이 라이브러리의 이름은 redux 로 결정되었습니다.

여담이지만, 발표 중의 한 이미지를 보면 - 댄 아브라모브는 애초에 라이브러리를 만들 생각조차 없었다는 것을 알 수 있습니다. 그는 그저 컨퍼런스에서 발표할 멋진 HMR 관련 코드가 필요했고, 이게 생각보다 인기를 얻어 라이브러리화하게 된 것입니다. (원본 트윗)

위 내용은 리덕스 발표 이후 그의 인터뷰 글에서도 확인할 수 있습니다.



배포와 그 이후

깃허브에서 리덕스의 첫 public release의 리드미를 보면 "fully hot-reloadable Flux" 라고 되어 있습니다.

그리고 디펜던시에는 react가 있죠. 우리가 지금 알고 있는 리덕스와는 많이 다른 형태입니다. 물로 저 당시에도 react-redux 가 존재했고 사용해야 했지만, 그냥 코드 정리가 좀 덜 된 것 같은 느낌입니다.

redux 와 react 의 분리

얼마 지나지 않아 리덕스 코드가 정리되며 빠른 redux 는 react 에 종속되지 않은 상태관리 라이브러리로 자리잡고, 항상 react-redux 가 redux 와 react 사이의 어댑터 역할을 하도록 정립됩니다.

redux 의 유행

그 이후 수 년 간 대부분의 리액트 프로젝트는 리액트로 뷰를 그리고, 리덕스로 상태관리를 하고, 리덕스 미들웨어로 api 콜을 하는 아키텍처로 구성되었습니다. 리액트를 하려면 리덕스를 필수로 공부해야 했고, 리덕스의 러닝커브 때문에 리액트가 어렵다는 인식이 생기기도 했습니다. 많은 보일러플레이트는 확실히 피로했고,이런 지적에 따라 보일러플레이트를 줄여주고 redux-thunkimmer 를 내장하고 있는 redux-toolkit 이 유행하기 시작합니다.

현재

redux 는 리액트뿐 아니라, 아니 더 나아가서 프론트엔드가 아닌 곳에마저도 영향을 주며 쓰일 수 있는 패턴이 되었습니다. 가령 flutter 에서도 flutter-redux 를 통해 redux 를 쓸 수 있습니다. 초기의 목적이었던 "HMR 되는 flux 라이브러리"는 너무나도 당연해져서 이제 리드미에서도 사라졌고 널리 알려진 전역 상태관리를 위한 국밥과도 같은 도구로 남아 있습니다.

정작 프론트엔드 진영에서 리덕스는 구시대의 무거운 도구로 여겨지기도 합니다. 유행이 변하며 서버상태를 더 잘 관리해주는 react-query 가 급성장했고, 한 술 더 떠서 상태관리 라이브러리 자체의 필요성에 대해서도 의문이 존재합니다. 리액트팀에서도 이 점을 인지하고 서버 컴포넌트에 집중하며 점점 SPA 형태의 웹앱과 전역 상태 관리는 유행에서 멀어지는 것 같습니다.



결론

댄 아브라모브가 컨퍼런스에서 사용할 멋진 코드를 만들기 위해, HMR에서 상태가 날아가는 이슈를 해결하려다 리덕스가 탄생했습니다. 그렇게 리덕스는 널리 알려지고 리액트 진영에서 필수와도 같은 라이브러리로 성장했으나, 이제는 리덕스 자체도 조금 시들해지고 그걸 넘어 상태관리 라이브러리의 존재 자체도 시들해지는 느낌입니다. 하지만 리덕스가 프론트엔드 트렌드에 큰 한 획을 그었다는 사실은 분명합니다.

오해가 있을까봐 덧붙이자면, 리덕스를 사용하는 이유가 HMR 때문은 아닙니다. 이 글은 널리 알려지지 않은 내용인 리덕스와 HMR의 관계, 그리고 리덕스가 만들어진 이유가 HMR이라는 내용을 담고 있습니다. 누군가 "리덕스가 왜 만들어졌나요?" 가 아닌 "리덕스가 왜 좋나요?" 라는 질문을 했을 때 HMR이라고 답변한다면, 그건 틀린 답변이라고 봐야 할 것입니다.



레퍼런스

profile
프론트엔드 개발자입니다

2개의 댓글

comment-user-thumbnail
2023년 8월 3일

많은 것을 배웠습니다, 감사합니다.

1개의 답글