前回、Backbone.Viewのソースを読みながら、UIの設計についてとりとめなく考えてみました。
UIの役割を担うオブジェクトの振る舞いは、極めてシンプルにまとめると:
- ユーザー入力による、DOMオブジェクトからのメッセージに対する応答
- アプリケーション内部の変化による、モデルオブジェクトからのメッセージに対する応答
- これらのメッセージに対する応答としての、DOMツリーの操作
の3つとなります。UIの設計は、この3つをいかに作るか、ということに注力することになりそうです。
Backbone.Viewでこの3つを実装しようとすると、1.についてはBackbone.View#eventsプロパティのハッシュテーブルが司令塔となります。そして、Viewオブジェクトのパブリックメソッドをコールバックとして定義すれば、完成です。2.については、モデルオブジェクトのメッセージをViewオブジェクトがlistenToすればOKです。
それぞれ、コールバックのbind/unbind(あるいはlisten/stopListen)の処理を考慮しなくてはなりません。が、前回Backbone.Viewプロットタイプの実装を眺めたとおり、1.については、Viewオブジェクトの初期化時・setElement時に、DOMエレメント<->コールバック間のbind, unbindを内部で行ってくれるのでアプリケーション側ではイベントのハッシュテーブルとコールバックだけを実装すればOK。2.についても、モデルオブジェクトのライフサイクルに合わせてBackbone.Eventsモジュールが自動的にstopListeningしてくれるので、これまたアプリではviewオブジェクトの初期化時にlistenToするだけでOK。
問題は3.です。
Backboneは、DOMツリーの操作について、一切関与しません。Backbone.View.prototype.renderはなにもしない関数です。なので、アプリケーション側でDOM操作をしなくてはなりません。テンプレートに関してもBackboneは一切関与しません。
このままだと、懸案が出てきます。大雑把に言うと、「DOMツリーの操作をするのに、新たなBackbone.Viewが必要になる」という点です。つまり、ユーザーの入力や、アプリケーションの内部変化に応じて、Viewをダイナミックに生成かつ操作する必要がでてくるのです。Backbone.jsにはその責務がありません。Backbone.jsはミニマルを志向するフレームワーク(どちらかというとモデルレイヤーとそのイベントハンドリングに重きを置いてる気がします)なので、Backboneと付き合う以上は、これはアプリケーション側の責務になります。このビューのオーケストレーションのロジックは、どこに書けば良いか?単にrenderメソッド内でjQueryのapiを駆使しDOMツリーを操作したり、ほかのviewインスタンスを生成する処理を実装し、view同士で分担してDOM操作をする、といったやり方が考えられます。アプリケーションで独自の設計方針を立てなければ、コードのメンテナンスが複雑になる恐れが出てきます。
テンプレートについても考慮が必要です。BackboneはViewの設計と同じく、テンプレートの設計はアプリケーションに全てを委ねています。DOMエレメントに求められる役割が大きくなるにつれて、テンプレートとロジックの書き方にもアプリ側に工夫が求められると考えられます。
話がそれますが、Railsに代表されるサーバーサイドのアプリケーションの設計思想に、ビューとビジネスロジックの分離があります。サーバーサイドのアプリケーションには、当然のことながら、DOMのストラクチャーの操作をする責務がないので、DOMは、アプリケーションの扱うデータの、単なる表現型の1つと捉えられるからです。非同期的なユーザーアクションの要請に応える必要もないので、設計はモデルレイヤーに重きが置かれます。しかし、今問題としているのはDOMストラクチャーの振る舞いの設計です。単なる静的なデータ表現型ではなく、DOMをダイナミックに「動かす」設計が求められるのです。テンプレートにロジックを入れられる、そのようなフレームワークが必要になってきそうです。
この要請に応えるためには、ビューとロジックの分離というサーバーサイド的な思想を一旦クリアし、新たな思想で設計をしたほうがいいんじゃないか、、、ということなのかもしれません。
* * *
前置きがすごく長くなりましたが、これから紹介したいRivets.jsは、軽量な、データバインドとテンプレートとを統合したフレームワークです。Backbone.jsのように、イベント駆動型のモデルレイヤーと相性が良く、さらにフレームワーク非依存なので、モデルの設計に関わらず、データバインディングとテンプレートを統合することができる、、、ということが公式サイトの冒頭に書かれています。
なぜRivets.jsなのか?なぜ、僕が今、Rivets.jsにコミットするのか?
・・・あまり確固とした根拠はありません。強いて言えば、ドキュメントが非常にシンプルでわかりやすかった。そして、Backbone.jsと同様、開発者がとてもcoolである(公式サイトからもその雰囲気が伝わって来る)、少なくともホットでない、冷静な感じがする。欲や流行(フレームワークって、どうしても機能が肥大化しがちなので)に流されず、コードに求められる「責務」をしっかり認識している感じがするんです。
そして何よりもソースコードがcoffeeで書かれている、という点。読みやすいです、coffeescript。curly brace「{」がないだけで、こんなにも視認性が高まるのかと、感心してしまいます。フレームワークが何を意図しているかが、わかりやすく伝わってきます。信頼がもてるのです。
あああ、、結局Rivets.jsについてはほとんど語ることができなかった。新たな記事で、Rivets.jsについて踏み込んでいきたいと思います。See you!