MVVMパターンで 学ぶ GUIアーキテクチャ・パターン

2012/8/4 わんくま同盟 大阪勉強会 #50
尾上雅則
本セッションの目的と動機付け
本セッションの目的は、
MVC/MVP/MVVMなどのいわゆるMVC系
GUIアーキテクチャ・パターン
をMVVMパターンを通して適切に理解・学習・適
用するための考え方を学ぶ事です。
MVVMパターンは
XAML系プラットフォーム(WPF/SL/WP7/Metro)
から生まれたMVC系パターンです。
よくあるMVVMの図ですが
これは何のために必要なんでしょう?
→ 保守性や変更容易性や開発生産性を確保するため
→ こんな事は全ての開発関連話題で当り前の事
問題は何を持ってそのメリットを確保するか
Viewは表示で、Modelはドメインあるいはビジネスロジックと
データ、ViewModelはその橋渡し・・・?
ドメインって?
クラサバだとビジネスロジックはクライアントにないよ?
Modelに書くべきことは結局どこからどこまで?
Modelが曖昧だと当然橋渡しのViewModelもわからない
何をもって保守性や変更容易性や開発生産性を確保するか
説明できていない。
ViewModelは橋渡しって3つの責務が繋がってたら真ん中が橋
渡しなのは当たり前でしょ?MVCもMVPもMVVMも全部一緒
になる。
納得したような気にはなりますが、
結局何も説明できていないんです

尾上 雅則 (おのうえ まさのり)

昭和58年生 フリーランス

C#/MVVM
WindowsForms/ASPNET/XAML系全般など

Blog – the sea of fertility – http://ugaya40.net
Twitter - @ugaya40
Facebook – http://facebook.com/ugaya40
MVVMer

Microsot MVP for Visual C#(2012/7~)



日本でMVVMが流行り始めた2年前、その頃はまだ誰も
View/ViewModel/Modelの各役割を説明できませんでした。説明は先
ほど例示したそれのレベルでした
インターネット上にはMVC系パターンに関する
知見があふれています。そのすべてが同じなわ
けではなく、さまざまな意見があります。
そういった状況でただ
「MVCでは○○は××する」
「MVVMでは△△は□□と解釈する」
などと言ってもそれを信じる根拠はありません。
本セッションでは私の2年間のうちのMVVMの概念に
関わる認識をなぞり、MVVMパターンをまず導出して
いき、
導出の中で見出した目的・理由を武器に
MVC系パターンの




本質はなんなのか
どう理解するのか
どう学習リソースを扱うのか
どう適用していくのか
について考えていきます。
PresentationDomainSeparation
DomoSolution - BeforePDS





コントロールの状態が制御判
断に利用されている
責務分割されていない(この
形のままじゃやりようが無
い)
例えば色ではなく画像で表すこ
とになったら変更範囲が大きい
責務分割されていないのでUIの
変更から影響範囲が考察しにく
い。
場合によってはイベントの処理
順にビジネスフローが依存しか
ねない
DomoSolution - AfterPDS

YourCondition.cs




Form1.cs

コントロールの状態に依存し
ない状態制御手段を持った。
コードがBeforePDSより長い
BeforePDSと比べてUIの変
更にはるかに強い
コードの見通しも良い
イベントの処理順にビジネス
フローが影響されたりするこ
ともない。
しかしこの程度の規模では冗
長さが目立つばかり
この考え方の事を
PresentationDomainSeparation(PDS)
と呼びます。
本来当たり前のOOPです。関心事の分離です。
相互依存は望ましくないのでObserverパターンで!
PresentationDomainSeparation
Martin Fowler
http://martinfowler.com/bliki/PresentationDomainSeparation.
html
(和訳)
プレゼンテーションとドメインの分離
Martin Fowler‘s Bliki in Japan
http://martinfowler.com/bliki/PresentationDomainSeparation.
html
(引用):プレゼンテーションとドメインの分離
“最も有用な設計原則に、 プログラムのプレゼン
テーション層(ユーザーインターフェイス)とそ
の他の機能をうまく分ける、というのがありま
す。”

分離することによる理解のしやすさ

テストしにくいUIを分離してテスト容易部分を増やす

複数のプレゼンテーションで共有できるドメインができる

