우리 팀이 Zustand를 쓰는 이유

­가은·2023년 11월 12일
57
post-thumbnail
post-custom-banner

부스트캠프 그룹프로젝트에서 우리 팀은 Zustand를 사용하게 되었다.
이 글은 우리 팀이 어떤 이유로 Zustand를 선택하게 되었는지에 대한 이야기이다.

여기서는 상태관리 라이브러리 중 왜 Zustand를 골랐는지에 포커스를 두어 이야기하기 때문에, 왜 상태관리 라이브러리를 써야 하는지에 대해서는 설명하지 않는다.
프로젝트 특성상 상태관리 라이브러리를 굳이 쓰지 않아도 될 지도 모른다.
이 글을 읽기 전에, 현재 프로젝트에 상태관리 라이브러리가 꼭 필요한지에 대해서 먼저 생각해보길 추천한다.

먼저 우리가 상태관리 라이브러리를 선택할 때 가장 기본적으로 고려한 것은 아래와 같다.

  1. 학습에 큰 어려움이 없어야 한다.
  2. 가벼워야 한다.

우리에게는 6주간의 시간밖에 없기 때문에, 상태관리 라이브러리 학습에 많은 시간을 투자할 수 없다.
또 Three.js같은 3D 라이브러리를 사용하기 때문에 렌더링 성능이 굉장히 중요하다.
그래서 상태 관리 라이브러리도 최대한 가벼운 것으로 선택하여 애플리케이션 성능에 주는 영향을 줄이고자 했다.


출처: npm trends

npm trends에서 검색한 상태관리 라이브러리 최근 1년간 다운로드 수이다.
우리 팀은 이 5개의 라이브러리를 후보로 두고 고민을 시작했다.

각자가 모두 다른 특성을 갖고있지만, 이 5가지는 상태 관리 유형에 따라 크게 3가지로 분류할 수 있다.
이들의 특징을 간단하게 알아보자.

🍞 상태 관리 유형 분류

1. Flux 방식

Redux, Zustand가 이 유형에 속한다.
이 유형은 Flux 아키텍처 모델을 기반으로 하는 중앙 집중식 상태 관리 솔루션이다.
Flux 패턴에서 데이터는 단방향으로 흐른다.

출처: https://haruair.github.io/flux/docs/overview.html

Action이 발생하면, Dispatcher에서 이를 해석한 후 Store에 저장된 정보를 갱신하고, 그 결과가 다시 View로 전달된다.

이 유형은 상태를 한 곳에 모아 관리하고 싶을 때 적합하다.
하지만 상태를 중앙 집중화하기 때문에 상태 업데이트가 많거나 복잡할 경우 성능 문제가 발생할 수 있다.


2. Proxy 방식

MobX가 이 유형에 속한다.
이 유형은 상태를 프록시 객체로 래핑한다.
그래서 직접 객체를 다루지 않고, 프록시를 통해 작업을 수행하게 된다.
이 특성 덕분에 중첩된 객체의 상태 관리에 유용하다.
일반적으로 중첩된 객체의 상태를 관리하려면 상태를 복사하고, 속성을 수정하고, 수정한 상태를 다시 덮어쓰는 과정이 필요하다.
하지만 여기서는 프록시를 통해 상태를 직접 변경할 수 있기에 중첩 객체 상태 관리가 훨씬 수월하다.

하지만 상태를 직접 변경하는 방식을 사용하기 때문에 오히려 불변성을 엄격하게 지키는 것이 어려워질 수도 있다.
또 프록시 개념에 익숙하지 않다면 다루기 어려울 수 있고, 특히 디버깅에 어려움을 겪을 수 있다.

그리고 이 유형은 객체지향 프로그래밍과 잘 맞다.
물론 함수형 프로그래밍과 함께 사용할 수 있긴 하지만, 이들의 핵심 원칙과 기능은 객체 지향 프로그래밍의 원칙과 더 잘 어울린다.


3. Atomic 방식

Recoil, Jotai가 이 유형에 속한다.
이 유형은 전체 상태를 원자 (Atom)으로 나누는 것을 추구한다.
원자는 업데이트 가능하고 구독 가능한 상태의 단위이며, 이들은 서로 다른 부분에서 독립적으로 사용된다.
때문에 상태 관리의 모듈화가 쉽고, 코드의 재사용성이 높아진다.
하지만 상태가 단순하고 재사용의 필요성이 낮을 경우, 이 모델을 사용했을 때 오히려 더 복잡해질 수 있다.


4. 우리의 선택

