Backbone.js(http://documentcloud.github.com/backbone/)を2,3ヶ月触ってみて、導入して良かったことをまとめます。
Backbone.js単体での威力はそこまでではないかもしれませんが、Server側も含めた設計思想を絡めて考えると大きな効果が期待できます(サーバー側も含めた構造改革が全体的に必要になるとは思いますが・・・)。
Rails単体で作成している場合、Viewにロジックが入れられない以上、 そのViewで必要な変数などは、全てControllerに書く必要がありました。
この状態では、ControllerがViewによって処理内容を変更する必要があり、結合強度が高くなってしまっていました。
このため、HTMLをレンダリングするためのControllerと、iPhoneなどでJSONを返すAPI的なControllerは分ける必要がありました。
これは、『DRYじゃないし、FatControllerになってしまって気持ち悪い』ということになりました。
そこで、ControllerとViewの1対1対応を割けるために、ajaxを導入し、 1つのViewをレンダリングするために、複数のAPIを叩くような構成をとることにしました。
こうすることで、Controllerは素直なCRUDのみを提供すれば良くなり、FatControllerは解消されました。 しかし、Railsでajaxを多用すると、
と、ajaxの管理が煩雑になってしまい、メンテナンス性が落ちてしまいました。 今まで、Controllerがやってくれていた処理を、Viewのjaxに回したために、View側で混乱してしまったという状態でした。
そこで、View側にも構造を導入してあげようということで、Backbone.jsを導入しました。 導入するルールとして、Railsとは完全に切り離し、通信はBackbone.jsを通して行うことにしました。 こうすることで、煩雑だったViewの整理整頓ができました。 つまり、
と、こんな感じです。 こうして、スッキリと開発できるようなり、Server側の製造負担は飛躍的に軽くなりました。
以上のように、ViewはControllerから完全に切り離されることになります。 こうすることで、View側はAPI通信をMockにし、完全独立な形態で開発できます。 また、API側はRailsである必要がないため、node.jsなどの用途にあったserverを準備できます。
サーバー側のエンジニアは単純にAPIを作り、クライアント側はBackbone.jsとデザインを作るだけになるので、分業しやすくもなりました。
さらに、View側は完全にstaticなファイルになるため、nginxから直接配布すこともできます。 つまり、HTML/CSS/JSをnginxから配布し、必要な情報を必要なServerから取得する構成ということになります。
これは、iPhoneアプリをダウンロードし、jsonなどで裏でサーバー通信するのと全く同じ構成になります。 つまり、Viewをアプリ化できることになります。
アプリ化すれば、iPhoneアプリなどとAPIを共有でき、開発のパワーを集中化させることができます。 また、静的ファイルは高速に配布できますし、jsonだけになるため通信量が低下、パフォーマンス自体も向上します。 websocketを使った通信をserverとのやりとりに使えば、pushなど面白い仕掛けもできます。
こうして、ViewとControllerの結合強度を下げることで、設計・製造の自由度やパフォーマンスが向上しました。
上記の通り、Viewが必要なAPIを叩くという構成をとったことにより、 APIは汎用的かつ、シンプルなツールを提供することになります。 これにより、API群は複数のViewから流用化できるため、開発自体が一気にDRYになり、 使い捨てのコードはなくなります。
次に、課題になったのが、Viewの開発スピードを向上させることでした。 Viewは、デザインが絡む部分なども多く、汎用化しにくいと考えていましたが、 ページを構成する各パーツに関しては同じようなものが多いのが現状です。
そこで、下記のような方針でViewの汎用化ツールを作ることにしました。
HTMLでViewをレンダリングする場合、
のようなステップで考えることが多いかと思います。 例えば、Twitterのタイムラインのページでは、
という形になると思います。
そこで、この(構造)の部分をどこにでも配置できるように作成し、流用化することにしました。 実際に使う場合は、(配置)と(内容)を決定してあげます。 Backboneの用語で言えば、(構造)がBackbone.Viewで、(配置)がelに、(内容)がmodelやcollectionになります。
例えば、一覧系のようにArrayをとりあつかう(構造)であれば、 MacOSXのFinderのような汎用的なUIを作れば十分そうです。 Finderを一つ作ってしまえば、どのcollectionでも使えてDRYですし、 継続的にメンテナンスすることでどんどんリッチにすることができます。
これまで、一覧系はバラバラに開発してきましたが、 FinderというBackbone.View=(構造)を作成し、実際に配置するタイミングで、Backbone.Collectionを詰めて使う。 こんな構成構成に全体的に変更しました。 結果的に、UI的にも統制のとれたものになり、機能としてもリッチになり、一石二鳥になりました。
なお、配置場所は、bodyの直下に配置すれば単なる一覧ページなりますし、ポップアップに配置すれば、リッチなセレクタにもなります。
Backbone.jsでは、内容(model,collection)と配置(el)をインスタンス化するときに決定できますので、 上記の構成がとても自然に実装できます。
各Modelはアイコンのみ、プレビュー、編集ページ、詳細表示など様々なViewを持ちます。 しかし、これらの見せ方は、Model間で共通化した方がUI的にも統一間がでてきます。
つまり、ちょっとしたプレビューやアイコンなども全てBackbone.Viewにmodelを挿入する形で作成し、各modelを横断したデザインができることになります。 (蛇足ですが、DBやAPIなどのサーバー側は縦割で、デザインは横割で作るイメージがありますよね)
コード的にもDRYになりメンテナンス性も向上、機能追加もそのViewをリッチにしていけば良いので、蓄積していくことができます。
こうして、使い捨てのコードはドンドン減っていきます。
上記のように、1つのmodelに対して、様々なViewを作ることになります。 ポップアップで表示し、その場で編集する場合など、 同一のページに同一のmodelの様々なViewが混在することが多々あります。
この場合、modelの名前を編集すれば、全てのViewを更新する必要があります。 昔であれば、ページをreloadさせるところですが、そんなダサイことは今更したくありません。
そこで、Backbone.jsではModelやCollectionのeventをViewがキャッチしてレンダリングする仕組みを取っています。
流れはこんな感じです。
このように、ViewにつめるModelやCollectionのイベントをキャッチして、 Viewのレンダリングを行うことを前提に作っていけば、自動的に各種Viewの同期が取れることになります。
こうして、reloadすることなく最小限の更新でViewの同期が取れることになります。
以上、まとめです。
長くなりましたが、以上です。