プレゼン部分はそのプラットフォームの知識が本来別に必要である

プレゼンプラットフォームの仕様・変更にドメインが引きずられな
い

メリットは多く、OOPにおいてはそもそも至極真当な話です。

PDSしなかった事により発生するデメリットは、一般的なOOP
がきちんとできなかった際のデメリットと同様です。規模の大
きさに特に比例して影響範囲などの把握が難しくなります。

ただ全ユースケースでの処理の概要が一人でも一望できるほど
規模が小さいプログラムでは冗長さが目立つかもしれません。
XAMLの事情とMVVM.
そして他のMVCパターンへ

同じコントロールも外観をXAMLだけで別の外見に。
<TreeView>
<ListBox>
画像貼りミス
じゃないですよ!

外見の変化はカスタムコントロールを作る動機ではなくなった。
• Windowサイズを広げてみる
DomoSolution – BeforePDS/WPFLayout
<WindowsForms>
残念。
<XAML>
CSSと同じようなシステム


コントロールに状態に応じた外観を定義する事が可能になっ
た。(状態間にアニメーションの定義も可能/状態を追加する
事も可能)
外観に関わるコードはこうやってほぼ全てXAMLに委譲でき
る。

WPF/Silverlightのデータバインディングは双方向の
データバインドに対応している

コレクションコントロール(ListBox/TreeView)などに
は最強の武器がある。
展開するまで
子のインスタンスが無
い!

コレクションコントロールのはまり所

チェック状態をバインドで処理していないと・・・
DomoSolution - CollectionControl

コレクションコントロールのはまり所

WindowsPhoneではさらに状況は深刻
DomoSolution - PhoneListBox
スクロール
関係ないところに
チェックが!
画面のレンダリングに必要な動的に変化する情報を保持す
るバインドオブジェクトを設ける事で正常に動作する
バインド!

XAMLはバインディングファースト





コレクションコントロールもそうだが、XAMLプ
ラットフォームの主な機能はバインディングが前提
で作られている
DataTemplateをC#/VBなどの汎用言語コードで構
築しても全機能を使う事はできない。
コントロールの状態は信用しない。
コレクションコントロールの挙動などからも、メ
ソッドどうこうより、バインドされたオブジェクト
が正常にレンダリングされれば良いという哲学を感
じる。
バインドするオブジェクトはコントロールの状態ス
トアとして機能する

XAML用コントロールをコードからのみ
自在に触るのは習熟が難しく限界がある。

XAMLはDSL(問題領域特化言語)


バインディング・レンダリング機能を充実
させるためにCLRプロパティとは別のプロ
パティシステムをも備える
CSSライクなDSLをわざわざ介す事で、柔軟
なレンダリング・レイアウトシステム、そ
して仮想化などを含むコントロールの自由
な実装を手に入れた。

XAMLは外観の変化に非常に柔軟なDSL


外観の変化を動機としてC#/VBなどの汎用言語コードを書く
事はほとんどない
XAMLはバインディングファーストDSL



メソッドやプロパティを直接触るのでは駄目で、バインディ
ングじゃないとできない事があるくらい!
バインドされたオブジェクトがコントロールの状態を決める
PDSの説明で出てきた「プレゼンテーションプラットフォー
ムの実装には汎用言語と異なった知識が必要」の典型例

WindowsFormsと比べると、XAML自体に対する知識がないと扱い
にくい。WindowsFormsはC#に関する知識だけである程度できる。
XAML系プラットフォームでPDSを適用する
と・・・
そしてXAMLにはXAML固有の都合でバインド
するオブジェクトが必要となるので
そしてXAMLにはバインドするオブジェクトが
必要となるので
そしてXAMLにはバインドするオブジェクトが
必要となるので
View
ViewModel
Model
この形の事をMVVMパターンと言います。
見ての通り全然特別なパターンではありません。
View
ViewModel
Model

Viewの都合で存在するViewModelを責務とし
て分けている理由はなんでしょうか?
Viewの都合であるものなのに、どうして
バインドするオブジェクトをViewのコー
ドビハインドとかに書かないの?

Viewの都合で存在するViewModelを責務とし
て分けている理由はなんでしょうか?
 まず一つ目として使いまわしの視点があります。
 ViewModelを書くのは手間です。使いまわせるとこ
