タグ「MVC」が付けられているもの

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

MVCの適用限界について考えることをテーマにして書き続けてきたが、MVCとその変遷が複雑すぎて、それらを考察し終えるのにはまだまだ時間がかかりそうである。
なので、一旦、現時点での筆者のMVCの適用限界に関する見解をまとめることにした。

ここでは、ドメインモデルとビジネスモデルをまとめて「ビジネスロジック」と表現する。以下の「ビジネスロジック」は「ドメインモデル」に置き換えても同様である。


●1. MVCパターンは、現代のGUIフレームワークには適さない
ウィンドウやウィジェットを入れ子構造で配置し、ボタンやリストなどの表示部品を置き、それらが押された時の動作などを各表示部品に直接関連付け、マウス操作などのイベントがアクティブな子ウィジェットから親ウィンドウへと伝搬される、AWTやSwingや*/TkやGTKやVBやVCなど、現在開発に使用されている代表的なGUIフレームワークでは、MVCで言う所のControllerが階層構造のViewに分散しており、ControllerはViewの一部という形になる。それにより、ControllerがViewに依存する形となり、例えば、CをそのままにしてVを追加/変更できるという前提が崩れる。

いわゆるGoF本に書かれているMVCでは、originalの(Smalltalkの)MVCとは異なり、ControllerはViewの一部だと割り切り、presentation logicとdomain modelを分けて多対1の関係とすることに絞っている為、現代的なGUIフレームワークにも適した考え方となっているが、それはMとVだけで成り立つ概念であり、MVCと呼ぶ意味が無いものである。
なお、MVCはGoF本の発刊時点で既にこの理由でobsoletedであった為、デザインパターンの元祖として紹介するだけで、同書の23のデザインパターンとは並列にされなかったという説もある。

これに関して、参考リンクに挙げたWebページから、いくつか興味を引かれた文章を引用する。

[3]のコメント欄より:

if you need to send an onMouseOver event to a controller instead of just changing state on the button in the view, what do you gain?
...
Only things that change application states (be they persistent, session-specific, or application-wide) should be sent to a controller

(Viewしかわからない)MouseOverイベントをControllerが受けてViewに配送することに何の意味があるのか?(Viewが単独で処理すれば良いのではないか?)という疑問である。Modelの変更に繋がり得るイベントだけがControllerを通れば良い、というのも同感で、そこまできちっとViewからControllerを切り離す必要性は無いと思う。

[6]のコメント欄より:

