JavaScriptおれおれAdvent Calendar 2014 – 18日目分

あとから更新。

JSオジサンでお話してきた内容です。というか、先月JSConf.Asiaでもお話してきた内容ですね。

be-happy
みんなで幸せになろうよ。

スライド

こちらご覧ください。

つらいアプリ実装の例

カラーピッカーの実装を考えます。

よくあるカラーピッカーUI。

実装

要素はご覧のとおり、四つ。

  • プレビュー
  • カラーマップ(クリックで色を選択できる)
  • 数値入力欄
  • スライダー

それぞれ現在選択中の色の値を表現します。またプレビュー以外は色を変更する事ができます。

カラーマップは以下の実装が必要ですね。

  • カラーマップをクリックしたら、
    • プレビューを更新
    • カラーマップ自身を更新
    • 数値入力欄を更新
    • スライダーを更新

カラーマップクリック時の処理。

他も同様です。

  • 数値入力欄で入力したら、
    • プレビューを更新
    • カラーマップを更新
    • 数値入力欄自身を更新(HTMLは勝手に反映されるけど)
    • スライダーを更新
  • スライダーを動かしたら、
    • プレビューを更新
    • カラーマップを更新
    • 数値入力欄を更新
    • スライダー自身を更新(HTMLは勝手に反映されるけど)

各UIの処理

……ううむ、大変そうですね。仕様が追加された日には大変な事になりそうですね。

仕様を追加

とか言ってるうちに、追加仕様が送られてきました。「押すと一発でおすすめの赤色に設定するボタン」が欲しいのだそうです。またその色が選択されている間、ボタンも活性化させ、選択状態(枠を太くするとか?)にします。

  • 赤ボタンを押すと、
    • プレビューを更新
    • カラーマップを更新
    • 数値入力欄を更新
    • スライダーを更新
    • 赤ボタン自身を更新

他のUIから変更した場合も、赤ボタンの選択状態を更新するため、以下の実装を追加する必要があります。

  • カラーマップをクリックしたら、
    • 赤ボタンを更新
  • 数値入力欄で入力したら、
    • 赤ボタンを更新
  • スライダーを動かしたら、
    • 赤ボタンを更新

赤ボタンを実装した結果……

あ、つらい。 (´ω`)

さらに仕様を追加

さらにおすすめの赤の他、おすすめの緑、おすすめの青も一発で設定できるようにしたいそうです。

加えて青ボタン、緑ボタンを実装した結果………………

あ、しにたい。 :(´ω`):

ModelとViewに分けて幸せになろう

幸せの壺を買うのも良いですが、幸せな設計を考える方が現実的かと思います。

世界を二つに分けます。すなわち、データ = ModelとUI = Viewです。

スライド29
Modelの世界、Viewの世界。

今度は二つの世界がある前提で、実装を考えます。

データの更新

カラーマップをクリックした際、その結果はModelに保存します。カラーマップViewの仕事は、そこで終わりです。ここで実装するカラーマップ側の機能は、選択値をModelへ保存するだけで、UI更新は行いません。

カラーマップクリック時の処理、改訂版。

このように、データを更新してこの段階での仕事は終わりです。ではUI更新はどうするかというと、次の段階で行います。

UIの更新

画面の更新は利用者操作ではなく、データ変更を要因とします。つまり「データが更新されたから、それに合わせて画面も更新する」という事です。

データが更新されたときの処理。

強調しますが、あくまでデータ更新に起因する画面の更新であり、利用者の操作は(直接は)関係ありません。

二つの世界

Modelの世界とViewの世界、行き来するメッセージ。

認知しやすい

こうやって分けておくと、「操作してデータ更新」のパターンが増えたとしても大して恐れる事はありません。そこの単位での責務は、ただデータを更新するだけですから。また「データ表示のパターン」が増えた場合も同様です。

線が増えても「右向き」「左向き」の二種類だけになり、管理も楽かと思います。

仕様追加に強い

はず。

今回は「カラーピッカー」という、いかにもひとつのモジュールっぽい画面ですが、モジュール同士の連携になった場合も役立ちます。

例えば「よくあるタブ」も、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です。もし興味あればどうぞ。