Redux 再考

今まで自分で作ったものが十数個、仕事で5社ぐらいの redux を見てきたので、その結果思うところを書く。

前提として、自分はエコシステムに乗るという意味で今では redux 肯定派だが、redux それ自身が過剰に抱えている複雑さはもっと分解されるべきだ、という立場。

Redux がうまく設計されているとどうなるか

  • 一貫した一つの設計論に従うので、考えることがなくなる
  • 難しさが廃されるのではなく、難しい部分が一箇所に集中する。React Component の末端では、何も考えることがなくなる。状態管理という難しい部分を作る人と、末端のコンポーネントのデザインに注力する人を分けられる。
  • 大規模になっても設計が破綻しにくい、というエンタープライズ向きな特性を持つ。が、その技術基盤は(静的)関数型由来の考えが多く、基礎設計や基盤理解にはハイスキルが要求され、需要と適用対象のミスマッチを感じることはある。結果として、そもそもハイスキルを前提として、大規模であることが自明な SPA 向きということになる

現実の Redux はどうなっているか

  • 「実際に起こること」は大したことがないが、「物事が起こる経路」が難しい。教える側とすると、関数型由来の概念ばかりで、説明するコストが高い。そもそも redux そのものが elm 由来で、 React 自体も関数型的 API デザインの傾向があり(不変性を根拠にした差分アルゴリズム)、 Redux はさらに過激に関数型由来の概念を必要とする(reducer という 実質 State Monad 的な何か, 副作用の分離、様々な関数合成、関数を返す関数、高階コンポーネント、etc...)
  • Middleware に何を使うかで、 redux ユーザー同士の非同期のノウハウは共有できず、分断されている(thunk, saga, steps, epic, no middleware)
  • 初学者にとって、 初期ボイラープレートが大仰で印象が悪い。巷にあふれるチュートリアルも、悪印象を助長するものが多い。ボトムアップに学ぶ人には、最終的な形態を最初に見せる必要はないと思うのだが…
  • 現実問題、「それ本当に redux が必要?」という問いに、答えを窮する採用事例が多い。React Native や Electron のような SPA ではわかりやすく必要と言えるが、普通のウェブサイトに大仰な Flux が登場しうるかは、局所的な複雑度がどれほどかによる
  • 静的関数型由来の概念が多いくせに、TypeScript / Flow での型付けが困難な API、という実用上の問題を抱えている(redux.combinerReducers)
  • サーバーサイドの人が使うと、DB 側のテーブル定義に従って reducer を分割しすぎる傾向がある。このせいで複数の reducer の中身を跨ぐ処理が書きづらい問題と相まって、結果として使いづらく感じる、という自滅傾向をよく見る。個人的には reducer は画面に対し一つで、あとで段階的に分割するほうがいいと思う
  • 他の Flux フレームワークはほぼ全滅したので、選択肢は実質 redux or 我流の 2 つしかないのが現実。エコシステムに乗る、採用と教育コストを下げる、Web の人間を ReactNative に耐えうる設計をできるようにトレーニングする、という点で、それ自体の必要性が薄いが redux を採用するというのは、実際ある。
  • SPAという技術そのものを目的にすると失敗する。ただ、あらゆるプロダクトチームは、自分たちのプロダクトに求めるUXを過大に設定する。だからこそ会社が興ってプロダクトがあるわけだが、外からは滑稽に見える。これは技術とビジネスの本質的な問題。

今後も主流であり得るのか

  • redux の作者でありオピニオンリーダーだった Dan Abramov は、現在 redux との距離を置いているように見える。React コアチームに近い、よりシンプルなものを、という立場になっている
  • 実務上優秀なライブラリと、普及させたい側にとって都合がいいライブラリは異なる。難しい概念を振り回す redux が React 側に疎まれてるんじゃないか、と感じることがある。例えば react-training 社の react-router が、簡単側に倒してAPI削りすぎて不興を買ってる
  • React 公式チーム的には HoC より render prop 推しで(New Context API の実装 example がそう)、 Dan Abramov もその気配がある。他に、GraphQL ライブラリの apollo の React バインディングなどの実装でも redux の関与を減らすような、それ自身で非同期や状態管理を行う render prop ベースの API が実現されており、 Redux 不要論の根拠の一つになっている
  • React v16 の New Context API そのものは Redux を倒すものではなく、むしろ Redux を効率的に実装するための手段なのだが、「状態をビューにマッピングする」という概念自体を再考する段階で、別のものが出てくる可能性もある
  • React v17 で React 自体が非同期処理の仕組みを持とうとしている(Suspense)が、非同期を簡単に書くためのツールとして使いたい側と、CPU パフォーマンスが良くないときのパフォーマンス向上に注力するための非同期というコアチームで、既にミスマッチがある。ただ非同期処理のやり方が固まってくると、 redux 側の設計指針も変わってくるだろう。
  • 現状 redux を超える React の設計論はないが、React v17 でContext, Suspense 込みで再考されるときに、新しい設計論がまたいくつか出てくるはず

React から見た Vue 周りのエコシステムについて

  • Vue は React 界隈で枯れた概念をコアチームに近い人たちが実装する傾向があり、良き二番煎じという振る舞いがうまい(Redux => Vuex, Next => Nuxt)。Facebook は基本的にコミュニティのライブラリを公認しない結果、エコシステムの主流が定まらずに混乱する傾向がある。特にルーター周辺。社内ではチームごとに好き勝手にやってる様子。
  • React / Redux の関数型的な不変性が厳しい世界からみると、Vue / Vuex の状態管理はかなり怠惰で弛緩しきってるように見える。学習には容易だがスケール時の不安がある。(みたいな話を @potato4d とした記憶がある)
  • ユーザー基盤から見ると、英語圏 vs 非英語圏という構図が見え隠れしている。本体周辺は英語ドキュメントがあるが、Vue の周辺ライブラリは中国語のドキュメント / Issue / バグ報告しかないことも多いのが、個人的に採用を躊躇う要素
  • React は難しいが一貫している(Simple)のに対し、 Vue はいろんなことが簡単にできるが一貫性がない(Easy)