« 2012年09月 | メイン | 2012年11月 »

2012年10月 アーカイブ

2012年10月08日

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から分離するという目的に反してしまう問題がある。

2012年10月21日

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"との関係が解説されている。

About 2012年10月

2012年10月にブログ「Weblog on mebius.tokaichiba.jp」に投稿されたすべてのエントリーです。過去のものから新しいものへ順番に並んでいます。

前のアーカイブは2012年09月です。

次のアーカイブは2012年11月です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。

Powered by
Movable Type 3.35