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