- SlideBoom

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の上に即興で構築
した適当なインフラを急遽あつらえたものなので汚い
です。
しかしこの資料とソースは公開します。今後もリファ
クタしていくたたき台にしようとも思っているので、
ぜひ積極的に参加していただいたり、ご意見をいただ
けるとありがたいと思っております。