ろがあるなら使いまわしたいものです。
 例えば詳細画面のViewModelを一覧画面でも使いた
いなどがありませんか?

Viewの都合で存在するViewModelを責務とし
て分けている理由はなんでしょうか?
 また、Viewのクラスは基本的にDispatcherObject
と言って、単一のUIスレッド以外から触ると例外が
出ます。
 ViewModelの値はModelから更新されることがある
のに、これは現在ネットワークアクセスなどがすべ
て非同期を強要される方向に向かっている(すでに
WPF以外すべての環境で強要されます)XAMLプラッ
トフォームでは大きな問題です。
 ViewModelをView内に記述するわけにはいかない
のです。
見ての通り、XAMLプラットフォームの特徴に配慮してPDSを
実現しようとした形がMVVMパターンになります。
MVVMは「XAMLプラットフォームとPDS」という視点から当
たり前に導き出されるものであり、それは特定の業務に向い
ているとか向いていないとかではありません。
MVVMは「XAMLプラットフォーム」で開発する以上考慮すべ
き考え方と言えます。
MVVMパターンは、XAMLプラットフォームの力
を存分に引き出して(それにはPDSが含まれる)設
計を行うためのものです。
MVVMを見て、MVC系はPDSを各プラット
フォームの特性に合わせて実現するものだと考
えれば、他のMVC系の理解もサクサク進みます。


例えばASP.NET MVCはWebアプリケーション
プラットフォーム
Webプラットフォームである以上、HTMLのレ
ンダリング(ASP.NET MVCの場合はRazorとい
うDSLを使う)、セッション管理、遷移管理な
どの機能を持ちます。

しかしRazorがサポートするのは、単一ページ
のレンダリングであり、Webでは複雑になりが
ちな遷移管理などその他のViewプラット
フォームの都合を請け負う部分が必要です。
ASP.NET MVCのRazor以外の、GUIプラット
フォーム都合部分(主に遷移など)を請け負うの
がASP.NET MVCでのControllerです。
 もちろんViewとModelの間のデータの橋渡し
もします。

原初のMVC
ASP.NET MVC
同じMVCなのに
なんで違うの?
MVC系が「Viewプラットフォームの特徴を生かし
たPDS実現パターン」だという事を思い出しましょう。
つまり、プレゼンテーションプラットフォームが変わ
MVC系は変わるのです。
このサイクルを
繰り返す
そしてこの事が「同じMVCといえどもプラット
フォームごとに全然変わってくる」理由と言えるで
しょう。


MVVMパターンを含むMVC系パターンはPDSを実
現するためのもの。
Presentation側が特にDSLを使用する場合などは、
そのDSLの我儘などを担う部分が必要となってく
る。
MV○パターンの○は全てPDSのPresentation側
で、Viewで処理できないPresentationPlatform
の我儘を担う。
 MVVMのViewModel
– XAMLのための状態ストア
 MVCのController – Razorで処理できないASP.NET
MVC固有部分

少なくとも国内ではそういう情報がほとんどな
い=少なくとも日本語ではそういった説明はほ
とんどないものの、実は元のマーチンファウ
ラーのPDSの説明に該当箇所がある。(海外で
も誤解している人が多い事は、MOVE絡みで把
握)
This principle is the most prominent part of Model View
Controller (MVC), indeed for many people MVC is how they
describe this separation.
PresentationDomainSeparation – Martin Fowler
この原則は、モデル・ビュー・コントローラー(MVC)の最も有名な個所で
す。確かに、多くのひとにとってMVCとは、この分断をどのように行うかと
いうものとなっています。
プレゼンテーションとドメインの分離 – MartinFowler’s Bliki in
Japanse



