ソフトウェアアーキテクチャの歴史
注意: このメモはWIPです
モチベーション
改めて ソフトウェアアーキテクチャ GUI のアーキテクチャの歴史を調べてみたくなった。本来の MVC とは何か?何が正しくて何が間違っているか?も重要なのだが、それよりは、なぜそれが生まれたのか?何を解決しようとしたのか?どのような問題点が生まれて、それをどう工夫して解決・発展してきたのか?を知りたい。しかし、そういうことがまとまっている日本語の情報が少ないので、自分で色々かいつまんでメモしておく。
MVC の原点は 70 年代にまで遡り、実装としては Smalltalk-80 のクラスライブラリとして実装されたのが最初だと思われる。しかし、後世に大きな影響を及ぼしたポイントをいくつか持ちつつも、当時のアーキテクチャが現代においてそのまま利用されているケースはほぼないといっていい。したがって、単に MVC といった時には大抵最初期の MVC を指すことは少なく、区別するために最初期の MVC は特に Classic MVC(古典的 MVC) と呼称されることが多い。 DynaBook
MVC が生まれてくる背景には、DynaBook と言われるコンピュータの構想があった。MVC の生みの親とされる Trygve Reenskaug 氏も、MVC は DynaBook の背景なしには語れないといっている。 I spent a very happy and inspiring year as a visiting scientist with the Learning Research Gorup (LRG) at Xerox PARC from the summer og 1978 to the summer of 1979. This group was dedicated to Alan Kay's vision of the Dynabook; a portable computer that should contain all data of interest to its owner/user. Very importantly, these data included the programs the owner used to manipulate them. The owner/user should be able to understand and write the programs, thus gaining ascendancy over the computer.
The MVC notes should be read on this background. The user was the czar; everything done at LRG was done to support him.
DynaBook とは、Alan Kay 氏によって立てられた理想のコンピュータの構想で、その詳細は 1972 年に A Personal Computer for Children of All Ages で記述されている (翻訳: あらゆる年齢の「子供たち」のためのパーソナルコンピュータ)。DynaBook とは、GUIを搭載したA4サイズ程度の片手で持てるような小型のコンピュータであり、それを用いる人間の思考能力を高める存在 を目指していた。人間の思考能力を高める、とは、人間が何かを思考し試すことを繰り返し、それによって深い学びを得る過程を DynaBook が手助けすることを指して、そのために DynaBook の OS はユーザが直感的に扱えるような要素で構成されており、ユーザが自分自身でシステム自体を再定義できるようなものを目指していた。実際、先の A Personal Computer for Children of All Ages では、子供が DynaBook を利用して天体に関する簡単なシステムを構築し、学んだことを実際に試すことで学んだことに対してより理解を深めていく様子が描かれている。 Xerox のパロアルト研究所 (PARC) では、この DynaBook の機能の一部を実装した 暫定ダイナブック の開発が、ハードウェアとして Alto、ソフトウェア(OS)として Smalltalk を採用して進められた。Alto が販売されることはついぞなかったが、マウスによる GUI 操作、ウインドウシステム、メニュー操作など、現代のパソコンに強く影響を与えることになった様々な特徴を備えており、これを見たスティーブ・ジョブスにも大きな影響を与え、後の Macintosh 開発のきっかけとなった。
Alan Kay 氏も所属していた Xerox PARC には Learning Research Group (LRG) というグループがあり、DynaBook の構想に関わる研究が行われていて、Trygve Reenskaug 氏もその一員だった。氏はオスロ大学の名誉教授でもあって、オスロ大学のホームページには個人のページがあり、MVC に関する情報が公開されている。
予めニーズに応じてシステムを作るのではなく、ユーザ自身がその時のニーズに合わせてシステムを組み替えられる
コンピュータサイエンスについては素人だが、興味のある分野ついては玄人なユーザでも、そのような組み替えができる
It must be trivial for a user to modify his DynaBook system at any time both in terms of representations and abstractions. Such modifications apply equally to the programs and the current data base.
上記のような要件を満たすためには、ソフトウェアの構造が非プログラマでも扱えるような柔軟な構造になっている必要がある。 そこで、これを実現するためのアーキテクチャ、メタファーが考え出された。そこで最初に考え出されたのが MVC の前身となるThing-Model-View-Editor であり、その内容は以下のようなものだった。 Thing
取り組むべき巨大なプロジェクト
巨大な橋の建設や、発電所、石油プラットフォームの設計と建設など
Model
コンピュータ上でのデータ形式を抽象化した表現
Model は、コンピュータ上では、それら自身を処理するメソッドと、データの集まりとして表現される
View については知らない
View
Model の視覚的な表現
1 つの Model に複数紐づくことができる (= 1つのModelは複数の視覚的表現が可能)
Editor
ユーザとViewの間のインタフェース
ユーザが命令を実行できるシステムを提供する (例: 動的に操作できるメニュー)
TMVE の現代における MVC との大きな違いは、現代の MVC は「コンピュータ が タスクをこなす方法」であるのに対し、TMVE は「ユーザがコンピュータを 利用して タスクをこなす方法」のメタファーとなっている点である。例えば、Thing は取り組むべきタスクそのものを表しており、これはコンピュータ外の要素である。したがって、TMVE はソフトウェアアーキテクチャではなく、人間がコンピュータを用いて複雑な課題に立ち向かう際の構成要素メタファーと捉えるのが良さそうだ。 MVC (T.Reenskaug, 1979)
TMVE から MVC と言う名前に落ち着いたのは、TMVE のメモが記述されてから半年以上議論を重ねた後になる。その時点での改めての用語の定義が Models-Views-Controllers に示されており、この定義は以下のようになっている。結果、Thing はなくなり、Editor は Controller の一形態として定義し直された。 Models
知識の表現
ユーザのメンタルモデル と一対一で対応づく
Views
Model の視覚的な表現
ユーザからの入力は直接は受け付けない
Controllers
ユーザとシステムのリンク
ユーザ入力を受け付け、View が適切な箇所に表示されるように調整する
Editor
特別なコントローラー
View 上に描画されている情報を編集できる
Classic MVC が現代の MVC に最も強く影響を残した部分として、Model と Presentation の分離 (Separated Presentation) が挙げられる。Model と View を各々独立して定義することで、Model を全く異なる複数の View で表現できるようになる。つまり、同一の Model を異なる方法で描画できるようになる (例えば、同じデータを円グラフで表示することも、棒グラフで表示することもできるし、もっと極端な例だと、GUI から CUI に変更することもできる)。 また、ここで出てきている重要な概念として ユーザのメンタルモデル がある。当時で言う メンタルモデル について正確な定義は自分にはわからないが、様々な記述を見ていると、この メンタルモデル は DynaBook を導入する前からユーザ自身の中にある、現実世界に対する認識 であり、それをコンピュータ上にデジタル化して再現したものが Model と呼ばれているように思える。Reenskaug 氏のページでも、MVCの目的は、ユーザの中のメンタルモデルとコンピュータ上のデジタルモデルの間のギャップを埋めること と説明されている。
The essential purpose of MVC is to bridge the gap between the human user's mental model and the digital model that exists in the computer.
http://heim.ifi.uio.no/~trygver/themes/mvc/MVC-2006.gif
ユーザはもともと現実世界に対する認識、メンタルモデル を持っており、それを脳内で扱って課題を解決している、と捉えられていて、その認識をデジタルに落とし込み、それを View を介して閲覧し、Controller を介して操作できるようにすると、ユーザは あたかも自身のメンタルモデルを DynaBook 上で自在に操作/閲覧できているかのような錯覚に陥ることができ、さらには、コンピュータのサポートがあることで、従来より効率的に課題に取り組めるようになる、と考えられたのではないか。
こういった経緯から、MVC 自体は、「巨大で複雑な問題を解決するための一般的なソリューション」として考案されたものと言える。そしてそのソリューションとは、メンタルモデルをコンピュータ上に再現し、それを GUI を介して操作するというアーキテクチャで稼働するシステムであり、そのアーキテクチャの要素名が Model, View, Controller である、と言えそうだ。 MVC was conceived as a general solution to the problem of users controlling a large and complex data set.
MVC (Smalltalk-80, 1988)
Reenskaug 氏が Xerox PARC を抜けた後、Smalltalk の開発は ParcPlace と言う別会社に引き継がれ、1988 年に Jim Althoff 氏らによって Smalltalk-80 のクラスライブラリとして MVC が実装された。ただ、この時の実装では Controller の扱いが original とは微妙に異なっていた、と Reenskaug 氏は指摘している。元の MVC では Controller は 適切な View の生成とその調整 を責務としていたが、Smalltalk-80 の Controller は original の定義でいう Editor (ユーザの入力を受け付け、View に描画されている情報を編集できる) の責務を担うものとなっていた。
Jim Althoff uses the term Controller somewhat differently from me. An important aspect of the original MVC was that its Controller was responsible for creating and coordinating its subordinate views.
(中略)
The Smalltalk-80 Controller is here a fourth element called Editor.
Model, View, Controller は各々抽象クラスとして定義されており、論文内ではその概要や、抽象クラスに含まれている機能、具体的なサブクラスの実装例が紹介されている。以下は、論文内で改めて説明されている MVC 各々の定義になる。 Model
アプリケーションの中心となる構造
シンプルな数値かもしれないし、文字列かもしれないし、もっと複雑なオブジェクトかもしれない
dependents として、自身に依存する View, Controller をもつ
自身の変更時に全ての dependents に対し通知をブロードキャストする
View
あらゆるグラフィカルなものを扱う
Model を保持し、保持した Model に対してリクエストを発行し、取得したデータを描画する
SubView や SuperView を持つことができる
Controller
ユーザからの入力を受け付け、Model や特定の View の操作を行う
低レベルなユーザのジェスチャを解釈し、モデルにとって意味のあるアクションに変換する
メンバ変数として、model, view, sensor を持つ
Controller は複数存在し得るが、active にユーザの入力を受け付けるのは常に 1 つのみ
よく勘違いされるのは、Controller は Model と View の仲介 ではない という点
Model, View 間の関心事の分離 (ビジネスロジックと UI の分離) は、Observer パターンによって達成されている
Controller は、ユーザからの入力をハンドリングする役割でしかない
https://gyazo.com/32d8e77435d1ee27e1c5ae9cbe82f002
基本的なライフサイクルとして以下が紹介されている。
1. ユーザが入力をする
2. active な Controller が Model に変更を通知する
3. Model は自身の状態を変更し、dependents (View, Controller) に変更をブロードキャストする
4. 通知を受けた View は、必要であれば Model から情報を取得し、描画を更新する
5. 通知を受けた Controller は、Model の新しい状態に合わせて少し振る舞いを変えるかもしれない
以下は、各クラスのインスタンス変数の例。定義通りの依存関係にあることがわかる (ここで、View -> Controller への依存があるが、これは実装の副産物であり、MVC パターンの本質とは関係がない。これは、View によって Controller のインスタンスを初期化するためだけに存在している)。
https://gyazo.com/72cef1195d1ac291f86b1f2644565a81
これにより、各々が Model を Observe しているので、ウィジェット同士が相互に通信しあう必要はない
GUI ウィジェットは、さらに Controller (ユーザの入力を扱う) と View (Modelの状態を描画する) に分離されている
Controller と View は (ほとんど) 直接通信せず、各々が Model と直接通信する
画面の各要素 (GUIウィジェット) 毎に、View/Controller のペアが存在する
1画面内のユーザ操作をまとめて監視するようなオブジェクトは存在しない
ユーザの入力を最初にハンドリングするのは Controller になる
Classic MVC が現代に強く影響した点は、プレゼンテーションとモデルの分離、Observer パターンによる同期 の二点かと思われる。しかし、これは現代のフレームワークに強い影響を与えはしたものの、現代のリッチな GUI には適さないと、Martin Fowler 氏は指摘している。氏の指摘は以下の二点である。 View logic をどこに置くか?
例えば、出力する文字に色をつけるかつけないか、を判断するロジックは、ドメインロジックではない
View state をどこに置くか?
例えば、リストの中のどれが選択中であるか?という状態は、Model には含まれない
80 年代当初は、そもそも GUI 自体がまだまだ未熟な分野であり、画面表示もモノクロで色は付いていなかったため、View が現代と比較して非常に単純なものだった。また、Classic MVC のコントローラは、ユーザの低レベルな入力 (センサー値等) を直接解釈していたが、これも現代の GUI フレームワークではほぼ OS やその他ライブラリから提供されることが多く、そのままの形で利用されている例は少ない。 Smalltalk は既述の通り、元は Xerox PARC で誕生したが、その後 Xerox PARC は ParcPlace という別会社に分離した。ParcPlace は VisualWorks というクロスプラットフォームな Smalltalk の統合開発環境を販売しており、これは他にも数ある Smalltalk の派生の中の1つとなっている。
VisualWorks では、前述の View logic/View state の問題を解消可能なパターンがライブラリとして導入されており、これは Marin Fowler 氏により Application Model として紹介されている。 Application Model の説明の前に、その理解のために必要な別のパターンである Property Object について解説する。Property Object とは、プロパティの値をラップしたオブジェクト のことを指している。下記は Smalltalk のコードで少しわかりにくいが、aPerson オブジェクトがそのプロパティに、プリミティブな型を格納している代わりに Property Object を格納しており、Property Object は value メソッドで値の取得 (get)、value: メソッドで値の設定 (set) が行える。
code:smalltalk
"Person オブジェクトの name に格納された Property Object から value を取得する"
temp = aPerson name value
"Person オブジェクトの name に格納された Property Object に 'martin' を格納する"
aPerson name value: 'martin'
このように、値を直接保持せず、値をラップしたようなオブジェクトは、Value Model というパターンとしても知られる。このようなパターンの利点には、以下のようなものがある。
Property Object を利用するクライアントは、統一されたインタフェースからその値を取得/操作できる
あるオブジェクトが Property Object として値を保持している時、クライアントはその値にどのようにアクセスすれば良いのか?を考えなくとも良い
Property Object を保持するオブジェクトは、プロパティをカプセル化できる
あるオブジェクトが Property Object を保持している時、クライアントはその Property Object の値がどこからきたのか?を考えなくても良い
例えば、Person オブジェクトが name という Property Object を保持している時、その実際の値 (string値) が、DB 上に保持されているのか?API 経由で取得してきたものなのか?新しく作られたものなのか?などを気にする必要はない
特に重要な性質が後者で、この性質を活かして、実際の Model の値をラップする Property Object を保持しているオブジェクトが Application Model である。Application Model は、View と Model の間の中間層としての役割を果たす。ただし、VisualWorks 上では Property Object という名称は用いられておらず、代わりに Application Model は Aspect Adapter という名前の Property Object を保持する。Aspect Adapter は、Model の特定のプロパティに対する Property Object として振る舞う。また、Observer パターンの実装を内包しており、対応するModel の値を常に監視し、それが更新された時に、更新内容を対応する View に伝えることができる。
VisualWorks 上では、以下のような手順で Aspect Adapter を設定するようだ。
1. GUI コンポーネント (テキストボックスやボタン等) を追加する
2. GUI コンポーネントに AspectAdapter を追加する
3. AspectAdapter に特定の Model の値を監視させる
4-a. Model の値に変更があると、GUI コンポーネントに通知される
4-b. GUI コンポーネントに変更があると、Model に反映される
https://gyazo.com/aeaf54ecfb27640fc68c47182a7ef9ef
Smalltalk のコードで AspectAdapter の定義を見ると、以下のようになる。
code:smalltalk
"Aspect Adapter である messageInput の定義"
"モデル anAA の値 m1 の変更を監視し、変更時には GUI コンポーネントに通知する"
messageInput := (AspectAdaptor subject: anAA sendsUpdates: true) forAspect: #m1. Application Model によって、View state/View logic の問題が解決できる。
View state については、View 固有の状態を、Model ではなく Aspect Adapter として Application Model に保持すれば良い
View からは、Application Model 固有の Aspect Adapter も、Model に実の値を持つ Aspect Adapter も同様に扱える
View logic については、Application Model 内に記述すれば良い
データの値が変更したことは Application Model が検知できるので、それに応じて Application Model でロジックを動作させ、結果として Model や View を変更すれば良い
しかし、VisualWorks では、View state と View をリンクする手段が提供されていない という問題があった。例えば、上図の例でいうと、2つのテキストフィールドに各々 AspectAdapter messageInput と messageOutput が関連している。この時、テキストフィールドは対応する AspectAdapter を Observe している。ここで、m1 の値に応じてテキストフィールドの色を変更したいとする。このように、Model に存在しないアプリケーション固有の状態は Application Model に持たせれば良いのだが、「テキストフィールドの色」と「messageInput の値」をリンクする手段が必要になる。新たにテキストフィールドの色を Observe するクラスを作れば良いが、それは大仰になる。そのため、Application Model は直接 Widget を触れるようになってしまっていた。
Application Model は、Presentation よりではあるが、MVC の中では Model に属す性質のもので、実際 Application Model と View は、元の MVC の Model と View と同じように Observer/Subscriber の関係にある。この関係にある Application Model が直接 Widget をさわれてしまうと、Observer/Subscriber という関係性が崩れてしまう。また、Application Model 上で様々なハックが生まれてしまい、肥大化してしまうという問題があった。
MVP
MVP というアーキテクチャについては、その名称で受け入れられているパターン自体にいくつか種類があるため、簡単には説明できない。原点とも言える Taligent の提唱した MVP から見ていく。
MVP (Taligent, 1996)
MVP は、最初 IBM で生み出され、その後 Taligent (IBM の子会社) の製品 VisualAge のクラスライブラリ IBM Open Class に導入された。1992年から1994年の間に Taligent でパターンの主な要素は利用されていたが、1996 年当時 Taligent に勤務していた Mike Potel 氏によって初めて正式に MVP という名称で記述された (下記リンク)。MVP が実装されたのはバージョン 4.0 からで、以下の論文で内容が紹介されている。 MVP では、まず、古典的な Smalltalk-80 の MVC を、Model と View/Controller の2つに分けて考えている。
https://gyazo.com/25a8e65dab70c9b1037233fdf1241827https://gyazo.com/629d7fb8a538bc9c85742e69ec462ce4
そして、さらに以下のように要素を分解している。
Data Management
Model は、Smalltalk の Model と同一で、データをカプセル化し、R/W 用のメソッドを持つ
Commands は、データに対して実行できる操作を定義するコンポーネントで、Model の Selection に対して実行可能な操作を抽象化している
Selections は、どのデータを操作するか指定するコンポーネントで、Model の異なるサブセット、例えば表データに対する列や行などを抽象化している
User Input
View は、モデルの視覚的表現であり、アプリケーションにおける画面とウィジェットで構成されている
Interactor は、マウスの動きやキーボード入力、チェックボックスやメニュー項目の選択などのユーザ操作を抽象化しており、それらのユーザ操作がどのようなモデルで実行される操作にマッピングされるかを扱う
Presenter は、Commnads/Selections と Interactor 間の中間層であり、コンポーネント間の対話を調整するコンポーネント。適切な Model, Selections, Commands, View, Interactor の作成と、そのワークフロー、ライフサイクルを管理する
https://gyazo.com/cf966165ce3643946195136fdbb0d288
Model と View の同期には、古典的 MVC と同様に Observer パターンによる同期を利用していた。Taligent MVP における Presenter は、古典的な MVC における Controller のような、ユーザからの入力を直接ハンドリングして View, Model の操作を行う ようなものではなく、Interactor と Command/Selection の仲介を行うロジックを含むモジュール として定義されている。ユーザからの入力をハンドリングするのは、Interactor の責務となっている (つまり、MVC における Controller の主要な責務は、Interactor に移っている)。そのため、Presenter はView 上のウィジェット毎に1つずつ存在する必要はなく、Presenter が複数の View を管理することもできる。
The third question is "How do I put it all together?" This represents the function of the classic Smalltalk controller, but elevated to an application level and taking into account the intermediate selection, command, and interactor concepts. To capture this distinction we refer to this kind of controller as a presenter.
...
The role of the presenter within MVP is to interpret the events and gestures initiated by the user and provide the business logic that maps them onto the appropriate commands for manipulating the model in the intended fashion.
MVP (Dolphin Smalltalk, 1996)
Dolphin Smalltalk あるいは Dolphin とは、Microsoft Windows のための Smalltalk 言語およびその統合開発環境の実装。
1995 年夏、Dolphin の開発チームは、Smalltalk の新しい実装である Dolphin Smalltalk の開発に適した User Interface モデルについて考えていた。VM やコンパイラの実装は終わっていたが、Windows ベースの GUI フレームワークを提供する必要があり、その決定に時間を費やしていた。当時はすでに VisualBasic や IS/2 等による Widget ベースの GUI プログラミングが存在していて、Dolphin もそれに倣って Widget ベースの GUI フレームワーク を作ろうとしていた。
Dolphin の開発チームは、初期は ParcPlace の VisualWorks で利用されている MVC パターンをベースに設計を考えていた。これについては、論文内で以下のようにその特徴と問題点がまとめられている。
MVC (Application Model) の特徴
MVC では、VC が M を Observe することで、各 VC が間接的に同期される
Application Model を V/M の中間層にすることで、そこに View 特有のロジックを配置できる
Controller は、ユーザの低レベルな入力を解釈しモデルにとって意味のあるアクションへ変換する
MVC (Application Model) の問題点
コントローラーという概念は、Microsoft Windows のような GUI 環境にフィットしない
Windows の提供する Widget は、それ自体がコントローラとしての機能を持っている
Application Model が View に直接アクセスするのは、Observer/Subscriber の関係が崩れてしまいよくない
しかし、この関係を厳密に保とうとすると、簡単なことでも遠回りなイベント通知が必要で現実的でない
と、上記のような問題で悩んでいるときに、Taligent の MVP の概念に出会い感銘を受けたという。しかし、Dolphin は元の Taligent の MVP を、「Application Model の置き換えが Presenter である」と間違って捉えていた。実際には、Taligent の MVP においては、Presenter は Smalltalk-80 MVC における Controller の進化形に近かった。したがって、Dolphin Smalltalk も MVP に基づいているとはされているが、同じ MVP でも Taligent とは結果的に異なるものになってしまっている。その結果としての論文から読み取れる Dolphin の MVP の定義は、以下のようになっている。
Model
UI が操作する対象となるデータ
UI についての知識は持たない
MVC(+Application Model) における Application Model とは異なり、UI を参照し操作する、といったことはしない
View
MVC の View と同様
コントローラーの代わりに View 自身が UI イベントを解釈し、意味のあるイベントに変換する
OS に生成されたユーザインタフェースイベント (Windows なら WM_xxxx メッセージ) を解釈する
この方式の方がモダンな OS には適している
変換されたイベントは、Presenter を介してルーティングされ、Model に作用する
Presenter
UI が Model をどのように操作、変更できるかを管理する
MVC の Application Model に相当するが、異なる点は View と直接リンクされているところ
Dolphin MVP は Taligent MVP から Interactor や Commands, Selection を除き単純化した上で、Classic MVC における Controller を Presenter に置き換えた。Dolphin MVP と Smalltalk-80 MVC は形は似ているが、以下の点が異なるのだという。 MVC の Controller の目的は、ユーザ入力を受け付けること。Model の更新はそのついで
Smalltalk-80 の時代は、ユーザの低レベルな入力であるセンサ値等を意味のあるアクションとして解釈していた
この解釈のロジックと画面への出力のロジックは大きく異なるので、Controller/View に分離された
Taligent MVP の Presenter/Interactor も、Controller を拡張したものと捉えて良い (が、Dolphin ではその解釈を誤っていた)
MVP の Presenter の目的は Model を更新すること。View からイベントを委譲されるのはそのついで
Controller がやっていた「ユーザの入力を解釈する」機能は、Dolphin MVP では View に移動している
というのも、Microsoft の提供する Widget には、すでに Smalltalk-80 MVC の Controller の機能が含まれていた
そのため、Smalltalk-80 MVC における Controller や Taligent MVP における Interactor の必要性がなくなった
代わりに、Presenter は View から受け取ったイベントを適切な Model 操作に解釈する中間層としての役割になった
また、MVC + Application Model においては、Application Model が実質 Model であり、Model とプレゼンテーション層は Observer/Subscriber の関係にあるにも関わらず、Model が直接 View 参照してしまう場合がありよくないとされていた。これに対し、Dolphin MVP では Application Model を Presenter として、Model としてのポジションから退けた。これによって、Model と View は Observer/Subscriber としての関連を保たれ、Presenter が Application Model の役割を担い、View state や View logic を持つ。Presenter/View 間は既存の Application Model/View 間よりも密に連携可能な形になっている。
Server MVC (Web MVC)
リッチな GUI には向かない Classic MVC から派生して、View 固有の状態やロジックを切り離した Application Model、MVP などのパターンが生まれた。特に、Dolphin の MVP はネイティブアプリ開発のための派生形と考えられそうだが、Web アプリケーション開発のための派生パターンとして従来の Classic MVC からさらに派生が生まれ始めた。特に明確な括りを表す言葉はなさそうだが、このメモでは Web アプリケーションのサーバーサイドの開発に適用されるパターンということで、Server MVC という用語を用いていく。 JSP Model 2 Architecture (1998)
1990 年代半ばから後半にかけて、Web アプリケーションは主に CGI を使用して開発された。Sun Microsystems は、CGI ベースのアプリケーションをより効率的に実現するための仕組みとして、Java Servlet 1.0 や、1990 年には JSP 1.0 仕様を導入した。この JSP 仕様の最初の仕様には、JSP 技術を利用して Web アプリケーションを構築するための2つのアプローチが示されていた。2 つのアプローチの主な違いは、リクエスト処理がどのコンポーネントにどうやってハンドリングされるのか?だった。 Model 1
同時に、JSP が、クライアントへの出力の描画の責務を持つ 実質的に、Model-View の分離 となっている
https://www.ibm.com/support/knowledgecenter/ja/SSRTLW_9.6.0/com.ibm.etools.struts.doc/images/cstrdoc001.gif
Model 2
Controller Servlet が、どの JSP ページを次に表示するか?決定する 実質的に、Model-View-Controller の分離 となっている。
以下のようなライフサイクルのようだ。
1. ブラウザーがサーブレットに要求を送信
2. サーブレットはデータベースに接続された Java Bean をインスタンス化
3. サーブレットが JSP ページと通信
4. JSP ページが Java Bean と通信
5. JSP ページがブラウザーに応答
https://www.ibm.com/support/knowledgecenter/ja/SSRTLW_9.6.0/com.ibm.etools.struts.doc/images/cstrdoc001a.gif
Model 1 に対し、Model 2 ではController Servlet が導入されている。これにより、ビジネスロジック, プレゼンテーション出力, リクエスト処理 の3つが分離されていて、この分離が MVC の分離として解釈されていることが多い。ドラフト内ではClassic MVC との関連づけはされていなかったが、Java World 誌の「server-side implementation of the popular Model-View-Controller (MVC) design pattern」という記事で類似性が示されたという。 Struts (2000)
Sun によって Model 2 アーキテクチャが導入されたが、Web ベースの MVC パターンを適用する流行を作ったのは Craig R. McClanahan 氏による Struts フレームワークだそうだ。Struts は MVC フレームワークとして導入され、その後 MVC は Java の開発コミュニティに広く採用されるきっかけとなり、リリース翌年には多数のフレームワーク開発のきっかけとなった。 Server MVC の特徴
Classic MVC と同様に、Server MVC も、Controller はユーザの入力を受け付ける。ただし、Classic MVC とは異なり、ユーザの入力はマウス操作やキーボード入力ではなく、HTTP リクエスト になる。また、Web アプリケーションはステートレスであり、View はリクエスト毎に新しくレンダリングされる。そのため、View の同期に Observer パターンは利用されない。これは、これまで紹介してきたパターン群とは大きく異なる点である。 MVVM
Presentation Model (Martin Fowler, 2004)
Presentation Model とは、Martin Fowler 氏によって紹介されているパターンであり、GUI コンポーネントの状態と振る舞いを保持するモデルをさす。VisualWorks の MVC における Application Model と似ているが、Application Model は直接 View (Widget) への参照を保持し更新を行なっている点はあまり綺麗ではなく、その点に関しては Presentation Model の範疇ではないとされている。
GUI は、GUI スクリーン上の状態を保持した Widget から構成される
しかし、GUI の状態を Widget 内に残しておくと、その状態を取得するのが難しくなる
Widget API を通して Widget を操作したり、描画の振る舞いを View クラス内に記述したりしなくてはならない
Presentation Model
View からその状態と振る舞いを引き抜く
ドメインレイヤー (Domain Model) とやり取りし、View での意思決定を最小限に抑えるためのインタフェースを提供する
View は全ての状態を Presentation Model に保持させ、それを頻繁に同期する (Data Binding)
例として挙げられている実装では、View 自体に Presentation Model との同期用のメソッドが生えていて、それを利用して双方向のデータの同期を図っていた。この例では、Model 操作は View に対する操作 (チェックボックスのチェックやボタンの押下など) 契機に生じるものと想定されていて、View はそれらに対応するイベントハンドラが発火された際に、同期用のメソッドを利用して同期をしたり、Presentation Model 内のロジックを呼び出したりする。
https://gyazo.com/d9aaf77967fe06f55c23b703911309e6
Data Binding についてはあまり深く言及されていないが、.NET Framework に提供されている Data Binding を利用した場合で、デフォルトではサポートされてないテーブル上のセルの色付けのためにコードを拡張する例が示されている。
MVVM (Microsoft, 2005)
MVVM は、Microsoft の WPF, Silverlight のアーキテクトであった John Gossman が自身のブログで発表したパターン。
モダンな UI 開発プラットフォームのための MVC の派生
View の開発の責務は、開発者ではなくデザイナーにある
デザインは、HTML や XAML、あるいは Dreamweaver や Flash、Sparkle 等の WYSIWYG ツールで行われる
UI 部分の開発は、ビジネスロジックやデータバックエンドとは、携わる人も、言語も、利用するツールも異なる
Model
データやビジネスロジック
コード上で記述されるか、RDB や XML にエンコードされたピュアなデータ
View
ボタンウヤウインドウ等のグラフィック要素
MVC における Controller の役割だった、キーボードショートカットのエンコードや、入力デバイスとのやり取りの管理の責務を持つ ツールによって宣言的に記述される
Data Binding により、Model のデータと View の要素が関連づけられる (例えば、Boolean 値が CheckBox に紐づけられる)
Model の一部は、単純に View に描画されるため1方向の Data Binding になる
他のデータは編集可能なように、双方向の Data Binding になる
しかし、アプリケーションの UI のごく一部のみしか Model には直接紐づけられない
特に、Model がアプリケーション開発者が調整でき内容な既存のものを扱っている場合
Model は、直接 Control にマッピングできないようなデータタイプを持っている可能性が高い
また、View は、コードに落とすべき複雑なロジックを持つ場合がある
かといって、View には含めるべきでない
Model に含めるには限定的すぎる、あるいは既存の Model には含まれていない
ViewModel
Model of a View
View の抽象と考えられる
Model のデータを View のためのデータに変換する
View が利用し Model とやり取りするための Command も含む
Data Binding については、上記ブログ記事には詳しく言及されていない。.NET Framework では、XAML による Data Binding の設定がプラットフォームレベルでサポートされているので、やりやすいのだという。
MVP + Supervising Controller, Passive View (Martin Fowler, 2006)
Martin Fowler 氏は、著作のためにプレゼンテーション層のパターンに関する資料をまとめており、その中で Supervising Controller と Passive View というパターンが紹介されている。これらはどちらも、プレゼンテーション層のロジックにおける Controller (Presenter) の責務範囲に言及したものとなっている。
これらのパターンは MVP の文脈で語られることも多いが、プレゼンテーション層における課題解決のための一般的に適用可能なパターンであり、必ずしも MVP の文脈で語る必要はないとのこと。また、Microsoft によって 2011 年に Web クライアントアプリケーション開発のためのパターンとしても改めて紹介されており、そちらの方がシンプルでわかりやすいかもしれない。
モチベーション
自動テストしたい (View はテストしづらい)
同様の振る舞いはページ間でコードを共有したい
ビジネスロジックと UI ロジックを、理解や捕手を簡単にするために分離したい
MVP の復習
描画 と イベントハンドリング を、各々 View と Presenter に分離する
View はユーザイベントを受け付けるが、それを Presenter に Forwarding する
Presenter はユーザイベントに応答するロジックを持ち、View の状態とモデルを更新する
テストしやすくするために、Presenter は、View の具象ではなく抽象を参照させる
これによって、実際の View ではないテスト用の View を注入してテストできる
そして、View の更新方法 に関しては、Supervising Controller と Passive View というパターンがある。
Supervising Controller
基本的なコンセプトは以下。
Presentation 層を、View と Controller (Presenter) に分離する
Model からの単純なデータのマッピングは、View がハンドリングする
多くの UI フレームワークは Data Binding によって View/Model 間のマッピングが簡単にできる仕組みを持っている これは引き続き利用できるようにしておく
入力に対する応答 と、複雑な View logic による View/Model 間の同期 は、Controller がハンドリングする
モチベーションは以下。
View からの複雑さの分離
View から複雑な振る舞いを引きはがすことで、View が理解しやすいものになる
View の詳細を Controller が知ってしまっているので、メリットが相殺される
これを別オブジェクトにする価値があるかどうかは疑問
テスタビリティの向上
より説得力がある
テストできる UI を作るのは難しい
テスタビリティを考慮するのであれば、View にどの程度振る舞いを残すかどうか?を考えるべき
その点でいうと、Passive View は全ての振る舞いを (Data Binding ですら) Controller に移す
その分コード量は増えるが、全ての描画ロジックがテスタブルになる
Passive View
基本的なコンセプトは以下。
描画と描画ロジックを、View と Controller に 完全に分離 する
View の状態は全て Controller (Presenter) によって制御する
モチベーションは以下。
テスタビリティの向上
Controller はテストしやすい
View のテストをする必要が完全になくなる
View でデータ同期が発生しない
同期作業によって、テストが難しい状態が発生し得る
この違いが重要か?は議論の余地がある
シンプル
Model/View 間の同期のための宣言的な記述は存在しない
Model/View 間の同期のための Observer パターンが存在しない
問題が発生した時にコードをおいやすい
どちらを選択するか?
Supervising Controller と Passive View のどちらを選択するか?
これらは、どれだけアプリケーションをテスト可能な状態にしたいか?によって選択する
テスタビリティが主要な関心であれば Passive View にする
完全なテスタビリティを犠牲にしてでもコードをシンプルにしたけレバ supervising View
Model とのやり取りは様々な実装方法があって、Observer パターンが一般的
https://docs.microsoft.com/en-us/previous-versions/msp-n-p/images/ff709839.aa7a8362-061a-47fa-9666-0357c0d18505%28en-us%2cpandp.10%29.png
---
TODO: その他のパターンについてもまとめていきたい...
WIP
以下はメモ
考えたいこと
同期/非同期
状態管理
ページ管理 (View 自体の状態ではなく、もっとレイヤー的に上の状態はどこでどうコントロールするのが良いか)
Data Binding
Reactive Extension を使っても、Observer パターンを使っても良さそう
複数の View の共通状態を更新するたびに、各 View に更新を明示的に支持する
メリット: 明示的に同期するのでコード上で追いかけやすい
デメリット: View がたくさんあると View 同士の相互依存度が高まり、コードが煩雑になる
複数の View が単一の Model を Observe し、Model が更新された時に全ての View が同期して更新されるパターン
メリット: コードがシンプルになる
デメリット: コード上から流れが追いづらい
iOS における MVC
MVI
Flux
データが単方向に流れるのが特徴
オブザーバーパターンに役割と名前がついたもの
iOS では VIPER というのもあるらしい...?