JavaScriptおれおれAdvent Calendar 2014 – 18日目分
あとから更新。
JSオジサンでお話してきた内容です。というか、先月JSConf.Asiaでもお話してきた内容ですね。
スライド
こちらご覧ください。
つらいアプリ実装の例
カラーピッカーの実装を考えます。
実装
要素はご覧のとおり、四つ。
- プレビュー
- カラーマップ(クリックで色を選択できる)
- 数値入力欄
- スライダー
それぞれ現在選択中の色の値を表現します。またプレビュー以外は色を変更する事ができます。
カラーマップは以下の実装が必要ですね。
- カラーマップをクリックしたら、
- プレビューを更新
- カラーマップ自身を更新
- 数値入力欄を更新
- スライダーを更新
他も同様です。
- 数値入力欄で入力したら、
- プレビューを更新
- カラーマップを更新
- 数値入力欄自身を更新(HTMLは勝手に反映されるけど)
- スライダーを更新
- スライダーを動かしたら、
- プレビューを更新
- カラーマップを更新
- 数値入力欄を更新
- スライダー自身を更新(HTMLは勝手に反映されるけど)
……ううむ、大変そうですね。仕様が追加された日には大変な事になりそうですね。
仕様を追加
とか言ってるうちに、追加仕様が送られてきました。「押すと一発でおすすめの赤色に設定するボタン」が欲しいのだそうです。またその色が選択されている間、ボタンも活性化させ、選択状態(枠を太くするとか?)にします。
- 赤ボタンを押すと、
- プレビューを更新
- カラーマップを更新
- 数値入力欄を更新
- スライダーを更新
- 赤ボタン自身を更新
他のUIから変更した場合も、赤ボタンの選択状態を更新するため、以下の実装を追加する必要があります。
- カラーマップをクリックしたら、
- 赤ボタンを更新
- 数値入力欄で入力したら、
- 赤ボタンを更新
- スライダーを動かしたら、
- 赤ボタンを更新
あ、つらい。 (´ω`)
さらに仕様を追加
さらにおすすめの赤の他、おすすめの緑、おすすめの青も一発で設定できるようにしたいそうです。
あ、しにたい。 :(´ω`):
ModelとViewに分けて幸せになろう
幸せの壺を買うのも良いですが、幸せな設計を考える方が現実的かと思います。
世界を二つに分けます。すなわち、データ = ModelとUI = Viewです。
今度は二つの世界がある前提で、実装を考えます。
データの更新
カラーマップをクリックした際、その結果はModelに保存します。カラーマップViewの仕事は、そこで終わりです。ここで実装するカラーマップ側の機能は、選択値をModelへ保存するだけで、UI更新は行いません。
このように、データを更新してこの段階での仕事は終わりです。ではUI更新はどうするかというと、次の段階で行います。
UIの更新
画面の更新は利用者操作ではなく、データ変更を要因とします。つまり「データが更新されたから、それに合わせて画面も更新する」という事です。
強調しますが、あくまでデータ更新に起因する画面の更新であり、利用者の操作は(直接は)関係ありません。
二つの世界
認知しやすい
こうやって分けておくと、「操作してデータ更新」のパターンが増えたとしても大して恐れる事はありません。そこの単位での責務は、ただデータを更新するだけですから。また「データ表示のパターン」が増えた場合も同様です。
線が増えても「右向き」「左向き」の二種類だけになり、管理も楽かと思います。
仕様追加に強い
はず。
今回は「カラーピッカー」という、いかにもひとつのモジュールっぽい画面ですが、モジュール同士の連携になった場合も役立ちます。
例えば「よくあるタブ」も、View「タブUI」とModel「タブ情報データ」に分割できます。そこへ後から「タブの選択に合わせて他の場所の表示を変える」という仕様を追加したとしても、恐れる事はありません。追加UIはModelを監視し、変更があればそれを自身に反映させるだけです。
課題は紐づけ
便利そうに見えますが、やはり銀の弾丸たり得ません。
ModelとViewを紐づけ管理する存在が必要になります。そこでどう管理するのか、とかそこら辺がまた悩みどころです。
MVCであればC=Controllerがその役割を負うのかな。MVCは(その定義がよくわからないので)よくわからないや。Reactだとそのあたりがひとまとめになって、Reactオブジェクト(?)を構成している風。
ライブラリー
おまけ。
Backbone.JSと自作ライブラリー
このModelとViewに分ける実装は、とりあえずBackbone.JSを利用すると簡単です。ライブラリーが小さく実装範囲が薄いので自分でやってる感ありますし。
で、もっと薄くて小さいBackbone.JS互換のModel-Viewライブラリーを作りました。
現在はminifyして19行の1.0 KBです。もし興味あればどうぞ。