이러한 특징들을 고려했을 때, 우린 먼저 Proxy 방식을 1차로 탈락시켰다.
프로젝트 특성상 중첩된 객체가 많을 것 같지도 않았고, 결정적으로는 객체지향 친화적이라는 점이 마음에 들지 않았다.
물론 함수형 프로그래밍 방식에도 충분히 적용할 수 있다.
하지만 그렇게 하면서까지 이 유형을 써야 할 필요성을 느끼지 못했다.

남은 것은 Flux 방식과 Atomic 방식이다.
이 둘의 가장 큰 차이점은 상태를 관리하는 방식이다.
Flux 방식은 모든 상태를 한 곳에서 관리한다.
여러 컴포넌트에서 공유되는 상태를 관리하는 데 효과적이다.
Atomic 방식은 각 상태를 각각 다른 곳에서 독립적으로 사용하고 관리한다.
상태의 모듈화와 재사용성이 중요할 경우 사용하면 좋다.

우리 프로젝트의 경우 그렇게 복잡하거나 관리할 상태가 많지 않다.
굳이 상태를 작은 단위로 쪼개서 관리할 필요까지는 없다고 판단했다.
그래서 일단은 Flux 방식 쪽으로 마음이 더 기울었다.

그래도 Flux 방식 라이브러리 하나, Atomic 방식 라이브러리 하나를 골라 비교해보기로 했다.


🍞 Redux vs Zustand

Flux 방식에 속하는 Redux와 Zustand를 비교해보자.
먼저 아까 봤던 npm trends 자료를 보면 Redux의 다운로드 수가 압도적으로 높다..

출처: npm trends

하지만 Redux는 다른 라이브러리들에 비해 학습곡선이 가파르다.
짧은 기간동안 프로젝트를 진행하는 우리 상황에서, 배워야 할 내용과 작성해야 할 코드가 많은 Redux는 적합하지 않다고 판단했다.
또 간단한 프로젝트에 무겁고 복잡한 Redux를 쓰는 것은 '굳이?'라는 생각이 들었다.
더 깊게 생각할 것도 없이 Redux는 후보에서 제외해버렸다.


🍞 Recoil vs Jotai

Atomic 방식에 속하는 Recoil과 Jotai를 비교해보자.
Recoil은 Facebook에서 개발한 상태 관리 라이브러리이다.
Jotai는 Recoil의 Atomic 패턴에서 영감을 받아 만든 라이브러리라고 한다.
그래서 둘의 사용 방식이 상당히 비슷하다.

결론적으로는 Jotai가 더 낫다고 판단했다.
첫 번째 이유는 번들 사이즈 차이이다.
Jotai는 830kb, Recoil은 2.17mb로 꽤나 큰 차이가 난다.

또한 활발한 업데이트가 이루어지고 있는 Jotai에 비해 Recoil은 업데이트가 많이 더딘 편이다.

이외에 몇 가지의 차이점이 있었지만, 결과적으로는 Recoil보다 Jotai가 훨씬 단순하며 가볍다는 사실 때문에 Jotai를 선택하게 되었다.
둘의 사용 방식에 큰 차이가 없기 때문에 어떤 라이브러리가 더 간단한 상태 관리에 적합한지에 포커스를 두고 고민했다.


🍞 Zustand vs Jotai

마지막으로 이 둘을 비교해서 최종 결정을 하기로 했다.
본격적으로 비교해보자.

Zustand와 Jotai의 기술적 차이가 궁금하다면 아래 내용을 읽어보는 것을 추천한다.
https://github.com/pmndrs/jotai/issues/13

1. 다운로드 수

먼저 npm trends 다운로드 수를 다시 보자.
여기서 Redux는 제외했다.

출처: npm trends

다운로드 수는 Zustand가 압도적이다.
새 라이브러리를 학습하는 우리의 입장에서는, 사용자가 많을수록 학습자료가 많을 것이기에 장점으로 느껴졌다.

2. 번들 사이즈

Zustand는 187kb, Jotai는 830kb이다.
Zustand가 훨씬 가볍다는 것을 알 수 있다.

3. Provider 사용 유무

Jotai는 보통 Provider로 애플리케이션을 감싸야 하는 반면, Zustand는 Provider를 사용할 필요가 없다.
사실 이 부분은 양쪽 모두 장단점이 있기 때문에, 확실한 장점이라고 할 수는 없겠다.

4. Vanilla JS 지원 여부

Jotai는 React만 지원하지만 Zustand는 Vanilla JS도 지원한다.
하지만 우리는 React를 사용하기 때문에 이 부분도 큰 장점으로 다가오지는 않는다.

