先日、新卒で入ったエンジニアが 「Immutable.jsの研修課題をやってるんですけど、正直なんで必要なのか分かんないっす」 と言っていた。
たしかに React, Redux と Immutable.js をセットでつかおうみたいなノリの記事はネットでよく見るが、じゃあなんでそのセットなの?という点に関してはあまり詳しく書かれていないことのが多い気がしたので、個人的にその理由っぽいのを雑に書き残しておこうと思う。
イミュータビリティのいいとこ
- コーディング・バグを減らす
- 言語仕様上ミュータブルな JavaScript は、大勢で開発してるとこっそりどこかで参照を持ったオブジェクトを書き換えてた、なんてことになりやすい。なのでデータを更新する際にはイミュータブルであることが保証できるとバグが起こりにくいコードを書ける
- メモリ効率がいい
- イミュータブルなオブジェクトは中身が同じなのでコピーが参照のみになり、実行時のメモリ効率がよくなる
- 参照がコピーされるだけなので、例えばコレクションの比較も実質 O(1) になるので速い
- 地味にWikipediaのイミュータブルのページが充実した内容で参考になる
ReactとRedux
- 仕様的に React+Redux 自体がイミュータビリティを期待したものになっている
- React が Unidirectional なデータの流れ方をする
- コンポーネントの中で明示的に
setState
が呼ばれて初めてビューの更新が予約される。 - この更新はミュータブルなステートの部分更新などではなく、新しいステートを丸ごと与える。
- コンポーネントの中で明示的に
- Redux が関数型アプローチ
- React 界のFlux実装のデファクトスタンダードこと Redux はステートの変更を純粋関数で行う
- 変更を行う Reducer が React のステート更新と同様に既存のステートから新しいステートを返す(イミュータブル)
- この辺の前提に加えて、ES6だけで更新処理周りのコードを書いていると、スプレッド演算子&
Object.assign
まみれになるところが、Immutable.jsでスマートに書けたりする。- 最近のバージョンでは TypeScript と組み合わせたトランスパイル時のチェックもそこそこいい感じになってきている
他の一部フレームワークとの相性
- Vue.js で Vuex に載せるデータを Immutable.js のコレクションにしたら微妙だった
- そもそも Vuex 自体がステートをミュータブルで持つので、どこがミュータブルでどこがイミュータブルなのかを気をつけないと意図しない挙動が起きることがあった
- そもそも Vue.js では
Object.defineProperty
と呼ばれる更新検知の機構を使って効率的にオブジェクトの更新を検知しているので、逆に Immutable.js を使わないほうがパフォーマンス的にもよくなる気がするし、むしろ使うべきじゃなかったと思っている。
- Boost the Performance of an AngularJS Application Using Immutable Data · Minko Gechev's blog
- ちょっと古いが Immutable.js を AngularJS と使った人の記事
- AngularJS は Digest Loop の中で scope オブジェクト間の差分チェックをして、もし差分があればそれをビューに適用していく仕組みになっている。これがコレクションになると O(n) になるが、 Immutable.js を使うとコレクション比較が実質 O(1) なのでパフォーマンスが向上する。
- この作者は
immutable
というディレクティブを自作したらしいが、 AngularJS 組み込みの filter ディレクティブなどとの相性が悪いらしく率直に言って使いづらそうだ。
- Immutable.js は JS のプレーン・オブジェクトへ変換する処理のオーバーヘッドがそこそこデカいので、ユースケース上ここがボトルネックになってくるとどのフレームワークと組み合わせていてもイミュータビリティが破綻し始める感がある。
- Wantedly People のフロントエンドを作ってる人がこのつらみをどこかで書いていた気がする
- JavaScriptにおけるコレクション(というか配列)操作についての計算量はここに書いた izumisy.work
まとめ
- React と Redux 自体がそもそもイミュータビリティとの相性がいいフレームワークになっているという印象。他のフレームワークだと場合によっては微妙。 React+Redux でやるなら Immutable.js は入れておいて損がないよ、と言われる理由はだいたいこんなもんかな。
- 余談だが Redux に影響を与えたと言われる Elm は全ての関数が最初からイミュータブル。もはや言語レベルでこうなっているのは結構嬉しかったりする(チームでコンセンサスを得る必要がなかったりするから)
- 最近では Immer という Immutable.js オルタナティブが出たらしい。パット見ではコレクション系のクラスっぽいものがなくAPIが非常にシンプルという印象。こっちも要チェックっぽい。
- おそらくイミュータブルの概念を理解するにあたってはガベージコレクションなどのメモリに関する知識と、データに対する計算量などのアルゴリズム的な知識のふたつが必要になるのではないかと思う。アルゴリズムについて学ぶにあたっては、やはり「アルゴリズムとデータ構造」が一番おすすめであると言える。

- 作者:Richard Jones,Antony Hosking,Eliot Moss
- 発売日: 2016/03/15
- メディア: 大型本