WPF + MVVM初心者が躓きReactivePropertyに救われたこと
WPF + MVVMで開発を始めて、半年ほどの初心者です。
WPF+MVVMは初心者に優しくない(=習得が難しい)なっと思った部分をReactivePropertyに拾ってもらって、ようやく先に進めるようになってきました。
多分、同じように躓く人は多いのではないかと思われたので、これまで感じたことを初心者目線で書きたいと思います。
間違っていたら、指摘をお願いします。ブログ始めたのはそれが目的なので。
さて、インターネットを彷徨って、かずき大先生のBlogに辿り着き、
「これなら、自分みたいな面倒臭がり屋でもいける。」
「後続の開発者にも、『WPF+MVVMの習得が難しい』と恨まれないだろう」
というわけで、ReactivePropertyでいきなりWPF+MVVMを始めました。(実際には予備調査を散々しましたが・・・)
面倒臭くないっていうのは非常に重要ですよね。
良いものも保守的抵抗勢力の総スカンを喰らえば採用すら怪しくなるので・・・
あと、何が良いって、ReactiveProperty楽しいですよね!?
仕事楽しんでますか?私は今楽しんでいます。
実は、WPF+MVVMを始める前に、WPFの習得を待っていられない、急ぎの仕事があり、Windows Forms+Data BindingでUserControlを実装してひどい目にあっていました。
- データソースとやり取りをする、INotifyPropertyChangedを実装したModel+ViewModel相当のものを作った
- BindingSourceを経由してコントロールにバインド
- プロパティが変化したら複数のプロパティを計算しなおしてUIに反映
- プロパティが変化したらUIの状態を表すプロパティ(Enabled/Visible)なども条件によっては変化させた
- 特に、DataGridViewで入力エラーチェックを実装し始めた辺りから非常に妖しくなってきた
- IsDirty/HasErrorsをコレクションで実装してさらに妖しくなってきた
- 苦しい時のイベントハンドラ登場
Data Bindingにイベントハンドラを組み合わせて複雑なことをすると、かなりの確率で死ぬ。ホントに死ぬ。
だもんだから、MVVMを調べ始めた当初から、WPF+MVVMの有難みは十分良く分かりました。
特にViewModel相当のものがあるのと無いのとで、複雑なことや入力エラー処理をするときの柔軟性がエライ違ってくる。
昔から「WPFの導入に失敗した」という事例を良く聞くけど、
XAML系プラットフォームでMVxを使わない
=MFCやWindows FormsをただXAML系プラットフォームに変えただけ
=習得が早いがイベント駆動で苦労してきた部分は何も解決しない
=導入しても恨まれるだけ
ということなんだろうな。
ただ、MVVMを調べ始めた当初は、サンプルやBlogを見ていて、妙な違和感があったんですよね。
言葉で表すと、例えば
- 書いている人によって、ModelとViewModelの機能の切り分け方に結構バラツキがある
- ViewModelは省略できると主張する人もいる
- Modelはデータソースそのものだから省略できるという人もいる
- 数値型をViewModelで文字列に変換してエラー処理をキッチリ実装している人と、数値型のままでなんとなく誤魔化している(=TypeConverterやIValueConverterで例外が出ないようにしている)人がいる
で、「どれが本当なの?」って調べれば調べるほどモヤモヤしてくるということ。
この辺のモヤモヤは、Livetの開発者の尾上大先生のBlogを見て、ちょっとすっきりした。
- GUIアーキテクチャパターンの基礎からMVVMパターンへ (スライド)
- スライド17
- スライド31
- スライド43
- スライド53
- スライド55
- スライド58-62
- スライド63-68
- スライド77-79 (2016/01/30追記)
- スライド81-85
- 本文
- コメントの応答
自分の躓いた部分をすっきりさせてくれたのは、この辺かな?
特に、サンプルについての言及と崩しのパターンについての説明は目から鱗だった。
これを踏まえて、躓いた自分が同じような初心者の皆に言えること・・・
「まずは基本から」
「サンプルは書いた人のバックグラウンドを引きずっているので、特定の崩しのパターンが含まれていることが多い」
「初期の学習では単純なパターンから入るので、崩しのパターンにすぐに飛びつかないこと」
「最低限データ検証まで押さえた上で崩せるところは崩す」
「仕様変更で崩しのパターンが受け入れられなくなったら一旦基本に戻る」
って、ところでしょうか。
ところで、初期の段階で崩しのパターンに飛びつく理由は、以下が大きいと思われます。
「INotifyPropertyChangedの実装が面倒臭い」
「ModelとViewModelに同じプロパティが出てくる冗長さが更に面倒臭い」
なので、
面倒臭い=崩したい
崩すのが必然なら良いが、ただ「面倒臭いから」という不純な動機だと、散々な結果(=大幅な手直し)が待っていることもあるのではないかと思いました。
MVVMフレームワークを使ってもこの辺はどうしようもないけど、ReactivePropertyはこの面倒臭い部分を請け負ってくれる。
つまり、最初の段階の「不純な動機」を排除してくれる。
しかも、データ検証のINotifyDataErrorInfoもおまけに付きて、何よりもRxによってLINQ式でイベントを起点とした処理を宣言的に記述することが可能です。
PCLなのでプラットフォームを選ばない(バージョンは選びますが・・・)ので、他のMVVMフレームワークとの相性も良いですし、単純なUIで有ればMVVMフレームワークは使用せずにBlend SDKと組み合わせるだけでも組むことが出来ます。
「ReactivePropertyを使わないという明確な理由が見つからない。」
それくらいインパクトがあります。
ただし、ReactivePropertyは別の理由で基本パターンを崩しているということに、ようやく最近になって気付きました。
「Rxが強力なのでViewModelが太ってくる。」
どういうことかというと、
「Modelがデータソースのデータ型に毛(INotifyPropertyChanged)が生えた程度になり、Modelの責務がViewModelに含まれるようになる。」
ということ。
このため、太りすぎたViewModelをスリムにしようとして、データソースのデータ型に毛(INotifyPropertyChanged)が生えた程度のままのModelに機能を移そうとすると、散々な結果になります。
どうしたら良いのか?
「ModelもReactivePropertyで実装したら良い。」
短い期間ですが、これが自分の出した答えです。
今回はここまで。
コメントお待ちしています。