MV○系パターンはプラットフォームを選んだ
時点で、何を使うべきなのかほとんどの場合決
まっている。業務などによらない。
MV○系パターンではModelの中の設計にタッ
チしない。MVC系はPresentation固有の知識
にあたる部分とそれ以外を分離するための知識
である。
導出フェーズ終わり
MVC系の有効範囲
結論から言うと概念を流し読みして理解が十分
でない状態でサンプルからきちんとした概念を
読みだそうとしても無駄です。
何故ならMVC系パターンは「楽に開発するため
に」あくまでもPDSに付随するメリットを手に
いれるための手段なので、例えばModelの中の設
計にタッチしていないわけで、サンプルコード
にはその他の概念が含まれすぎています。
何種類か見てみましょう。
例えば計算機レベルのサンプル
厳密に3つの責務にわけた所で、PDSの冗長さが目
立つだけです。きちんと理論から到達したなら、
PDSのメリットと冗長さというデメリットを比較し
て大抵こうはなりません。
サンプルとしての意図でこうなっているんでしょう
が、その割にはメリットも伝えられません。
例えば計算機レベルのサンプル
ViewModelをModelと統合しています。
計算機程度の小規模であるならば、大抵の場合
あるべき姿です。でもこの姿からMVVMの姿っ
て学べませんよね。
えーと、単純に読むのがつらいですし、適用さ
れているMVC系以外の考慮事項多すぎますよね。
例えばSilverlightのWCF RIA Service。
普通に考えればそれだけ使えばModel部分を全部代替できるという
ものではないのですが、
そういう代替できるシナリオをわざわざ用意したり、ViewModelの
責務に微妙にModelが染み出したようなサンプルがMSさんの物には
多いです。
マーケマーケ。仕方ないとは思います。。。
例えばASP.NET MVC3のスキャフォールディング。
ControllerからDBいぢれたりしちゃいます。
PresentationPlatformはその進化の過程で”定型シナリ
オに簡単に対応するために”PDSを部分的に崩しすような
機能を盛り込んできる事があります。
そしてこれが搭載されたMSさんが出してるような
ASP.NET MVC3のサンプルは必然的にこの機能アピール
が多くてつまりほとんどPDSが崩れているという。
でもCodePlexにあがっているような規模の大きいサンプ
ルで(Project Silkとか)では使っていないみたいですよ。
PDSを崩すデメリットが大きくなるからでしょう。
同じMVVMを考慮し
た結果だけでも本当
に無数にあります。
ここから概念を抽
出?・・・。
× Model内の設計
・
・
etc
ドメインロジックパターン
だけでも
TransactionScript
DomainModel
TableModule
(次のセッションで詳しく)
サンプルから概念を理解した気になっている人は、MVVMで
あれば例えば


ViewModelではコマンドを使う
コードビハインドを書かない
などと言った実装上の選択にすぎない事をMVVMの定義と紐
づけます。しかしそれはやはりMVVMの定義とは関係がない
ものです。
そういった実装要素は、メリットとデメリットをしっかり見
極めてご自身で状況によって取捨選択してください。
サンプルでの学習は概念の理解を前提としてそういった時に
有用です。
結論:いきなりサンプルからは無理なので横着しないで
きちんと概念から学びましょう。サンプルで学べるのは
MVC系の考え方ではなくMVC系フレームワークの使い方
程度です。
そしてそうやって学んだ使い方では、もともとMVC系の
責務分割の目的がわからないものだからその実装要素が
何の目的に寄与しているかわからない、結果実装要素の
取捨選択ができない。