MVC, and StateMachines are orthogonal concerns (depending on the app each tier may have it's own StateMachine). The differentiation typically is in MVC the model state is persistent, and survives a many to one relationship (e.g. a bar and line graph both using the same data.) where as state machines are useful for runtime states.

MVCと状態遷移モデルは直交する概念で、状態遷移モデルの状態は全てMVCのModelの状態であるべきだということにはならず、永続的でV-Cとは多対一の対応の関係にあるものがModelの状態であり、ViewやControllerがそれぞれ実行中の状態(及び遷移モデル)を持っていても良い。
GUIフレームワークでは、Viewの状態とControllerの状態が分離されない(全て同じ箇所に書けてしまう)ので、意識的に努めて行わない限りは、ViewとControllerが分離されない。というか、現実的には(単純な例題でもない限り)ViewとControllerとの状態の分離はやり切れないと筆者は思う。

同じく[6]のコメント欄より:

Some definitions of MVC call for a single controller, supporting multiple models, each with a view. Obviously, Flash apps almost never work like that - Flash MVC is really distributed MVC, often different views have their own controllers, and views are all managed by a master state management controller.

Adobe FlashのアプリをMVCに当てはめると、M:V:Cの関係が通常の多対多対1の関係ではなく、ViewはそれぞれControllerを持ち、それとは別の巨大なControllerによって制御される、"distributed MVC"である。

なお、Cocoa MVCでは、"Responder"(Controllerへの参照のようなもの)と"Responder chain"(イベントを処理できるハンドラーの検索順序を決めるリスト)という概念によってGUIフレームワークとMVCとを整合させているそうだが、本当にこれによってControllerがViewの構造とは独立の構造を持ち、例えばViewだけが交換可能になるのかどうかは、筆者にはよくわからなかった。(View毎にResponder chainを用意するというのは、View毎にControllerの構造を用意するというのと同じようなものなのでは...)


●2. MVCパターンは、リッチなクライアントを持つWebシステムには適さない
本来、MVCパターンでは、Modelが変化すればViewがその通知を受けて、ViewがModelの状態を取得して表示に反映するものであるが、通常使われるHTTPのような(PUSH型でなく)PULL型の通信手段を使用しているWebシステムでは、Modelの本体がサーバー側、Viewの本体がクライアント側にあるので、Modelの変化に伴ってViewを更新することができない。

Webシステムでよく使用される、J2EEやStrutsやFlexのような、いわゆる"Model 2"のフレームワークでは、サーバー側の構成にMVCパターンの考え方が採用されており、WebシステムでMVCと言えば大体これのことを指す。しかし、クライアント側も含めてMVCパターンにすることをサポートするフレームワークは存在しない。
"Model 2"でも、サーバー側、クライアント側それぞれ別々にMVCパターンを適用することは可能であるが、それはアプリケーションのGUIのみをMVCにするようなものなので、クライアント側をMVCにするメリットは少ない。

クライアント側がHTMLを表示するだけのViewの機能と、HTMLブラウザの機能だけで実現できるフォームやボタン程度のUIであれば、クライアントはViewのみとしてもまず問題にはならないが、AjaxやFlashを用いるなどして、クライアント側のUIをリッチにすることが可能になり、例えばユーザーの入力にリアルタイムに反応してボタンの有効状態が変わるようにしようとすると、それによってボタンが有効になるべきかどうかをキーストロークの度にいちいちサーバー側に問い合わせるか、Modelに相当するビジネスロジックをクライアント側にも含める必要が出てくる。

このような問題をまともにMVCパターンで解決するには、Webシステム全体としての機能をMVCに分割し、Model, Controllerそれぞれをサーバー側とクライアント側に配置し、Model同士、Controller同士がそれぞれ最小の通信量で済むように協調動作することが必要になる。それ自体が容易でないのに加えて、そういう構成をサポートするMVCフレームワークは現存せず、それに既存の"Model 2"のMVCフレームワークが使えないので、サーバー側とクライアント側を合わせてMVCパターンにすることは困難であろう。
ついでに言うと、"Model 2"のMVCと本来のMVCは異なるので、Webシステムで本来のMVCパターンを取り入れようとすると混乱が起こるのではないだろうか。

参考リンクからいくつか引用する。
[1] "MVC As Anti-Pattern"より:

But what if you are building a web application with a rich client?
[snip]
Do you still need an MVC framework?
I think the answer is most likely no.

このページ全体がこのテーマで、論旨がよくまとめられているので、興味のある方は是非読んで頂きたい。

Developers who use modern rich-client frameworks do not have to create controllers to manage events. What a runtime and its frameworks do internally is a different story.

この"rich-client frameworks"は、View内の構成要素それぞれがController(イベントハンドラー)を備える、通常のGUIフレームワークのことを指す。

[3]より:

I've come to the conclusion that... drumroll please... MVC is probably not needed for most RIAs.

RIAはRich Internet Applicationsの略で、クライアント側もリッチなアプリケーションであることを意味しており、この記事の所々にある"FrontController pattern"は、その対極に、クライアント側はシンプルで、何もかもサーバー側のFrontControllerを経由する構成のことを意味している。

You often see architectures in which a single controller handles all of the "actions" for the entire application. I see this as a necessary evil, not a "good thing". The world of the giant switch statement is exactly what we wanted to avoid with OO programming, right?

ここでは、MVCのControllerは巨大なswitch文の塊になりがちであることが問題にされている。例のmost controversialなSkinny Controller, Fat Modelと同時期に呈された、MVCに対する不満である。

[3]のコメント欄より:

I agree, separate model and view is enough, controller sometime is abused

M-Vの分離には意味があるが、Cの分離はえてしてやり過ぎである。

[6]より:

Fact: No one codes Flash using pure MVC.

このページに書かれているのは主に一般論だが、なかなか深く鋭い話で、一読に値すると思う。

[3]のコメント欄より:

In addition, just consider the case (in the real Business world) when you need to deploy a program (which also holds the Controlling) on the client machine

クライアント側にView以外のロジック(ビジネスロジックそのものや、サーバー側のビジネスロジックを扱うController)を含めることについての問題提起であり、一般にクライアント側でのプログラムの実行は難しいので、故にV-Cの分離は重要だと述べられている。確かに考慮すべき事柄ではあり、V-Cの分離が現実的に可能であれば一理あるが、実際にはV-Cの分離に労力を掛けるより、クライアント側でプログラムを実行することに労力を費やす方が、コストが小さく、何よりも自由が利くので、労力に見合うのではないだろうか。

[3]のコメント欄より:

Anyone who justifies MVC as a way of making a web app "like" a desktop application's MVC architecture is fooling themselves. The internet just doesn't work that way. I've seen IT budgets balloon and schedules run late because of the blind, over-zealous switch to MVC, while chanting "industry standard" to anyone who asks "why?"


●3. MVCパターンは、リッチなGUIには向かない
MVCパターンでは、UIの制御は、必要であればViewに(カーソル位置、スクロール位置等の)表示状態を問い合わせながら、Controllerが主となって行うことになっている。それにより、ControllerはViewの画面構成に依存せず、Viewのみの交換や、表示の異なる複数のViewの追加が可能になるのである。

しかし、そのようなViewの抽象化は、全てのViewに「タイトルバー」と「メニューバー」があり、「メニューバー」は「項目」または「項目グループ」を含む、など、ある程度はUIの形状が決まっていないと困難である。

また、Viewの状態が複雑になるだけ、Controllerも複雑になる。いくら何でも、マルチウィンドウ状態を持つVを、1つのループとswitch文でなるControllerが制御するのは限界があるので、必然的にControllerは分解することになるが、その分解方法はある程度Viewの構造に依存しないと複雑になる。Viewを抽象化し切るのが困難になり、抽象化する労力が効果に釣り合わなくなるのである。ウィンドウマネージャーくらいの機能だとまだ実現可能かも知れないが(それでも相当大変だ)、クリックされた位置がどのような抽象状態の時にどうする、とか、メニュー画面がスクロール可能な場合はどうでページ送りの場合はどうで、とかいうのを、Viewを抽象化してViewがどんな形でも動けるようにするのは至難の業である。

ウィンドウシステムのあるマルチアプリ環境にMVCパターンを当てはめることを想像すると、アプリ毎にMVCがある構造を思い付くのが自然ではないだろうか。アプリの追加/削除まで考えると、仮にMはアプリケーション間で共通のものを使用できるとしても、VやCをも共通にできると思う人は居ないだろう。それができるとすれば、メニュー画面しかないアプリくらいである。つまり、アプリケーションマネージャーを除き、Viewの数だけControllerが存在すると思うのが自然である。1つのアプリケーションでも、巨大になれば構造を分解することになるが、マルチアプリ環境と同じ発想で、ViewとControllerを複数のV-Cのセットに分解する構造にすることを考えることが可能なので、それに行き着くのが自然であろう。GUIが大規模になれば、Controllerの構造がViewの構造に一致する、というより、ControllerがViewの構造に縛られるのは宿命なのである。

このことは、実はoriginal MVCでも少し触れられている。前の記事にも挙げた、"The Model-View-Controller (MVC) Its Past and Present"のP-8 "Tools for Tasks"とP-9 "Tool as a composite"がそれであり、タスク依存のV-CはToolとして独立させれば良く、ToolはToolを組み合わせて構成すれば良いということなので、これは、現在主流のGUIフレームワークを使うと自然とその形に誘導される、GUIをウィジェットの入れ子構造で実現することとほぼ同じことである。これでアプリケーション全体がToolの組み合わせだけで実現することがMVCパターンの範囲に入るなら、現在主流のGUIフレームワークはMVCパターンから逸脱していないことになるが、さすがにアプリケーションのトップレベルがMVCの構成でないのはMVCパターンとは呼べないであろう。また、通常MVCという用語が使われる時に、P-8やP-9の意味を含むことは稀である。

また、GUIが複雑になれば、GUIそのものをMVCに分ければいいという意見が出てくることもあるが、一般にV-Mが強結合だとMVCはうまくいかないことが知られているし、それこそMVCパターンを使うことが目的になり、何の為にMVCにするのかがわからなくなってしまう。

[3]のコメント欄より:

One of the reasons that people build controllers is to isolate the interaction logic from the view, with the goal of being able to swap out the view. The problem with this approach is that with the richer UI vocabulary that RIAs allow, I believe it is not possible to do this.

UIがリッチになると、UIのロジックをViewから切り離すのは不可能だと思うと書かれている。
筆者も、M,CをそのままにVだけ交換可能にするというのは、スキン(画像ファイル)の交換くらいが限界だろうと思う。GUIの見た目が変わって操作が全く同じということはほとんど無いだろう。


●4. MVCパターンは、エディターには向かない
テキストエディターや文書作成アプリや画像編集アプリなどは、MVCパターンへの当てはめ方が難しいアプリケーションの例としてよく挙げられるものである。
何をModelにするべきかという問題ではあるが、デザインパターン、つまり共通の知識としてのMVCの一般的なコンセンサスとして、Modelの状態は永続的なものであることと、ModelはViewに依存しないことがあるが、それからすると、テキストエディターのModelの責務は、文書を保存して読み出すことくらいになってしまう。

人間にわかり易い形、つまりビジュアルなデータ編集ツールの中心部を、ビジュアル抜きに形式化するのは困難である。かと言って、ビジュアルがメインのアプリケーションなら表示状態もModelに含めれば良いかというと、そもそもPresentationとModelが分離される背景には表示系はよく変更されるという前提があり、表示系が変更するとMにもVにもCにも変更が入ってしまうのでは、何の為にMとVとCとに分離するのかがわからない。

また、通常、ControllerとModelとの間のセッション状態(ひとまとまりの協調動作における状態)をModel側に持たせることは好ましくない。C-Mの関係においてはControllerが能動的、Modelが受動的に動作するので、セッションの開始と終了がわかるのはControllerだからである。例えば、テキストエディターの編集中の状態をModelに含めると、同時に編集するデータの数に比例してModelの状態が複雑になってしまう。(セッションの数だけModelのオブジェクトを作成するならさほど複雑にならないが、それはControllerがセッション管理しているのと同じことである)

Original MVCでも"THING-MODEL-VIEW-EDITOR"という分け方があるように、オブジェクトの中身を操作するUIはMVCパターンの中でも特殊な位置付けであり、"EDITOR"はMVCに当てはまらないものの代名詞とも言えるのである。

エディターの他に、MVCの適用が困難な例としては、ゲームがよく挙げられる。エディターと同様に、画面表示がメインのアプリケーションは、ModelとViewの結合が強いので、MVCの分割に向かない。また、HMI(Human-Machine Interface)や感性モデルやバーチャルリアリティーのように、変化しないModelを確立するのが難しい分野にも向かないと考えられる。現実世界のモデル、現実のビジネスモデルとHMIは追究の仕方が異なるので、開発スタイルも異なるはずである。

アプリケーション全体としては直感的にMVCに分けることができても、部分的にMVCに分けるのが困難になる例としては、Modelの実行中の確認ダイアログが有名である。
そのビジネスロジックにおいてその手順中にユーザー確認が必要であったら、その情報はModelにあるべきであるが、ダイアログ画面の表示制御はControllerの仕事である。確認ダイアログ1枚くらいなら、Modelの処理をその前後で分けて、Controllerが前半の処理とダイアログ制御と後半の処理を順に行えば簡単であるが、一連のビジネスロジックの処理中に何枚かのユーザー入力画面が必要だったり、それらが画面遷移モデルを伴ったりすると、問題は一気に複雑になる。あくまでControllerがビジネスロジックを含めない方針にすると、ModelはControllerへの応答だけで次に出す入力画面を伝える必要があり、ユーザーからの入力が不正かどうかをControllerは判断できないので、Modelは不正入力を判断して、場合によってはエラー表示を伴う異常処理を行わなければならなくなる。
ビジネスロジック固有のUIの画面遷移と、タスクやView固有のUIの画面遷移とがあり、View固有としてV-C側に置かれていた画面遷移が、Viewが増えた時にView間で共通のビジネスロジックだと決まると、Modelに移動させる必要が生じたりする。
そもそも、ビジネスロジックがUIを伴っても、その実行時の画面遷移状態はセッション状態であり、Modelの状態としてはふさわしくない。
かくして、UIを伴うビジネスロジックがControllerに置かれるようになり、Modelの存在意義が希薄になり、Controllerがビジネスロジックの塊となるのである。

これも突き詰めると、MVCでは、UIを伴う処理をModelに取り込むのは厄介だということであり、エディターがMVCに向かないのと共通点の多い問題である。

各々のプロジェクトにおいて、何をModelにするかという方針を明確にしさえすれば、そんな問題は起こらない、という意見もあるが、対象が物理モデルやH/Wでも無い限りは、どこまでをビジネスロジックと見做すのかは、それほど一意に決まらない。始めはアプリケーション固有ロジックであっても、それが再利用されるようになって初めてビジネスロジックになることも少なくない。どう考えてもpresentation logic、そのViewでしか使わない固有の処理だろうと思ったものが、実はそのビジネスモデルで共通だったというのは、よくあることである。
UI intensiveなエディターをどうMVCに分解するかというのは、SmalltalkのMVCでも同様の問題がある気がするのだが、筆者はこれについて何らかの解が示されているwebページを見た記憶が無い。筆者は、エディターからModelを迷い無く切り出せるようなModelの定義は存在しないと思っている。

参考リンクからいくつか引用する。

[2]より:

By letting the service layer refer to sessions, I am also creating a Model that is hard to test without having an entire application in place.

ここでは"service layer"はModelの上層部、ControllerやViewから直接呼び出されるI/Fを含む層を指す。Modelがセッションを参照すると、Modelを単体でテストするのが困難になる、と書かれている。

同じく[2]のコメント欄より:

This makes me think of what Misko Hevery was saying in a previous blog post - that the more testable something is, the better it is probably architected. And, the more easily tested it is, the more it likely decoupled from other objects.
One of the huge benefits of separation of concerns is testability. If you've designed your components properly, you should be able to write test cases that can give you some peace of mind.

[4]より:

If you are designing a graphics intensive program, like a game, you would probably couple the View and Model classes much more tightly than what MVC suggests. As we can see from the Basic sample application, when programming a very simple application it is common to combine the controller with the view classes.

[3]のコメント欄より:

Things, of course, get tricky when user interaction comes into play. For example, if you need to pop up an alert that asks the user a question before completing the transaction.

[3]のコメント欄より:

If you're doing a word processing application, is the keypress sent to the controller, added to the document via the model, then the view is refreshed via the controller? Or is the model used to save changed files and the view handles all the live updates to the text?

[6]より:

MVC says that the entire application state is supposed to reside in the model. However, many applications maintain application view state in the controller, and the data state in the model.

MVCではアプリケーションの状態は全てModelに置かれることになっている(Original MVCではある程度のGUIの状態はViewが保持してもいいことは省略されている)が、実際にはControllerがViewの状態を保持していることが多い、ということ。

ControllerにGUIの状態を置かないことが実際には難しいことを暗に言っていると思う。
Original MVCでControllerがViewに表示状態を問い合わせても良いと書かれているのは、当時はGUIの状態は少なく、リスト上の表示範囲やカーソル位置など、View固有の状態だけで表現できるという前提があったから、もっと言うとSmalltalkではアプリケーションの形をある程度決めることができたからそういう設計思想が通用したのであり、ボタンの状態や文字色やパネルの入れ子や不定形なGUIやフォーカスやアニメーションなど、昨今のバリエーション豊富なGUIでは、むしろModelよりも状態数が多いことも少なくない。


●5. MVCパターンは、リアルタイムなUIに向かない
これは、Viewの画面更新はModelの変更完了後になされ、ユーザー入力を受けるControllerがそのままViewの画面更新を同時に行わないことによる。
よくあるMVCの実装だと、Model-Vew間のObserver patternがきっちり作られているため、ModelとViewが非同期的に動作し、Modelに何か変化があったという通知をViewが受けて、ViewがModelに最新の状態を問い合わせるという、Model内のデータの更新と画面の更新とを同時に行うのに比べて無駄の多いシーケンスとなる。Controllerから見ると、もう画面をどう更新すればいいかがわかっていても、イベント配信のスケジューラーに任せる形で、表示更新を後回しにするしか無いことがある。

もちろん、Viewは必ず非同期に動作しないといけないということは無いので、Modelの更新中にViewに更新要求しつつ、即座にViewに実行権を明け渡すような同期処理にすることも可能だが、Modelの更新に同期して都度表示更新するのがユーザーレスポンスが再短時間になるとは限らない。すなわち、Modelの更新がある程度済んでから描画する方が速いケースも少なくない。
一続きのModelの更新が完了したタイミングがわかるのは基本的にControllerなので、必要な時はModelの更新前にViewに表示更新禁止指示を出し、Modelの更新後にViewに表示更新要求を出せば良いのだが、そのような必要が多いシステムであれば、VewをModelのObserverにする意味が無いであろう。

また、MVCパターンでは表示に関するビジネスロジックもModelにあるのが前提(Viewが交換可能なのが前提だから)なので、必然的にViewからModelへの問い合わせが増えることも考えておく必要がある。Modelへの問い合わせが、メソッドの同期呼び出し等、同じ実行コンテキスト内の同期処理であればオーバーヘッドは小さいだろうが、ViewとModelが並列動作していて排他制御が必要だったり、Modelがネットワーク越しにあったりすると、一部のビジネスロジックはViewにも含めるような、MVCパターンから外れる対策が必要になるだろう。

参考文献[5]より:

The first problem area is to deal with setting the color of the variance. This shouldn't really fit into a domain object, as the color by which we display a value isn't part of the domain.

表示する値(ここではvariance)に定性的な意味合いに基づいて色付けする場合にその色の決定処理をどこに置くかという例題で、この文章に続いて、MVCパターンにおける、表示に関するビジネスロジックの扱い方について、深く考察されている。長くなるので詳細は割愛するが、オブジェクト指向言語だとtext fieldのsubclassを作るのが好みだと書きながら、結論としてはMVCの他に"Presentation Model"(View側のビジネスロジックを含める部分)を設けることによって大抵解決できると書かれているのが興味深い。


●6. MVCは絶対的な指針にはならない
人々のMVCパターンの理解がこれほどまでにばらつく理由は、Web系のフレームワークにおいて絶対的な地位を築いた"Model 2"や、かのGoF本に書かれた技術的なロマン溢れるMVCなどの、原典であるSmalltalkのMVCからかけ離れた亜種がSmalltalkのMVCより圧倒的に有名になったことが直接の原因だと思って間違い無さそうである。そのように多種多様なMVCが生まれる原因には、それらのいずれもがMVCを誤解したものだと言われないことがあると思うし、それは、MVCに正解が存在しないからであろう。

Smalltalkの開発中に考案されたMVC理論は、複雑すぎて人々に理解されず、そして、SmalltalkのMVCは現代の進化したGUIを持つアプリケーションにそのままでは使えなくなったので、MVCの原典を繙く人が増えなかったのだと思う。
さらに、ソフトウェアの規模が大きくなったのに合わせてMVCに色々と改良が加えられても、人々が納得する決定版が現れないので、人々のMVCの理解がばらつくのを止められないのだと思う。

人々は、ある理論を理解することを放棄する時、それが全てではないでしょ、という言い訳をする傾向がある。ソフトウェア設計者は、既存の設計が理解できない時、もっとシンプルにできるはずだと言い訳して放棄する傾向がある。ことこれほど広まっているMVCパターンに限って、理解できないという言い訳は敗北と考えて、せめて割り切ってMVCと接することができるように理解に努めてきたが、筆者は、MVCの理論にも適用可能範囲にも絶対的なものは無い、つまりMVCとして絶対不可侵な範囲も無く、こういうアプリケーションに有効と言える対象も無く、ましてやどんなアプリケーションでもMVCパターンに従うべきだということは無いと確信するに至った。

MVCパターンは、ただ闇雲に何が何でもMVCにすれば良いものではない。理論を知らなくても、忠実に守っていれば何かご利益があるような便利な知識ではなく、オブジェクト指向と同様、単なる設計理論の1つであり、設計思想の追求の仕方、設計の突き詰め方のヒントを与えてくれる程度のものである。

[6]より:

Patterns are architectural heuristics. Understanding them should widen your solution spectrum, not narrow it. They provide you with proven ways of solving a specific problem in programming. The reality is that you will rarely encounter that specific problem in the wild, but you will encounter variants of that problem

デザインパターンを理解すると問題解決能力が上がるべきであり、逆にそれに従うことによって問題解決手段の選択肢を狭めるものであるべきでない、という意味だと思う。
筆者は、デザインパターンは将棋の定跡のようなものだと思う。実戦において、定跡と全く同じ局面になることは滅多に無いので、ただ手順を覚えるだけではあまり役に立たないが、似たような局面になることはよくあり、定跡手順の意味を理解していると、大きなヒントになる。
同じ手でも、定跡を知らずに指すのと、定跡手順を知った上で外すのとでは、試行錯誤の質が大きく異なり、その後の勝率に差が出る。定跡を知らなくても、終盤で逆転するとか、力づくで勝ち続けることは可能だが、限界がある。終盤は法則化、体系化できないので、勝率を上げるには終盤力、つまり計算速度を上げることしか無くなる。
同様に、ソフトウェア設計も、コーディング能力に頼るのでは限界がある。それは個人の資質にも依存する職人芸であり、何よりも、習得方法、指導方法の確立が難しいので、伝達及び維持が困難である。この業界は、技術は盗むもの、とか言っていて間に合う世界ではない。だからこそ、アルゴリズムや設計理論やデザインパターンを知ることに価値があるのである。

[6]のコメント欄より:

I only like to talk about MVC now when there is something resembling Smalltalk MVC triads at work and controllers are required to move messages between triads. Otherwise I think the GOF book got it right to not include MVC as a pattern.

When people say they are using MVC I take that to mean they see their application as being organized somehow into three parts that can be worked on separately:

1. data and business logic,
2. presentations of that data, and
3. some sort of event management and propagation system.

I don't really think MVC means much more than that anymore. Consequently its value in discussing real-world designs has become suspect.

[3]のコメント欄より:

One of my main issues with the whole framework/mvc debate is that it has been my experience that one size can not fit all.

どんな規模の開発にも有効なフレームワークやデザインパターンは存在しない、と言い換えても良いと思う。

[3]のコメント欄より:

The most important part of an abstraction is not what patterns it strictly adheres to, but what it provides the programmer in terms of power, maintainability and ease of use.

... and back to the discussion on MVC: my 'tool' abstraction encapsulates user input processing, drawing transparent scratch information (for example to display a selection rectangle) and model object manipulation. Is the tool a controller or a view? Could it even be a model (at the application level as opposed to the document level)? The answer: who cares. These labels we use are for architectural communication and education, not as rules that must be adhered to regardless of the problem domain.

A more important question than "do your developers implement design patterns?" is "do your developers *understand* design patterns and spend the time creating, analysing and discussing abstractions that may enhance the design of your application?"

問題の抽象化の目的は、作り易さ、メンテナンス性、扱い易さなどの実際の成果であり、デザインパターンに厳密に従うことではない、と書かれている。
また、デザインパターンを使っているかどうかでなく、デザインパターンを理解して使っているかどうかが大事な問題だ、とも書かれている。


参考文献
[1] MVC As Anti-Pattern
 MVCパターンは、リッチなクライアントを持つWebシステムには適さない、という主旨で、よくまとめられている。MVCパターンの限界を考える出発点として最適だと思う。
[2] A Better Understanding Of MVC (Model-View-Controller) Thanks To Steven Neiland
 MVCにきちんと従うためのわかりやすい指針というか、格言のようなものが考え出されている。
[3] MVC considered harmful
 本文には大したことが書かれていないが、コメント欄の議論は非常に深く、参考になる。
[4] Best Practice Software Engineering - Model View Controller
 簡単なMVCの紹介。1ヶ所、上記の引用部分の記述が非常に鋭いと感じたので、挙げておく。
[5] GUI Architectures
 その筋では有名な、Martin Fowler氏による、Webアプリケーションのフレームワークの進化の歴史が書かれている。必読。
[6] On Design Patterns and Reality
 一般論が多いが、なかなか深く鋭い話で、一読に値すると思う。

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

1つ前のエントリーで、いわゆる"Model 2"がMVCパターンの用語で説明されるようになったことが、人々のMVCの理解をバラバラにする原因になった、と書いたが、そのことは、前エントリーの参考リンクの先のページでも見られるように、多くのWebページで触れられていることでもあるが、筆者はむしろ、いわゆるGoF本に書かれているMVCの説明が最大の混乱の元だと思っている。"Design Patterns: Elements of Reusable Object-Oriented Software"(邦訳タイトルは「オブジェクト指向における再利用のためのデザインパターン」)、いわゆるGoF本の§1.2にある以下の記述がそれである。

MVC consists of three kinds of objects. The Model is the application object, the View is its screen presentation, and the Controller defines the way the user interface reacts to user input.
MVC also lets you change the way a view responds to user input without changing its visual presentation. You might want to change the way it responds to the keyboard, for example, or have it use a pop-up menu instead of command keys. MVC encapsulates the response mechanism in a Controller object.
A view uses an instance of a Controller subclass to implement a particular response strategy; to implement a different strategy, simply replace the instance with a different kind of controller. It's even possible to change a view's controller at run-time to let the view change the way it responds to user input. For example, a view can be disabled so that it doesn't accept input simply by giving it a controller that ignores input events.
(注:ここでは"disabled"はボタン等が操作できない状態のことを指す)

GoF本の1.2節を開いてまず目を引くのは、図にControllerが無く、1つのModelと複数のViewのみで構成されていることである。上記の引用文にある通り、これは、ControllerがViewの一部として扱われているからである。
MVCの最大の目的はPresentation logicとBusiness logicの分離による安定性の向上(変化する部分と変化しない部分の分離)である、というのはOriginal MVCから一貫した理念であるが、システム全体を(Controller抜きで)ViewとModelに分離すると書くことによって、それを最大限に強調しているのである。これはMVCの本質をわかりやすく表していると思う。

しかし、それから少し読むと違和感を覚えるのが、ユーザー入力を受けたViewがどう振る舞うかを、そのViewのControllerが決める、という記述である。このようなことは、Original MVCには書かれていない。また、Original MVCに書かれている、ControllerからViewへのメッセージ送信についても、GoF本には明確な記述が無い。
もしこれが、Original MVCのControllerの定義にある

Conversely, a view should never know about user input, such as mouse operations and keystrokes. It should always be possible to write a method in a controller that sends messages to views which exactly reproduce any sequence of user commands.
と矛盾しないとすれば、ユーザー入力がViewからControllerへ伝搬されるというのは、"views which exactly reproduce any sequence of user commands"の部分を拡大解釈したものであり、Controllerは入力デバイスのドライバーやウィンドウシステムの役割のみを担うものとしていると解釈するのが妥当であろう。
早い話が、JavaのSwingやQt, GTKなどのイベントドリブンなツールキットを用いて実装されるGUI全体をViewだとしているのである。
図にすると次のようになる。

Class diagram of MVC in the GoF design pattern book
図5-1: GoF本のMVCのクラス図(静的構造図)

Communication diagram of MVC in the GoF design pattern book
図5-2: GoF本のMVCのコミュニケーション図(動的構造図)

ポイントとしては、Viewがユーザーイベントの配信を制御することが可能になっており、Original MVCではV-C間の関連におけるControllerの役割だったものの大部分がViewに移動している。また、ViewはControllerより先に存在する前提であり、Viewが表示されていない状態からControllerがView上にメニュー画面の表示を要求するようなことは想定されていない(Swing等のGUIフレームワークを使えば、最初からGUIが何か表示されているのが普通だから、想像は難しくない)。

ViewとControllerの関連の向きがOriginal MVCと逆であることをわかりやすくするため、Controllerのデバイスドライバー/ウィンドウシステムとしての役割を省いたのが、次の図である。

Communication diagram of MVC in the GoF book
図5-3: GoF本の記述に沿ったMVCのコミュニケーション図(簡略化版)


このMVCのモデル(以下、GoF MVCとする)は、GoF本のテーマにはよく乗っており、同書の以下のデザインパターンが使われていると書かれるのは非常に納得できる。
・Observer
・Strategy
・Composite
・Factory Method
・Decorator

Observer patternが使われることは言うまでもないが、Modelが変化すると、observerとして登録されている全てのViewに何か変化があったことが通知されることを実現するのに使われている。
Observer pattern in GoF MVC
図5-4: GoF MVCにおけるObserverパターン

Strategy patternは、ユーザー入力に対するViewの振る舞いを決めるControllerが、Viewのインスタンス毎に切替可能であることを実現するのに使われている。多くのGUIフレームワークでは、イベントのコールバック関数(リスナー)が動的に登録可能であることに相当する。ここではControllerがViewの一部なのは、上述の通りである。
Strategy pattern in GoF MVC
図5-5: GoF MVCにおけるStrategyパターン

Composite patternは、View同士が包含関係になり、親Viewが受けたイベントを、内包するViewに伝搬することにより、複合ViewをViewと同じように扱うことを可能にするのに用いられている。GUIフレームワークでは、例えばコンテナの中にコンテナを含めることに相当する。Original MVCの"The Model-View-Controller (MVC) Its Past and Present"のP-9にある"Tool as a composite"も、大体同じような内容である。
Composite pattern in Gof MVC
図5-6: GoF MVCにおけるCompositeパターン

Factory Methodパターンは、各Viewのdefault controllerを得るのに用いられる、とされる。これによって具象Viewから具象Controllerへの依存を無くすことができ、例えば具象ViewがControllerのいずれかのサブクラスを指定してインスタンスをcreateする必要が無くなる。GUIフレームワークでは、起動時のパーツの配置や初期設定をアプリケーションのmainクラスがまとめて保持することが、強いて言えばこれに相当するだろうか。(世の中にはあるのかも知れないが、筆者はあまりControllerのFactoryというのを見たことがない)
Factory Method pattern in GoF MVC
図5-7: GoF MVCにおけるFactory Methodパターン

Decoratorパターンは、Viewのサブクラスに共通する機能の追加を、それぞれのサブクラスを新たに作ることなく、委譲を用いて実現するのに用いられる。GUIツールキットでは、例えばGoF本には、各コンポーネント(クラス)にスクロール機能を追加する時に用いられると書かれている。
オブジェクト指向の経験則として、既存クラスの拡張や既存クラスへの機能追加は、派生クラスを作成するより、AdapterやDecoratorなどを使った委譲によって行う方が良いことが多いと言われることがある。小規模な機能拡張で一々、それぞれの機能の有無毎に派生クラスを作成するのは面倒で非効率であることを考えば、納得できる。
Decorator pattern in GoF MVC
図5-8: GoF MVCにおけるDecoratorパターン


世の中にC→Vの関連が無くV→Cの関連があるMVCパターンの図が存在するのは、GoF本の記述が原因であろう。
また、MVCのデザインパターン的な側面を語られる時は大体、V-C間の関連はViewからControllerへの関連であることも興味深い。V-C間の関連がControllerからViewである、Original MVCに則してGoFのデザインパターンが語られることはほとんど無い。
これは、既存の多くのGUIフレームワークに当てはめてMVCを解釈するには悪くないし、MVCが将来そのような考え方に置き換わっていくのは必然なのかも知れないが、それは筆者にはどうしてもMVCの拡大解釈であり、MVCとは別の名前を付けるべきだったように思える。

GoF本に書かれているMVCは、極端に言えば、Controllerが無くても動作可能なMVCアーキテクチャーである。ウィンドウシステムがミドルウェアに、データモデルや表示系アプリがアプリケーション層にあれば、アプリケーション層だけを見るとControllerが存在しない。
実際、GoF本には、何もしないControllerをViewに与えることによって…という記述があるし、Original MVC的にはViewからのModelの更新はあり得る訳だから、システム全体としてController無しでMVCパターンを実装することも可能だということになる。

ControllerはViewとModelの橋渡しに過ぎず、MVCモデルはViewとModelが主役、というのはMVCの本質であり、それを強調することは悪いことではないと思うが、Controllerの役割やC-Vの関連についてほとんど触れられないのは如何なものであろうか。MVCの本質でなくても、Controllerの位置付けはMVCの必須構成要件である。
オブジェクト指向的に考えると、Controllerのオブジェクトは本質的には不要なので、どの方向から考えても結局はControllerの責務は最小にされるべきだという結論になるからだ、としても、ControllerがViewの一部であるように表現してしまうのは、MVCの説明としては問題があるのではないか。

筆者は、GoF本の記述は、テーマ的にMVCについて触れない訳にはいかないから、同書の内容、あるいは現存するGUIフレームワーク(筆頭著者のErich Gamma氏はJavaとの結び付きが強いからAWTだろうか)と整合する為に、このようにされたのだと考えるべきものだと思う。

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

さて、2つ前のエントリーに書いた図1-1図1-2の最もシンプルなMVCパターンでは、すぐに行き詰まることを多くの人が知っている。というか、これではControllerがメニュー画面を出すことすらできない。Controllerの定義から、メニュー画面はControllerそのものであるが、画面表示するにはModelを変更するしかないからである。

まさか、ControllerがViewに依存しないように、メニュー画面のイメージをModelに送るようにすることはあり得ない。多少はViewの使い方を知っていてViewに対するメッセージをModelに渡すなら、それはControllerがViewに依存していることになるので無駄である。Viewへのメッセージの文法を知っているなら直接Viewにメッセージを送れば良い。

ViewとControllerとの間に関連も依存も無いMVCが最も美しい、と考えるあまり、メニュー画面の動作をもModelに含めるのが正しい、突き詰めると、アプリケーションの動作は全てModelにあるのが正しい、と考える人は少なくないが、それは本来のMVCパターンではない。
実は、originalなMVCに答えがある。

"MODELS-VIEWS-CONTROLLERS"のControllerの定義より
It provides means for user output by presenting the user with menus or other means of giving commands and data. The controller receives such user output, translates it into the appropriate messages and pass these messages on to one or more of the views.
(訳:Controllerは、ユーザーにメニューを見せること、または他のコマンドとデータを渡す手段により、ユーザーからの出力手段を提供する。Controllerはユーザーからの出力を適切なメッセージに変換し、そのメッセージを1つ以上のViewに渡す。)

つまり、元々、メニュー画面のようなControllerの表示は、Controllerが直接Viewにアクセスすることによって行うという考え方なのである。図にすると次のようになる。

Class diagram of MVC with V-C connection
図2-1: Controllerの表示が可能なMVCのクラス図(静的構造図)

Communication diagram of MVC with V-C connection
図2-2: Controllerの表示が可能なMVCのコミュニケーション図(動的構造図)

図1との違いのポイントを挙げる。
  • ConcreteViewにControllerによる表示のためのI/Fがある
  • ConcreteControllerからConcreteViewへの関連がある
  • ControllerのViewのみの変更は、C-Vに閉じて完結される

この具象Controllerと具象Viewとの関連は必須ではない(全てのViewがControllerの表示を行う必要はない、CUIやリモート制御だとModelのViewがControllerのUIを表示しないこともある)ので、抽象Controllerと抽象Viewとの間には現れない。

C-V間の関連が無いMVCは、抽象レベルだけを取り上げた、MVCの一部のエッセンスだけを示したものである。それで済む時もあるが、それが最も美しいということではない。
ソフトウェアのデザインパターンをかじった人ならわかると思うが、抽象クラスだけで構成されるパターンは存在しない。というより、抽象クラスを含むパターンは、オブジェクト指向の「依存関係逆転の原則」の存在箇所の明確化のためにも、最低どれか1つの具象クラスが無いと成り立たない。具象クラスまで含めてのデザインパターンである。

ディスプレイに表示するViewがあって、UIがそのディスプレイ上に無いシステムは、MVCパターンとして考える意味が無い(何の為にViewを分離しているのかわからない)。MVCパターンは元々GUIのあるシステムを対象に含めているので、その要素を省いて語るべきではないと、筆者は考える。


"MODELS-VIEWS-CONTROLLERS"のControllerの定義には、他にもV-C間の具象レベルでの関連が示されている。

Conversely, a view should never know about user input, such as mouse operations and keystrokes. It should always be possible to write a method in a controller that sends messages to views which exactly reproduce any sequence of user commands.
(訳:同様に、全てのviewはマウス操作やキー入力といったユーザー入力には一切関知しない。ユーザーコマンド列を再生成するだけのviewにメッセージを送るmethodをControllerに書くことは可能なだけである。)
この文書には他に"user output"という表現もあって、"user input"と"messages"と"user commands"の違いがわかりにくい(はっきり言って、筆者にはわからない)が、"THING-MODEL-VIEW-EDITOR"のVIEWのEXAMPLE 1の所に
It understands a message asking it for an item that is positioned at a given point within its frame, and a message asking it to select a given item.
(筆者注:この文脈ではframeはControllerによる表示のこと。"a given point within its frame"と書くことにより、"user input"そのものではなく、抽象的な意味合いの位置情報であることを強調しているものと思われる)
One possible sequence for selection is that the Editor reacts to redbug and asks the ListView for the item that is pointed to. The Editor then asks the ListView and any other Views to select that item.
(筆者注:この文脈ではEditorは具象Controller、ListViewは具象Viewのこと)
とあるので、Controllerは、現在Viewがある場所に何を表示しているかを問い合わせることができる、という意味だと解釈するのが妥当であろう。マウス操作による画面上のクリックなど、ユーザーがView上の表示に依存する操作を行った場合、Viewがその位置に何を表示しているかがわからない限り、Controllerはユーザーの指示を解釈できないが、その問題を解決する為の必要最小限のサポートをViewが(あくまでユーザー入力の生データには関知せずに)行うべきだということである。

また、その少し後ろのEXAMPLE 4の所に、

In addition, it will need some operations on the View itself, they have to do with the positioning of the symbols in the diagram.
つまり、Modelの要素の表示位置を変えるなど、Modelの変更とは無関係にModelのViewが変化する場合は、そのためのI/F(呼び出すのはController)がViewに必要になるということである。

また、"MODELS-VIEWS-CONTROLLERS"に戻って、VIEWの定義に、次のような具象M-V間の関係が書かれている。

A view ... gets the data necessary for the presentation from the model by asking questions. It may also update the model by sending appropriate messages. All these questions and messages ...
つまり、ViewがModelを変更することもあり得るということである。これだけでは何のことかさっぱりわからないが、"THING-MODEL-VIEW-EDITOR"のVIEWの所の冒頭に
A View is also able to perform such operations upon the Model that is reasonabely associated with that View.
とあり、その後ろのEXAMPLE 6の所に
It is also able to pass on operations on the network and its activities that are related to this particular View. Typical operations have to do with modifying the current schedule.
(筆者注:ここではnetworkはModel、activitiesとscheduleはnetworkの要素)
とあるので、(Controllerを介して)Modelの要素に十分に直結したView上の変更が発生すれば、それに対応する変更を、Controllerに関係なく(Controllerを介さずに)、Viewが直接Modelに対して行っても良いということなのである。

これらを含め、MVCパターンは次のように図示できる。

Class diagram of MVC without V-C connection
図3-1: MVCのクラス図(静的構造図)

Communication diagram of MVC without V-C connection
図3-2: MVCのコミュニケーション図(図2-2からの差分のみ)

ところで、以前のエントリーに、J2EEやASP.NETなどがMVCを参考にしていると書いたが、これらで使われているのは元々のMVCパターンとは異なる、"JSP Model 2 architecture"または単に"Model 2"と呼ばれるアーキテクチャーである。
一応、Webサーバー側のMVCパターン実装、ということになっているが、基本的にはサーバー側はconnectionlessかつstatelessであり、Viewの出力はHTTP requestに対するresponseとしてユーザーに出力するため、Modelの状態が変化した時にViewが表示を更新する、ということができず、M-V間にObserverパターンの関係が無いのが特徴である。

Class diagram of "Model 2"
図4-1: "Model 2"のクラス図

Communication diagram of "Model 2"
図4-2: "Model 2"のコミュニケーション図

元々、"Model 2"が最初に現れた時にはMVCの用語は使われていなかったが、次第にMVCの用語を用いて説明されるようになった(下記参考リンク参照)。それにより、MVCと"Model 2"がごっちゃにされ、人々のMVCの定義がバラバラになり、MVCをややこしくした。
筆者は、ViewがObserverでないMVCはあり得ないと思うので、"Model 2"もMVCではないと思う(し、結構多くの人に賛同頂けるものだと信じている)が、特にWeb系ではそんなことを気にしない人も少なくないようである。
"Model 2"を含めると本当に話がややこしくなるので、このサイトでは"Model 2"はMVCパターンに含めない。

●"Model 2"の参考リンク
  • Understanding JSP Model 2 architecture - JavaWorld --- 現時点での事実上の原典
  • MVC, Model 2, Java WebApps (Brian's Waste of Time) --- "Then the Web happens and Sun starts talking about Model2 in terms of MVC."("Model 2"がMVCの用語を使って語られるようになり、Sunもそれに乗っかった)ということが書かれている。
  • Java EE 5のTutorialの中の1ページ --- Webアプリの世界ではMVCはModel-2と同じものだとみなされることがしばしばある、と書かれている。
    Note - When employed in a web application, the MVC architecture is often referred to as a Model-2 architecture. The bookstore example discussed in Chapter 4, Java Servlet Technology, which intermixes presentation and business logic, follows what is known as a Model-1 architecture. The Model-2 architecture is the recommended approach to designing web applications.
  • How Struts Implements Model 2 --- "The Origins of Model 1/Model 2"という章に、MVCとModel 2との関係が書かれている。
  • ASP.NET Presentation Patterns --- The original MVCと"Model2"と"ASP.NET MVC Framework"との関係が解説されている。

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

前エントリーに引き続き、MVCパターンについて、その利点と、何が崩れるとそれが失われるかを考えてみる。以下、一部に図1-1図1-2には無いV-C間の関連が前提になっている記述があるが、それについては次のエントリーで説明する。

  1. Viewの追加/変更がViewクラスに閉じ、Modelに影響しない
  2. ModelはView/Controllerへの依存が無く、安定度を上げることができる
  3. ModelとViewとをそのままにして、Controllerを差し替えることができる
  4. ModelはViewの表示状態に関係なく動作することができる
  5. Model+ControllerとViewを並列実行することができる
(1)は、物理モデルやビジネスロジックと比較して、アプリケーションの表示系(Presentation)は変更が入りやすいことが前提となっており、変更されやすい部分、すなわちViewと変更されにくい部分、すなわちModelとを分離することによって、Viewの変更の影響が及ぶ範囲を限るのが、そもそもMVCパターンの発想の原点であり、第1の目的である。
元々、ControllerはViewとModelとを繋ぐ役割で小規模だと考えられており、Viewの変更がControllerに影響することについては論じられることが少ないが、Controllerが肥大し、変更が入りにくいロジックを含むようになって、しかもControllerがViewに依存するようになると、Viewの変更の影響が変更されにくいクラスに及ぶようになり、この第1の目的に合わなくなる。

(2)は、Modelの品質は特に重要であることが前提にあり、できるだけ他への依存を無くし、個別に重点的にテストして、変更されにくいコードとして確立することを目的とした結果である。もちろんViewやControllerもきっちりテストしてバグの少ないのものに仕上げるべきであるが、ソフトウェアのバグを完全に無くすのは確率的に不可能であることを理解し、特に重点的に品質確保するコードの範囲を選択して絞るのは、現実世界では絶対に必要なことである。
一般に、自パッケージからの依存数をCa、他のパッケージへの依存数をCeとした時にCe/(Ca+Ce)と計算される、クラスの不安定度(Instability)は、0か1に近い方が良いとされるが、M,V,Cそれぞれをパッケージとして、Model内のクラスの不安定度をほぼ0(ViewのObserver I/F以外には外部パッケージへの依存が無い)にできるのがMVCパターンのメリットである。ModelがViewに依存するようになって安定度が下がったり、Controllerに安定度が高いクラスが混ざってController全体の安定度が中途半端になると、このメリットが損なわれることになる。

(3)は、ビジネスロジックやドメインモデルをユーザーインターフェースから分離することによって、ビジネスロジックやドメインモデルに対する同じ操作を複数のUIから実行できる(例えば、キー入力でもマウス入力でも同じ操作が実行できる、異なるメニュー画面から同じ操作が実行できるなど)構成がスムーズに実装できることを意味する。当然、MVCパターンはUIが複数あるソフトウェアを対象にしていることになる。
この利点により、ControllerをModelのテスト用のUIまたはテストコードに置き換えることによって、Modelを全く変更せずにテストすることが可能になる。GUIを持つアプリケーションにテスト用のCUIを追加したり、Modelに対して連続してメッセージ送信する自動テストプログラムを追加することも可能である。
プログラマーの長年の経験則として、結局ソフトウェア開発はいかに効率よくテストすることを可能にするかに掛かっている、というのがあり、特にここ10年くらいの流れである。テストドリブン開発やxUnitフレームワークが邪道だと否定される様子はほとんど無い。テストさえすりゃ作りはどうでもいい、ということに繋がる考え方でうまく行く筈が無いだろう、と、まともな科学者や技術者ならそう考えるものだが、現場は感覚的にも実際にも、ある程度以上きちんと作るのは困難になるので、限界を追求すると、きちんと作るよりきちんとテストすることにコストを掛ける方が成功するのが、人間の知力の限界を物語る現実なのである。

(4)は、計算処理中に表示処理を混ぜることがいかにプログラムを保守しにくくしてきたかを多くの人が思い知った結果であり、MVCパターンに限らず、データとプレゼンテーションを分離することは、よくなされることである。
データ及びそれに対する操作(business logic)に比べ、データの表現手段(presentation logic)はよく変更されるので、business logic内に表示用の処理が混ざっているとプログラマーはよく嫌な思いをする、ということもあるが、その前に、business logicとpresentation logicは品質確保の要件や要求レベルが異なることが多いのである。

(5)は、やはりビジネスロジックと表示系に要求される品質が異なる前提が根底にあるために利点と言えるものであり、表示系がメインのシステムでない限りは、出力先が人間である表示系の動作速度は比較的クリティカルではないので、動作速度が問題になると、自然に表示系をビジネスロジックとは非同期に優先度を下げて動作させようということになる。
逆に言うと、MVCパターンは表示系に求められる性能が高い、表示系に対する要求がクリティカルなシステムには適さない可能性がある。極端に考えると、例えば映像効果のためのシステムでは、表示デバイスの制御が問題の中心であり、映像が最終的な出力なので、映像出力系がModel、目的の映像出力を得るためのUIの表示系がViewだと設計することが考えられる。なので、もしUIに表示効果バリバリのフレームレートの高い描画が求められると、その描画系はViewではなくModelとして扱う必要が出てくることになり、本来のModelとViewのためのModelと、2つのModelが現れることになる。その2つのModelの調停をどこが担うか(Controllerが担うか、それら2つのModelを統括するMagager Modelを作るか)という問題もあるし、そもそも変更が入り易いUIをModelから分離するという目的に反してしまう問題がある。

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対多と書いている。
(続く)