この記事は 仮想DOM/Flux Advent Calendar 2015 2日目の記事です。
みなさんFlux書いてますか?
僕はオレオレ実装を書き続けて消耗してます。
Fluxフレームワーク使いたいけど使いたくない……!!
いったい今Fluxフレームワークって幾つ生き残ってるの……戦争は終わったの?
っていうか最近新フレームワークの噂聞かないけど、まだFluxって流行ってるの?
今日はその辺をまとめてみたいと思います。
もくじ
前提知識
Fluxってなに?という方はこちらの資料をみると良いでしょう。
非常に丁寧にまとめられています。
なお、以下ではアーキテクチャについては Flux
、Facebook による提案実装に付いては facebook/flux
と表記します。
Flux以前
Flux が登場した背景には、React の大流行の影響が大きいでしょう。
React のおかげで、クライアントサイドでもサーバサイドと同じく「データ変更の度に Viewを全て描き直す」という構成がとれるようになりました。
ただし、React はあくまで View ライブラリであり、アプリケーション全体の構成についてはユーザーに委ねられています。
多くのユーザーは React を既存のフレームワークと組み合わせて利用していましたが、次第に React の性質に合ったより新しい設計指針が求められるようになりました。
なお、Flux の登場に影響を与えたかは不明ですが、Flux 以前にも React を用いた Om というフレームワークが存在していました。
v0.1.0 は 2014/01/04 にリリースされています。
Om は ClojureScript 製のフレームワークであり、開発も ClojureScript で行います。
アプリケーション全体の状態を一つの immutable な state として持ち、View は cursor を通じて state を参照するという構造になっています。
売り文句としては「immutable なデータを用いることで高速に動作する」「Undo/Redo のできるWebアプリが簡単に書ける」などと言われていました。
つい最近も Om について触れた翻訳記事が出ていましたね。
Om の思想は後のFluxフレームワークの幾つかに影響を与えています。
2014年5月 Flux登場
Flux
という言葉が初めて登場したのは、2014-05-08 に行われた Facebook F8 のセッションでの事でした。
Facebook のエンジニアである Jing Chen 氏は、従来のMVCアプリケーションにおいて規模が大きくなるにつれてしまう問題について説明し、その解決策として Flux を提唱します。
当初は「既存のMVCそのものだ」「また新しいバズワードか……」といった批判的/懐疑的な意見も多かったですね。
↓の記事では、Reddit における Jing Chen 氏らの議論がまとめられています。
人によって理解が異なる「MVC」を避け、データの流れを一方向に強制して新しい名前をつけた、という感じでしょうか。
Flux はアーキテクチャに過ぎませんが、参考実装が facebook/react の example として公開され、後に facebook/flux に移管されました。
初期の実装を見ると Dispatcher が Promise ベースの素朴な感じで面白いです。
https://github.com/facebook/react/commit/85339bfdae5cd622fb97dc8c681376ba24e847da
〜2015年前半 戦国時代
インターネットのみんなはフレームワークが大好き。
というわけで、早速 Flux 実装大会が始まりました。
今回は↓のまとめ記事を参考に当時のFluxフレームワークについて調べてみました。
(まとめ記事ですら多すぎる……)
http://pixelhunter.me/post/110248593059/flux-solutions-compared-by-example https://github.com/kriasoft/react-starter-kit/issues/22 https://github.com/voronianski/flux-comparison https://reactjsnews.com/the-state-of-flux/
今回は以下のフレームワークを紹介します。
- Fluxxor
- Fluxible
- NuclearJS
- Alt
一応こちらに今回の調査した全フレームワークのメモを置いておきます。
大変だった……。
Fluxxor
今回調べた中で最も初期に開発されたのが Fluxxor です。
なんと first commit は 2014/05/12 でした。
F8 のセッションから4日しか経ってない!
Fluxxor は登場が早かったこともあり、日本語でもそれなりに情報が見つかると思います。
僕も去年 Virtual DOM アドベントカレンダーで解説記事を書きました。
Fluxxor では Store を Fluxxor.createStore
で作成し、const flux = Fluxxor.Flux(stores, actions);
で flux オブジェクトを作成します。
Actions は this.dispatch()
を呼ぶ関数のハッシュです。
Fluxxor の特徴は mixin を利用した機能です。
FluxMixin, StoreWatchMixin を利用して、Component から Store や Action を参照しやすくする、というものでした。
その後、React v0.13 で ES6 Class*1 がサポートされ、Babel の流行により 皆 ES6 Class でコンポーネントを書くようになりました。
現在では React.createClass()
+ mixinを使った機能はちょっと使いづらくなってしまいましたね。
Fluxxor は facebook/flux からの乖離もほとんど無く、ボイラープレート的なコードを無くすことを目的としたものでした。
他にも McFly など、facebook/flux との互換性やシンプルさを売りにするフレームワークはありましたが、一方で Dispatcherをなくしたり独自の概念を導入するなど、よりよいアーキテクチャを模索するフレームワークが沢山生まれてきました。
Fluxxorの「Store, Actions への参照をもつ flux
オブジェクトを作成し Component に渡す」という方針は、後のライブラリにも受け継がれています。
Fluxible
Fluxible はあの Yahoo が開発しているフレームワークです。
first commit は 2014/10/29 ですが、既に Yahoo の幾つかのサービスで本番稼働しているようです。
Fluxible は Isomorphic なアプリケーションを作成しやすい点をウリにしています。
Isomorphic なアプリケーションには、サーバサイドで描画した時のアプリケーションの状態をクライアントサイドで再現する為の Dehydrate/Rehydrate という仕組みが必要なのですが、Fluxible はこれを公開当初からサポートしていました。
また、fetcher や router は別パッケージに切り出されており、Yahoo 製の物以外を組み合わせて使うこともできるプラガブルな設計になっています。
Isomorphic アプリケーションについてはこちらのスライドが参考になります。
https://speakerdeck.com/koichik/isomorphic-survival-guide
Isomorphic は React と共に盛り上がってきた設計思想ですが、Fluxフレームワークにも Isomorphic 性を重視する物が多く存在します。
Alt
Alt はAirbnbのエンジニアによって開発されたフレームワークです。
コミットログによると 2014/12/11 に開発が開始しています。
Alt のアーキテクチャは facebook/flux を踏襲したものですが、Dehydrate/Rehydrate に対応したり、Promise ベースの非同期 Action、ボイラープレート的なコード量の削減など、いくつかの改善を行っています。
中でも特徴的なのは Snapshot 機能でしょうか。
Alt では Alt
クラスのインスタンスを作成し、そのメソッドを呼ぶ事で Store, ActionCreator を定義します。
import Alt from 'alt'; const alt = new Alt(); class FooStoreClass { // ... } const FooStore = alt.createStore(class {}, 'FooStore');
この時、alt
内部では全ての Store への参照を保持しています。
そのため、Store の状態をまとめて保存することで、その時のアプリケーション全体の状態を簡単に保存できます。
Alt は Snapshot を活用し、Flush, Recycle, Rollback 等の API が実装されています。
これらを使うことで、Undo/Redo 機能をもったアプリケーションなどが簡単に作成できます。
Time traveling と呼ばれることもあるみたいですね。
Snapshot 機能をもつ Fluxフレームワークは Om に通じるところがあるのではないでしょうか。
NuclearJS
NuclearJS は Om の影響を全面に打ち出しているフレームワークです。
first commit は 2014/09/10 と、割と早い時期に登場しました。
NuclearJSはOmに倣い、アプリケーション全体の state を全て immutable-js の Map に保存します。
Store 毎に state を保存するのではなく、Store はこの state の一部分を受け取り、新しい state を返す Action のハンドラを登録する役割を持ちます。
Store 内の処理や依存関係により state が 滅茶苦茶になるのを避けられる、というのがなんとなく想像できるでしょうか。
また、この state を保存すれば Snapshot も簡単にできる、というのは Om 同様ですね。
また、Om は state そのものではなく、state の一部を取り出すための Cursor を定義して View に渡すのですが、NuclearJS は Cursor に相当する Getter を定義して使います。
facebook/flux では複数の Store の依存関係を waitFor で管理するのですが、Store の関係がわかりづらいという問題がありました。
Getter では state 内の値そのままではなく、state 内の任意のデータから計算した値を返すことができるため、依存の問題を回避しやすくなっています。
一枚の巨大なオブジェクトにアプリケーション全体の状態を保存するといった考え方は、後の microcosm や Redux につながっていきます。
振り返り
Fluxフレームワークの開発者は facebook/flux の実装、アーキテクチャに問題を見出し、それを解決する方法として独自フレームワークを提案してきました。
↑で取り上げたフレームワークは
- ボイラープレートコードの削減
- Isomorphic
- Snapshot & Time traveling
- 一枚の巨大な state (Single source of truth)
をテーマに発展して行きました。
2015/5月 Reduxの登場
Redux は ReactEurope の発表の為に Proof of Concept として作成されたものです。
first commit は 2015/05/30。
リポジトリの公開と同時に、開発に至るまでの考え方の変化を丁寧に解説したブログ記事が公開されました。
Redux のアーキテクチャは、一枚の巨大な state や Time traveling など、それまでのFluxフレームワークで浮かび上がってきた概念をまとめたものになっています。
その全体像は、しばしばElmにおける Model-View-Update
アーキテクチャに喩えられます。
(Elm を念頭に置いて作られたわけではないようですが、作ってみたらなんか似てた、と Abramov 氏は語っていました)
2015年7月 ReactEurope で行われた Hot Reloading & Time traveling デモや、前述のブログ記事の衝撃は大きく、Redux はものすごい勢いで流行しました。
Flummox や fluce, marty.js といった Flux 実装の README には「Redux を使え」と書かれるほどです。
"The best dev stack" を標榜するプロジェクトボイラープレートの Este.jsでも採用されてました。
日本でもブログや Qiita 投稿も多く、流行ってるっぽいですね。
某有名コミックビューアなどでも使われてるみたいです。
戦国乱世となっていた Flux 界隈ですが、Redux の大流行以降はある程度平穏を取り戻したように見えます。
前半まとめ
本記事では、2015年前半までのFluxフレームワークの流行を駆け足で追ってみました。
後半では、Redux までの流れが Flux 界隈や周囲に及ぼした影響、及び対抗勢力について探ってみたいと思います。
*1:ここではReact v0.13のリリースノートに合わせ「ES6 Class」と表記しています。「ES2015 Class」の方が正確です