[開発プロセス#5] Webクライアントのパターン

前回はWebアプリケーションのモデリングを、ロバストネス図で行うことによって、MVCを基調とした考え方と大きな違いはないという点を考えました。もっとも、「感覚的にそうである」と言ってしまえばすぐに結論に至りますし、厳密な意味で同等あるいは同様であるということを証明するまでも至っていません。言えたことは、ロバストネス図で記述する内容が、Webアプリケーションの動作や構造を明らかにする上で検討することと、概ね共通しているという点くらいかと思います。

その議論の続きで、Webクライアント側のシステム設計を進めるにはどうすればいいかを考えます。Webクライアント、つまりJavaScriptとHTML、そしてCSSで表現可能な世界では、今でも簡易的あるいは補助的なプログラム作成が可能な程度で、本体はサーバーであるような印象を持つ人も少なくはないと思います。古い時代、確かに大掛かりなプログラムを動かす環境としては、ブラウザーは貧弱でした。しかしながら、10年ほど前、2007〜2008年くらいの時期にブラウザーのメーカーがJavaScriptの動作環境を飛躍的に効率化した頃から、世界は大きく変わり始め、jQueryによってDOMベースのプログラミングが一気に普及しました。DOMのAPIは昔からありますが、APIを使ってまとまったプログラムを書くのは比較的に難し買ったのですが、jQueryは簡素化された書き方で、クライアントサイドのプログラミングの機会を広げました。さらに、2009年にはAnglarJSの前身である<anglar/>がリリースされ、その後にBackbone.js、KnockoutJS、Ember.jsなどと本格的なフレームワークがリリースされました。当初は、サーバーサイドのMCVとクライアントサイトのMVCという考え方もあったのですが、サーバーとクライアントの本質的な違いに気づくのに時間がかかりませんでした。

ネットワークサービスではデータの共有が1つの重要な機能です。そうした仕組みはサーバー上でRDBあるいはNoSQL等を使って実現することになり、永続的に利用出来る仕組みは必ずサーバー側に構築されることになります。したがって、データベースを効果的に使うための「モデル」というレイヤーのプログラム群を構築したり、データ処理に直結するビジネスロジックは、サーバーサイドで実行されるのが素直な役割分担でしょう。一方、ユーザーインタフェースは結果的にクライアントのブラウザー側で実現されていることです。UXの向上を掲げるプロジェクトが一般的になり、Webのユーザーインタフェースでも、高いレベルの要求が発生しました。つまり、高いデザイン性とスムーズな応答が求められるようになり、ボタンを押せばサーバーを呼び出すというやり方を越えるべく、AJAXによりブラウザー画面の更新以外にも通信を行い、サーバーのやりとりの結果で画面の一部を更新するといった処理が必要になりました。つまり、クライアント側では高度なユーザーインタフェースをサポートするのが主要な目的であることがはっきりしてきたのです。

もちろん、MVCでも高度なユーザーインタフェースの管理は可能です。しかしながら、具体的にどうすれば高度なユーザーインタフェースを構築できるかを考えてみましょう。ユーザーインタフェースで入力した結果をJavaScriptのプログラムで処理をしたいとまずは考えます。加えて、ユーザーインタフェース要素で発生したイベントの処理を効率良く処理したいというニーズもあります。こうした主要なニーズ分解して考えれば、そのニーズに合致するアーキテクチャパターンはM-V-VMであると言えるでしょう。MVVMは.NET Frameworkの中にあるWindows Presentation Framework向けのアーキテクチャとして、MicrosoftのJohn Gossmanによって提唱されたものですが、Flashの対抗として出されたブラウザー拡張機能のSilverlight上でのアプリケーション開発が中心的な話題になっていたと思われます。

MVVMでは、Model、View、ViewModelをコンポーネントして、アーキテクチャが定義されています。しかしながら、この3つのコンポーネントよりも重要なのが、それらのコンポーネント間のつながりです。まず、ビューとビューモデルの間は、バインディングによって結合されていることが挙げられます。バインディグとは、例えばテキストフィールドがページ上に表示されているとして、そのテキストフィールドの中の文字列(つまり、コンポーネントの値)が、何らかのエンティティ(例えば変数や配列の要素、オブジェクトのプロパティなど)と論理的に結合されていて、大局的にはコンポーネントとの値とエンティティの値は、一方が変わると自動的他方にも伝達されて、常に同じ値になるということです。言い換えれば、ビュー階層にあるコンポーネントの変化は、自動的にビューモデルは知ることができるという意味にもなります。一方、モデルは、MVCのモデルと同様な意味を持つとされますが、サーバーサイドではシステム全体のエンティティに関連するものの、クライアントサイドでは、現在のビューにおいて扱うべきモデルに一般には限定されると考えられます。そのモデルはデータベースと関係させるかどうかについては様々な議論があり、今後検討します。まず、MVVMモデルにおけるモデルは、オブザーバーパターンを利用して、モデル内での変化がビューモデルに伝達されるという仕組みを持ちます。この「ビュー階層の要素のバインディング」と「オブザーバーで監視されたモデル」というのがクライアントサイドに要求される、基本的なアーキテクチャと言えます。これらの処理の実現は、JavaScriptでスクラッチから行うのはかなり重いものです。そのため、様々なフレームワークがありますが、JavaScriptのフレームワークは最近出てきたフレームワークも含めて、MVVMパターンを基調としていると考えるのが妥当だと考えます。

MVVM

現実にはフレームワークを使うことになるのですが、フレームワークを特定しないで、クライアントサイドの動作をロバストネス図の表記を使ってコミュニケーション図で記述してみました。例えば、入力項目がいくつかあり、それらのデータが揃うとサーバーにそのデータを送信するという状況を考えます。このような動作のUX的な良し悪しがありますが、ここではバインディグとオブザーバーによって、モデルビューに相当するコントロールオブジェクトにうまく処理が渡ることは確かなようで、それがダイアグラムで表現できていると言えるでしょう。

MVVM Client-Side

ここで議論があるのは、最後の「送信」でしょう。言い換えれば、サーバー側はモデルなのか、モデルビューの通信先なのかという点があります。ビューモデルが、モデルとビューの仲介であるという定義に従えば、サーバーに送るのはモデルの役割になります。しかしながら、それはモデルなのでしょうか?サーバーサイドにあるデータベースを、クライアントサイドで抽象化してみているのが、クライアントサイドのモデルという考え方もできるので、だとしたら、「送信」はモデルの1つに定義するのが的確かもしれません。

ここでアーキテクチャパターンが必ずしもすべてを表現できるものではないという考え方に立つこともできるでしょう。MVVMはクライアントの処理すべてを記述できるでしょうか? 例えば、ページを表示後、ある特定のclass属性を持つ要素の設定をプログラムで変更するような仕組みはBootstrapなどフレームワークの動作としては代表的です。その仕組みは明らかにモデルではないとしたら、モデルビューではないとしたら、どうなるでしょうか? この点を考えても、アーキテクチャーのベースはMVVMであることにより、高度なユーザーインタフェース構築の援助にはなるものの、全ての要素を、ビューとモデルとビューモデルに割り当てるのは無理がありそうです。

しかしながら、ロバストネス図を利用すれば、バウンダリやエンティティでないものは、なんでもコントロールオブジェクトとして定義しておくことができるので、コントロールの一部はビューモデルであるとしても、ビューモデル以外の仕組みも記述できます。MVVMを基調としつつも、ダイアグラムの自由度を利用することで、多彩な処理のモデル化が可能であると言えます。

ちなみに、MVVMの仕組みがあれば、「送信」ボタンは不要になりそうです。しかしながら、その種の「従来と違う」ユーザーインタフェースは不人気です。ボタンが不要でも、ボタンをつけることを要求されることになるでしょう。OS Xでは当初より「確定」ボタンがないにもかかわらず、Webページにはサブミットボタンがないのは気持ち悪いと考える人が多いようです。現状で、送信ボタンのないユーザーインタフェースで受け入れられるようにするには、テキストフィールドの隣などに、「未送信」「送信済み」などとフィードバックの情報を表示するなどの工夫が必要です。