5. 상태 관리 방식

가장 큰 차이점이다.
사실 위의 내용들보다는 이 부분이 가장 중요한 것 같다.
Zustand는 중앙집중화된 하나의 store 안에 여러 상태들이 담기는 반면, Jotai는 각각의 상태가 atom 형식으로 흩어져 있다.
Top-down 방식과, Bottom-up의 차이이다.

위에서 언급했듯이 우리의 프로젝트에서는 상태를 여러 곳에서 관리하는 Atomic보다는 한 곳에서 관리하는 Flux 방식이 더 맞다고 생각했다.

그리고 이런 논리적인 이유들을 떠나서, 팀원 모두 Flux 방식의 라이브러리 사용 경험이 없었기 때문에 Zustand가 더 매력적으로 느껴지기도 했다.




결론적으로 우리는 Zustand를 사용하기로 했다.

이 글에서는 각각의 라이브러리 특성을 깊게 공부하기보다는, 라이브러리 간 차이점을 중심으로 비교해보는 시간을 가졌다.
비교되는 두 라이브러리 모두 가지고 있는 기능이나, 우리 프로젝트와 크게 관련 없는 기능 중에는 아예 언급하지 않은 것들도 있다.
더 깊게 알아보고싶은 라이브러리가 있다면 공식문서를 통해 공부해보는 것을 추천한다.

참고자료

post-custom-banner

14개의 댓글

comment-user-thumbnail
2023년 11월 12일

이유를 가지고 라이브러리를 선택한다는 점이 인상깊네요!!
보통의 팀 규모의 프로젝트에서는 개인의 선호로 인해 라이브러리가 선택되는 경우가 많은데 적절한 이유를 들어 조사를 하신점이 멋지네요! 응원합니다!!

1개의 답글
comment-user-thumbnail
2023년 11월 12일

Zustand는 로고가 귀여워요 🐻

1개의 답글
comment-user-thumbnail
2023년 11월 12일

키야 많이 알아보셨네요 역시 울팀 리더

1개의 답글
comment-user-thumbnail
2023년 11월 17일

상태관리 라이브러리를 관성적으로 쓰게 되는데 많이 깨닫고 갑니다 ㅎㅎ.. Zustand가 Vanilla JS 서포팅하는건 좀 신기하네요..!

1개의 답글
comment-user-thumbnail
2023년 11월 17일

왜 상태관리에 Zustand를 사용했냐는 질문을 준비하고 계신 분들은 이 글을 읽으면 될 정도로 정리가 잘 되어 있네요!👍

1개의 답글
comment-user-thumbnail
2023년 11월 21일

중앙화된 스토어에 플럭스 패턴, 쉬운 사용법은 리덕스 툴킷에도 포함되는 내용인데요?

다만, 프레임워크 문법이 훨씬 쉽다는 점에서 많은 뉴비들이 선택하기에 좋을 것 같습니다.
persist같은 옵션도 있으니 나중에 사용해보세요.
https://velog.io/@yunsungyang-omc/Zustand-%EA%B0%84%EB%8B%A8%ED%95%98%EA%B2%8C-Zustand-%EC%A0%81%EC%9A%A9%ED%95%B4%EB%B3%B4%EA%B8%B0
굳이 따지자면, 서버 상태를 관리해주는 라이브러리의 등장으로 클라이언트 사이드의 상태관리 포션이 많이 줄은게 사실이고 경우에 따라서는 상태관리도 컨텍스트나 리듀서로도 충분히 관리할 수 있다고도 생각해요

1개의 답글
comment-user-thumbnail
2023년 11월 23일

react를 사용하면서 상태관리에 대한 복잡함과 어려움을 경험하고 상태관리 라이브러리를 알아보고 있었는데 정리가 잘 되어 있어서 너무 도움이되었습니다!
프로젝트의 규모와 특성을 고려하여 라이브러리를 선택하고 장단점을 비교하시는 부분들에서 배울 것이 많았네요.

답글 달기
comment-user-thumbnail
2023년 11월 24일

그룹 프로젝트를 진행하는 과정에서 저는 경험이 많지 않아 대표적으로 많이 언급되는 Redux와 Recoil 중 러닝 커브가 낮은 Recoil을 선택했는데, 조금 더 생각봐도 좋았을 것 같다는 생각이 드는 글이었습니다. 좋은 글 감사합니다! 추후 상태관리 라이브러리 선택에 있어서 참고하겠습니다 :)

답글 달기