RIAアーキテクチャ研究会 第2回セミナー 尾上 雅則 1. 自己紹介・デモアプリ紹介 2. リッチクライアントのModel 3. 古き良き設計 4. WinRTとAsync CTP/ReactiveExtensions 5. リポジトリ非同期ステートフルModel 6. まとめ • • 3プラットフォームで • 実装された Twitterクライアント 尾上 雅則(おのうえ まさのり) 28歳 C#er / MVVMer ◦ WPF/Silverlight/WindowsPhone/WindowsForms/AS P.NET/SQL Server/ReactiveExtensions勉強中 Blog ◦ The sea of fertility – http://ugaya40.net Twitter ◦ @ugaya40 3Platform(WPF/Silverlight/WindowsPhone) Twitterクライアント WPF4 Silverlight4 Windows Phone 7.1 設計(全プラットフォーム共通) ◦ Full MVVM ◦ リポジトリ非同期ステートフルModel なぜTwitterクライアントなのか ◦ DBアクセスは定型的に過ぎ、またオブジェクトの変化が少な くそもそも適切な粒度でリッチクライアントらしくまとめる には無理があると判断。 ◦ サンプルで使用するDBアクセスの方法を標準と思われがちな のが心外。DBアクセスは機能・非機能要件によって使い分け ましょう! 使用ライブラリ ◦ MVVM Light Toolkit 軽量であるが故に、もっとも万能である。 http://mvvmlight.codeplex.com/ ◦ ReactiveOauth OAuthでの通信をReactive Extensionsを利用して使用して行える。 作者 : @neueccさん http://reactiveoauth.codeplex.com/ ◦ Reactive Extensions コールバック・イベントハンドラのネストの撲滅 イベント合成 詳細は http://neue.cc の各記事参照 • • 「リッチクライアント」のって 言わなきゃいけないのは何故? 外観 呼出 Data Binding 画面 画面を レンダリングする ための情報 ビジネス ドメイン (アプリの機能) イベント 呼出 画面 View Data Binding レンダリング情報 ビジネス ドメイン ViewModel Model イベント アプリの外観・見た目・小手先 の操作性に関わる部分以外 UI想定前のアプリのイメージ ビジネスドメイン Model ちょっと高度なバッチ処理を書 くようにModelを書く アプリの外観・見た目・小手先 の操作性以外の事をViewModel に混ぜないように書く Modelの仕様を決めるための、 いわゆる業務的なインプットは 例えばユースケース定義の粒度。 ビジネスドメイン Model ユースケース定義には アプリを使用するユーザー・外部シ ステムのアクション アプリが外部に及ぼす影響 などが定義されている。 入力仕掛りなどユースケース定義にはない。 操作情報 ユーザー Model システム クラス群 外部システム (DBなども) 視認できる 情報 (表示・帳票) IN Model クラス群 OUT システムが受ける入力・すべき出力、 それらをユースケース定義の様な粒度で過不足なく 満たす、 それがModelの仕様であると理解しています。 ユーザーがアプリを起動する IN ◦ 認証されている場合 OUT 認証情報をストレージから復元する ◦ 認証されていない場合 認証する 次回のために認証情報を保存する ◦ 認証済になった場合 ユーザーの基本情報を表示する ユーザーのリストのタイムラインをTwitterから取得し、基本タ イムラインと合わせて表示する ユーザーがポストする ◦ ユーザーが投稿をTwitterにポストする IN OUT ユーザーが更新したいタイムラインを更新操作する ◦ 指定されたタイムラインの新しいツイートをTwitterから取 IN OUT 得し、新しいツイートを追加表示する。 起動時 各種ストレージ IN アプリケーション コンテキスト TwitterSampleApplication OUT ④認証 認証サービス AuthorizeUrlBuild er,Authorizer アプリケーションコンテキスト TwitterSampleApplication IN OUT 認証済アカウントコンテキスト AccountContext 自ユーザー 情報 タイムライン TimeLine Tweet Tweet Tweet Tweet 多くの場合当然ただのデータの入れ物じゃだめ。プ ロパティ(状態)を持ち、メソッド(操作)を持ちます。 ここまでの内容を踏まえれば自明のことです。 IN OUT ◦ ドメインモデル貧血症じゃだめな事が多い ◦ Modelをただのデータの入れ物にすると、ViewModelが データを詰めるんですか?。ViewModel/Viewの役割は? また、サーバと通信するアプリであっても、クライ アント側にも当然Modelはあります。これもここま での内容を踏まえれば自明のことです。 リッチクライアントのModelは IN ビジネスドメイン OUT ステートフル(状態を持つ) ドメインモデル貧血症ではない(状態だけではない) Modelの粒度はユースケース定義を想像して! 悩んだときは、「ではこの処理をModelでしなかっ た場合ViewModelがするのが適切なのか?」 なんでも設計の基本は、対象のINとOUTを明確に。 • WPF/MVVMなオールドスタイル Modelで時間をかかる処理を行った場合(ネットワー クアクセスなど)に、GUIをブロックして操作不能に IN OUT してしまうようでは話にならない フリーズって言われちゃいますよね? ソリューションは非同期呼び出ししかありません。 本質的な問題は、それがView/ViewModelの責務(外 IN OUT 観や小手先の操作性)に属するのか、Modelの責務(ビ ジネスドメイン)に属するのかです。 多くの人が直観と実装しやすさから、 Modelはすべて同期的に実装する IN OUT ViewModelが非同期でModelを呼び出す 事を選択しました。 しかし・・・ Silverlight(WindowsPhone)を含むプラットフォーム は、Webアクセスなどが非同期APIでしか提供されて いません。 IN OUT もしこのWPF/MVVMのベーシックスタイルで実装す ると。。。 あれ?非同期は小手先の操作性と判断して ViewModelに寄せたんじゃなかったの? ViewModelとModel両方非同期って問題を複雑化さ せているだけじゃ・・・。 ステートフルModelは、ViewModelへの通知にイベン トを使用します。イベントハンドラのネストが発生し IN OUT やすいんですね。。。 このプロパティの変更通知来たら・・・ フィルタリングして・・・ その時にこっちのプロパティの変更通知きたら・・・ どう解決するのか? IN いくつかアプローチはあります。 OUT しかしはずれのアプローチは当然引きたくないわけ で・・・ ちょっと先を見てみることにします。 • 未来と未来へのソリューション Windows 8から搭載される新たなネイティブの基盤 (Win32後継?) IN OUT .NETから見ると普通に.NETに見えるらしい。 C++erはネイティブアプリをXAMLで書くようにな るらしい。 OSレベルで処理が50ミリ秒以上かかる可能性のある ものはすべて非同期APIしか提供されなくなる。 .NETだけやるにはあまり関係ない?いいえ。 Silverlight/WindowsPhoneも考慮すればMSの姿勢 は明らか。 WindowsPhoneを含むSilverlight環境に加えて、ついに Windows本体にも非同期が! 非同期を克服しなきゃいけない! IN そもそも非同期の何が嫌か OUT 単純に書くのが面倒くさい ブロックのネストが増える。 異常系まで絡むとわけわかめ。 しかもリトライとかしなきゃいけないネットワークアクセス が非同期とか・・・ ◦ とにかくネストが醜い。 ◦ ◦ ◦ ◦ では、非同期処理へのソリューションは?? 次期?C#での、非同期処理の構文レベルのサポー ト? IN こんなに簡単に! OUT 詳しくは http://ufcpp.netで! LINQ to Events by @neuecc イベント・非同期などのネストをフラットに、イベ IN OUT ントや非同期を時間を超えて合成・フィルタリング など。 LINQ to Objectがループブロックのネストを殺害し たように、本当に非同期やイベントのネストが消え てなくなります! 多少はデモアプリの実装として紹介しますが、詳し くはhttp://neue.ccにて。 • 提案 リポジトリとは? IN 外部システムとの通信 ファイルアクセス DBアクセス OUT など、システムにとって厄介な異常系を引き起こしか ねない呼び出しを、リポジトリの呼び出しと今回は定 義しています。 語源はリポジトリパターンからです。 リポジトリは、ソースコードにとって IN OUT テストが容易でない 非同期のネストを生む(Silverlight/今後) リトライなど厄介な要件が多い などの問題を引き起こす要因です。 逆に言えば、これらリポジトリを除いたソースコード は比較的可読性に優れ、テストも比較的容易です。 リポジトリ非同期ステートフルModelとは、 IN OUT リポジトリへのアクセスをすべてReactiveExtensions の返す継続(?)に置き換えたModelです。 このModelでは、リポジトリにアクセスするメソッド はすべてIObservable<T>を返します。 なんの事かわからないでしょうし、 実際どういったメリットがあるのかわかりにくいと思 いますので、デモアプリのソースコードから説明しま す。 リポジトリ非同期ステートフルModelとは、 IN OUT リポジトリへのアクセスをすべてReactiveExtensions の返す継続(?)に置き換えたModelです。 このModelでは、リポジトリにアクセスするメソッド はすべてIOservable<T>を返します。 なんの事かわからないでしょうし、 実際どういったメリットがあるのかわかりにくいと思 いますので、デモアプリのソースコードから説明しま す。 不調な事で有名なTwitter API。気分よく使うにはリト ライ処理が必須です。 IN OUT Twitterに特定のユーザーの情報を問い合わせています。 この例では異常時に2回まで1.5秒ごとにリトライをかけています。 (TwitterApiクラス) IN 大きすぎるので、ソース コードで確認してください。 最低でも3段の連鎖 WebAPIアクセスがネスト することなく順番に実行さ れます。 (AccountContextクラス) IN OUT フォロワー数を5000件づつカーソルとともに返してくれるAPI を叩いています。 カーソルが0になるまでアクセスを繰り返して、結果を集計して 一つにして返してくれます。 もちろん各アクセスごとにリトライ1.5秒ごと2回までしてます。 非同期の責務はすべてModel側に集中することになり ました。 IN OUT 異常系がきちんと考慮されているにもかかわらず、異 常系コードがほとんど出てこないModelコードになり ました。 LINQ的な機能が使えるので、イベント・非同期の結果 のフィルタリングもでき、ifのネストすら減りました。 継続や非同期やらの扱いに関係なく、Modelが満たす べき要件は同じです。 IN OUT ViewModelとModelの責務の違いをしっかりと意識し て開発すれば、ModelはUIの影響を受けないため、非 常に教科書的な、クラス構造が仕様を表すようなOOP の実装に近くなってきます。 Modelをより強く意識していただけるようになる一助 となっていれば幸いです。 リポジトリ非同期ステートフルModelですが、すでに 実戦投入経験もあり非常にうまく機能しています。 IN OUT しかしまだより良い書き方があるはずだという意識は もちろんあります。 非同期へのソリューションもようやく皆が意識し始め、 たたき台をもとに議論し高めていくには最良の時期に 思います。非同期とリッチクライアントパターンの関 係についてもっと多くの人と詰めていきたいと思って います。ご意見いただけると幸いです。 まずModelですが、僕がRxスキルが未熟なためまだ汚 いです。 IN OUT そしてViewModelも、MVVM Lightの上に即興で構築 した適当なインフラを急遽あつらえたものなので汚い です。 しかしこの資料とソースは公開します。今後もリファ クタしていくたたき台にしようとも思っているので、 ぜひ積極的に参加していただいたり、ご意見をいただ けるとありがたいと思っております。
© Copyright 2024 ExpyDoc