コマンド使うのがMVVMだよね?
コードビハインド使わないのがMVVMだよね?
どちらも違います
もしPDSを踏まえてMVVMを理解していたらどうな
るか?
ViewModelは「Viewの何の我儘を請け負っているの
か」に頭が回るようになりますし、そうなれば
ViewModelはViewの状態を受け持つという事もわか
ります。そしてPDSの観点からViewModelに含める
べきではないコードが明確になります。
コマンドはコードビハインドを使わないっていうの
は?
そう、何一つトップダウンな決めつけなしできちんと
PDSから各プラットフォーム用のMVC系をボトムアップ
で理解していけば、コマンドの使用やコードビハインド
を使わないという知識は、XAMLとMVVMの組み合わせ
が可能にするViewの抽象化要件やデザイナとの分業要件
のためにある事がわかるはずです。
ならViewの差し替え・抽象化要件がなかったら?
コマンドを使わなくても良いし、コードビハインドを書
きまくれば良いと判断できます。
MVVMの責務分割の根拠となるPDSの不理解こそが
MVVMを教条主義に変えるものです。
サンプルコードから学んだつもりになっても学べな
いのは当たり前です。きちんと概念 – それが責務分
割であるMVC系ではその責務分割の根拠となるPDS
からしっかりと理解すればさまざまな事がわかって
きます。
まだ世の中に出て間もない新しいものは、そのプ
ラットフォームの特徴を見極め、先ほどMVVMを導
き出したように自分で検討してみるのもいいかもし
れません。
そしたら周知してくださいね!
実は今回お話したMVVMの定義は簡略系です。
MVVMの先祖にPresentationModelパターンと
いうMVC系のパターンがあります。
同じに見えませんか?
ええ、MVVMパターンはPresentationModelパ
ターンに加えViewの抽象化要件やデザイナとの
分業などを可能にしているだけにすぎません。
その気になればViewを完全にXAMLの定義だけ
で構築することが可能な事や、Viewの抽象化に
対応できること(コマンド/コードビハインドの使
用生むなど)がPresentationModelパターン一般
に想定されていないXAML系MVVM特有のメリッ
トを生んでいます。
では今まで説明したMVVMの定義で組んだアプ
リケーションはPresentationModelを適用したの
であって、MVVMを適用したのではないのか?
そうではありません。紛れもなくXAML系の都合
とPDSを考慮 = MVVMパターンを考慮し、開発
されたアプリケーションとなります。
MVVMパターンがもたらすメリットのうち、
Viewの抽象化要件やデザイナとの分業は多くの
ケースでは不要だから、それに関わる部分を選
択しなかっただけですね。そして不要な部分は
メリットが無くてデメリット(冗長さ)があるだけ
なのだから採用しない、それこそがまさに適切
なMVVMパターンの適用法です。
こうやってMVVMの責務分割/その根拠となるPDSから理
解していればこういう取捨選択が可能になり、結果それ
がMVVMの典型的な実装になっていなくても、それは紛
れもなくMVVMの適用結果として適切な実装(パターンを
使用してメリットを享受)だし、MVVMを考慮した結果と
言えます。
これがMVVMなんだ!などという実装は存在しないし、
則るだとか遵守だとかいう表現はそもそも不適切です。
そういった表現はMVVMを実装例から学べたつもりに
なっている人に特有の表現なので気を付けましょう。そ
してメリットを理解できていない実装に縛られているせ
いでMVVMを教条主義だと貶めるのも彼らです。惑わさ
れないように。
適用TIPS

ここでは前章までに培った知見を使って世の中
で言われがちな様々な課題を確認していきます。

理解度確認に一緒に考えていきましょう。

MVVMを基準で話します。
Q.Modelはデータの入れ物?
A.データの入れ物だとしたら値をつめるのはViewModelしかな
くなりますよね。PDSは?
意図的に崩したのでないのであれば×。他のMVC系でも同様
Q.ModelはEntityFrameworkとかRIA Service?
A.そうなる場合もありますが、そうならない場合の方が
多いのでその考え方に縛られないでください。必要あれば
別の層をかぶせてModelとしてくださいね。△
まとめ
MVVMであれば、ViewとViewModelの責務は決
定的です。よく
「今考えている処理をViewModelとModelのど
ちらに書けばいいかわからない」
という話を耳にしますが、
それはModelが曖昧な上にViewModelを橋渡し
としか思っていないからです
真ん中にいるViewModelやControllerが必要以上に
責務を負う事は、橋渡しもするからこそどんどん肥
大する可能性があり危険なのです。
PDSを確保したいなら、ViewModelやControllerは
極力薄くなるようにするべきです。欲しい機能は
Model、あるいはViewのコントロールに持たせてい
きましょう。
あのControllerやPresenterやViewModelをも全て
一言でくくる事になり何の説明にもなっていない真
ん中橋渡し論は本当に罪深いものです。
しかし世間はそういった認識にあふれています。惑
わされないようにしてください。
楽をするためには時にはPDSで得られるメリッ
トとデメリットを測りにかけて、PDSを崩すこ
とも大事です。
PDSを守るのが本来の目的ではなく、あくまで
も楽に開発するための設計パターンです。きち
んと概念/PDSから理解していればメリット・デ
メリットの取捨選択はできますよね?
小規模なコードでPDS遵守しても苦しいだけの
事は多々ありますよ。