MVCパターンの適用限界を考える(1)

MVC(Model-View-Controller)パターンは、UIを持つアプリケーションのデザインパターンとして非常に有名であり、特にこれを参考にしたJ2EEやASP.NETを始めとするWebアプリのフレームワークが成功を収めてきたことから、その価値は誰もが認める所である。
しかし、これをローカルシステムのGUIアプリケーションの設計に適用しようとすると、妙に難しいと感じた人が少なくないのではないだろうか。

MVCパターンは、元々Smalltalk-80の開発において考案され実装されたものらしいが、MVCの考案者によると、

MVC was created as an obvious solution to the general problem of giving users control over their information as seen from multiple perspectives.
("The original MVC reports"より)すなわち、複数の視点で表現されたユーザー情報を制御することを可能にする、という一般的な問題に対する自明な解として考案したものとのことであり、Smalltalk専用に考案されたものではなく、ネットワークシステムの為に考案されたものでもない。実際、MVCの実績はSmalltalk以外の言語で上がっており、MVCのアイデアに通信ネットワークの存在を仮定するようなものは見当たらない。であればどんなGUIアプリケーションでも有用なはずだ、と推測するのは全く自然なことである。

筆者も、当然MVCはローカルシステムでも有効なはずだと10年前から信じており、MVCの適用がうまく行かないのはMVCの理解が間違っているからだ、と思ってきた。しかし、この10年間でたぶん4回くらい、仕事でMVCを取り入れようとしたソフトウェア開発のプロジェクトの様子を知る機会があったが、いずれもほとんど成果が上がっていないようだった。見た感じ、MVCの理解が間違っているような気がすることも多かったが、それにしてもそんなに効果が出ないものだろうか。
実は筆者も、プライベートで何回か、MVCパターンを意識してプログラムを作ってみたことがあるが、MVCの価値を感じたことは一度も無かった。そういえば、MVCパターンの利点というのは、根拠のあるもの、具体的で検証可能なものはほとんど聞いた覚えが無い。オブジェクト指向設計と同様、経験的にやりやすかったから、現実にうまく行ってるから、という理由で推奨されているような気がする。それなら、大規模システムに有効なオブジェクト指向設計がミッションクリティカルなシステムに適さないのと同様に、MVCパターンにも苦手な分野があるのではなかろうか。
…ということを最近になってやっと考え始めたので、調べたことや考えたことを少しずつここに書いてみることにした。

MVCを知っていれば、既存のMVCを応用したフレームワーク(アプリケーションの枠組み及びアプリケーションの開発を支援する環境)が使える、というのは現実的なMVCを知るメリットではあるが、そういったフレームワークを使わない場合、MVCパターンをアプリケーションの設計に取り入れるメリットは何だろうか。

まず、筆者がずっと、きっとあると信じてきた、MVCパターンの利点を挙げる。

  1. Modelが再利用可能なので、ViewやControllerが交換可能で、容易に追加できる
  2. システム分割方針が分かりやすくなり、担当者毎、モジュール毎の役割分担が明確になる
  3. ソフトウェア構造としてM,V,Cが分離しやすく、従って独立して設計しやすい
  4. M,V,Cそれぞれのプラットフォーム(実行環境)やコンポーネント(共通モジュール)を別々に設計することも容易である
しかし、実際にはそうはならないことも多い。

(1)については、UIが複雑に、またビジュアル(グラフィカル)で応答性を高めるほど、VはMに限らずCの状態も表示するためにCに依存するようになり、特にポインティングデバイスやタッチバネルの処理で顕著なように、ユーザー入力が表示状態に依存してCがVに依存するようになるため、VとCの結合が強くなり、VやCが単独で交換可能にならなくなる。V+Cのセットでなら交換可能な構造が保てても、そうなると既にV+Cの規模が巨大になっているので、もう1つ別のV+Cを作る労力が、もう1つアプリ全体を作るのと大して変わらないことになってしまう。

(2)については、上述のようにUIが高度になるほどV-Cの関係が密接になって境界がわかりにくくなる他に、元々M-Cの境界がはっきりしないという問題がある。
あるモデル(ユーザーデータとその操作手段)を制御(操作)するアプリケーションは多岐に渡り、極端に言うと無限のバリエーションがあり得るんだから、アプリケーション固有のロジックはCに置くべきだろうという考え方もあれば、有名な"Skinny Controller, Fat Model"のスローガンに代表されるように、ロジックはできるだけModelに置くべきだ、という考え方もあり、システムに機能追加する時にあるロジックをMに入れるべきかCに入れるべきかは、人によって判断が分かれるのである。

(3)は、例えばModelを含めてシステムに機能追加する場合、Modelに追加するI/FはViewを意識して設計せざるを得ないことは普通に起こる。何も考えずにModel内のあらゆるデータを参照可能にする為にI/Fを揃えようとすると開発量が多くなることもあるし、複雑な変換や抽出を必要とする巨大なデータをそのまま渡されるとViewの処理が大変になるので、ある程度ユーザーにとって意味のあるまとまりにして渡してくれ、と言われることもある。
VとCが独立に設計できなくなりがちであるのは上述の通りである。

