프론트엔드 애플리케이션 상태를 다루는 법

ㄹ @disjukr@hackers.pub
tweet: https://x.com/disjukr/status/1943312702266347805
시간에 따라 변화하는 의존 그래프를 관리하는걸 리액티브 프로그래밍이라고 부르는데, 각 노드를 해당 노드의 시간축으로 바라봤을 때 어떻게 생겼는지에 대해 관심을 두면 옵저버블이 나오고, 애플리케이션의 일순간 노드 의존관계의 단면이 어떻게 생겼는지에 대해 관심을 두면 시그널이 나온다.
프론트엔드 애플리케이션의 상태관리에는 옵저버블보다 시그널(+ 수명관리)이 적합한데, 왜냐면 프론트엔드 상태는 변하는 녀석들만 놓고 보면 시간축으로 봤을때 결정적인 것들(차가운 옵저버블)이 거의 없고, 반면 각 노드의 의존관계(특히 렌더트리)는 시간에 따라 변화무쌍하게 바뀌기 때문이다.
프론트엔드 애플리케이션의 상태를 옵저버블을 조합해서 표현하려는 유행도 있었고 (Rx) 전체 상태를 함수에다 집어넣고 다음 상태를 뽑아보자는 접근이 유행하기도 했고 (Redux) 상태기계를 쌓아서 표현해보자는 접근이 유행하기도 했는데 (XState)
각각이 미시적으로는 장점이 있지만 애플리케이션의 거시적인 구조를 표현하기에 적합한 구조는 아니라고 본다. 시그널(+ DI와 수명관리)을 통한 상태관리를 큰 틀로 잡아놓고 그 안에서 옵저버블, 리듀서, 스테이트머신을 사용하는게 각각의 장점을 최대한 뽑아낼 수 있는 구조라고 생각.
옵저버블은 결정적인 상태들을 많이 다룰 수 있을때 표현이 유려해지는 장점이 있다. 그래서 애니메이션 표현등에 제한적으로 쓰면 좋다. 리듀서는 커다란 직렬화 단위를 관리하기에 좋다. 페이지를 새로고침해도 상태가 남아야 하는 폼에 쓰면 좋다.
스테이트머신은 여러 상(Phase)이 존재하는 상태를 표현하기에 적합하다. 게임의 NPC 인공지능이나 지금 어떤 애니메이션을 재생할지를 표현할때 쓰면 좋다.
마지막으로 이런 것들을 시그널(+ DI 및 수명관리)로 묶어주면 전체 애플리케이션 상태를 있는 그대로 선언적으로 깔끔하게 다룰 수 있다.
시그널 옆에 계속 적은 (+ DI 및 수명관리)가 뭐냐면: https://github.com/disjukr/bunja