(4)は、実際にJ2EEではModelのコンポーネントとしてJava Beans(EJB)、ViewのプラットフォームとしてJSP technology、ControllerのプラットフォームとしてServlet technologyがあると説明されることがあり(参考リンク:[@IT 1] [@IT 2] ["Multitiered Applications" in Java EE tutorial])、M/V/C別々にプラットフォームを構築しやすいように見えるが、よく見ると、EJB以外は汎用的すぎて、M,V,Cそれぞれに特化したプラットフォームとは言い難い。Java BeansはVでもCでも使われる仕組みであるし、JSPはMだけでなくCにもアクセスできるし、作ろうと思えばJava ServletだけでMもVもCも作れる。M,V,Cそれぞれのプラットフォームとしても向いている、用途が広いテクノロジーを使っているのである。
むしろ、M/V/Cそれぞれのプラットフォームを作ろうとすると、そこまで汎用的で高度に洗練されたものを作ることになるのだろうか、という疑念すら抱かせる。

大体、一般にソフトウェアのデザインパターンの価値は、設計のノウハウであることよりもむしろ、設計者間の共通言語として使われることにあるのである。大概のパターンは、それを知らなければそういう構造にならないような、思い付きにくいアイデアではない。また、シンプルで普遍的にまとめられているものが多いので、その構造をにすると直ちに多くのノウハウが取り込める訳でもない。デザインパターンのノウハウの本質はその構造にした理由にあるのである。ある設計の基本構造とその構造にする理由とを合わせて一言で伝えるためにデザインパターンはあるのである。理由はおろか、パターンの構造自体も設計者間に共通認識が無くて伝わらなければ、デザインパターンとしての価値が無い、印籠やブランドの類でしかないのである。

さらに考察を進める前に、MVCパターンをおさらいする。
上記MVCの考案者"MODELS-VIEWS-CONTROLLERS"によるModel, View, Controllerの定義は、次のようなものである。
Model
実世界における問題を、特定の視点で抜き出したものを表現するもの。言い換えると、実際の問題や事象をモデル(模式、模型)化するもの。("Models represent knowledge."の"knowledge"は問題や事象に関する知識のこと。)
View
Modelの視覚的な表現。1つのViewはModelに取り付けられ、Modelに対して問い合わせをすることにより必要なデータを取得する。Viewはそれが取り付けられるModelのことを良く知っており、Modelへの問い合わせは全てそのModelで使われる言葉を用いてされる。 ("It may also update the model by sending appropriate messages."についてはややこしくなるのでとりあえず保留。)
Controller
ユーザーとシステムとを繋ぐもの。画面上にそれとわかるように表示することにより、ユーザーに入力手段を提供する。また、ユーザーによって入力されたコマンドをメニュー等によって表示するためのメッセージをViewに送信する手段を提供する。
ControllerはViewを補完せず、Viewの表示に介入しない。同様に、Viewはマウス操作やキーなどのユーザー入力そのものには関知しない。


次に、MVCパターンの最もシンプルな構成を、UMLで表現してみる。
Class diagram of MVC without V-C connection
図1-1: 最もシンプルなMVCのクラス図(静的構造図)

Communication diagram of MVC without V-C connection
図1-2: 最もシンプルなMVCのコミュニケーション図(動的構造図)

上記の"MODELS-VIEWS-CONTROLLERS"の定義にはViewからModel、ControllerからViewへの関連が含まれているが、それらは必須の構成要件ではない(その関連におけるメッセージのやり取りが無くてもMVCパターンは動作する)ので、最もシンプルな構成ではそれらを省いている。

ポイントは、次のように集約される。
  • 1つのModelに複数のViewを動的に登録することができる
  • ModelはViewの存在を知っているが、Viewの具体的な実装を知る必要が無い
  • 1つのModelを複数のControllerから操作することができる
  • ViewとControllerは完全に独立している

なお、1つのViewが複数のModelに関連する、つまり複数のModelの表示を受け持つことも可能だとされることが多い(上記MVCの考案者による"THING-MODEL-VIEW-EDITOR"でも"each View being capable of showing one or more pictorial representations of the Model"という記述がある)ので、M-V, M-Cの多重度は1対多でなく多対多が正しい、と思われるかも知れないが、Modelを交換可能とすることはMVCの本質ではないことと、そのようなViewは役割をModelの数だけ分割し、その数だけMVCのセットがあるのと同じことと、一般にオブジェクト指向設計において多重度が多対多の関連は意味が曖昧であることを理由として、M-V, M-Cの多重度は1対多と書いている。
(続く)


MVCは「デザインパターン」以外に「モデル」「アーキテクチャー」「フレームワーク」などと呼ばれることも多いが、「モデル」はModel-View-ControllerのModelと被り、「アーキテクチャー」と呼ぶには単純すぎ、「フレームワーク」は何らかの実装を伴うべき(J2EEのMVCは一部実装があるからフレームワークと呼べる)だと考えるのと、上記MVCの考案者"The Model-View-Controller (MVC), Its Past and Present"に"MVC pattern language"という表現があることから、ここではMVCはデザインパターンと呼ぶことにしている。

なお、筆者はJ2EEは使っていないが、ModelをMySQLに依存する1つのクラスとして作り、ViewをJSPで作り、ControllerをJava servletとして作ることが大好きである。そうすることにどういうメリットがあるのかに関係なく、MVCパターンの実装として美しいのであり、これほどその構成で作ったことそのものに達成感があり、感傷に浸れる爽快な構成は無いのである。もはや手段が目的になってしまっており、そうする必要が無くてもそうしたいのである。