WPFでのプログラミングスタイルMVVMをユーザービリティー開発から考える

Windows のアプリをWPFを使用して作るときにはMVVMというデザインパターンを使用する事が多いと思いますが、MVVMを考える時、プログラマー視点で考えてしまうと、形だけはMVVMだけれども、手間だけ増えて何のために分けたんだっけという情けない状態になりかねません。アプリを使う人の為のユーザビリティー開発のためのデザインパターンであるという見方から考えると、どういう風に分けたらいいかの指針となると思います。

WPF(Windows Presentation Foundation)とは

  • GPUを使用したベクターグラフィックスで画面描画を行うインターフェース
  • リッチな表示ができるが、その分処理が重いので高速化の工夫が必要

昔、Windowsは、画面の作成にGDI(Graphics Device Interface)というAPIを使用してビットマップで表示していました。GPUが使用されたのは、DirectXとかOpenGLとかを使用したグラフィックアプリケーションのみでした。GPUが発達して処理能力が格段に増えると、標準的にGPUで描画する方が良いと誰でも考えると思いますが、Windows Vista からその方向で修正が加えられました。Vistaはその意味で画面表示の変換点だった事、セキュリティーを変更しすぎて従来の多くのソフトがインストール時に不具合が発生したことで、非常に評判が悪い物でした。その後、どんどん画面表示にGPUの機能が使われ、今ではタスクマネージャーにもGPUの使用率が表示されるようになりました。そんな流れの中で、普通にVisual Studio でアプリを作る時にGPUを使う仕組みがWPF となります。従来のビットマップ表示も Windows Forms という形で残っていて、同じようなネームスペースを持っているので混乱しますが、まるっきり違う表示方法です。
Widows Forms で書いた画像は、ビットマップ画像となるので、拡大したり縮小したりした時に絵が汚くなります。それに対して、WPFは実際に画像を作るのはGPUで、CPUはGPUに対してどこからどこまで線を引けとか、どこどこを塗り潰せとかの指示のみをするベクタ―グラフィックスという形式をとっているため、表示エリアを拡大したからといて画像が粗くなるという事が無く、非常にきれいな表示ができます。
ここで誤解しがちなのが、GPUを使っているんだから表示が速くなると思い込むことです。CPU側で表示のためのデータをまとめてGPUに指令を送るためには、それなりの処理(オーバーヘッド)が必要とされます。ですので、簡単な事をGPUでやらそうとするとかえって遅くなるという事が生じます。最近Deep Learning の為にGPUを使用する事が当たり前のように行われていますが、その時も、大量の計算用データを一気にGPUに送って処理をさせるという事が行えないとCPUで処理をした方が速いという現象が起こります。グラフィックボードのメモリーが少ないとか、単純な処理の繰り返しにならず条件判断が必要な時にはCPUの方が速いという事になります。
WPFでも同じで、必ずしも速い訳ではないので、表示速度を上げるためのプログラミング上の工夫はGDI以上に必要とされます。例えば、グラフで大量の線を引くことを考えると、従来のGDIでは画面の解像度以上の描画は意味がないので端折っても同じですが、GPUを使うとなると単純に線の数だけ処理が増えることになります。表示速度の改善方法をいろいろとまとめてくれている方もいるみたいです。
qiita.com

MVVM(Model-View-ViewModel)とは

  • 画面開発とロジック開発を分離したデザインパターン
  • プログラマーは画面を考えずに、インターフェースをUIデザイナーに提供する
  • UIデザイナーは画面デザインツールBlendを使用してユーザービリティ―をデザインする
  • 画面Viewとロジック側ViewModelは疎結合バインディング)でつなぐ
  • プログラマーはデザインされていない画面でロジックのデバックを行う
  • ロジックが完成したら、デバッグ画面とUI画面を置き換えることでアプリが完成する

MVVMデザインパターンの意義

MVVMとはModel-View-ViewModel という3階層でプログラムを作るデザインパターンです。なぜ、このようにするのかという事が重要で、一番の本質は優れたユーザーインターフェース(usability)を開発するためという事を忘れてはいけないと思います。すなわちアプリケーションソフトの処理内容(ロジック、Model)と、画面の表示 GUI(View) を分離して開発できるようにすること、画面はプログラマーが作るのではなくユーザーインターフェースのデザイナーが作る、すなわち、画面はプログラミングしないでデザインツールを使ってお絵描きの様にして作ります。その様なお絵描きツールを使えるようにするために XAML(ザムル)と言われる静的な言語が採用されています。XAML をキー入力するように書かれている解説書とか BLOG が多いと思いますが、本来打ち込まないようにするために XAML が採用されたわけなので、お絵描きツールである Blend を使って画面を作りましょう。よく言われるビハインドコードを書いてはいけないというのは、書いてしまうと Blend の範疇を超えてしまいツールのサポートが受けられなくなるからです。そういうように考えると、XAML をキー入力している人がビハインドコードに何も書かないことにこだわっているなら、ナンセンスなような気もします。もっと極端に言うなら、プログラマーが画面を作るなら、XAML をキー入力するよりもビハインドコードでプログラミングして画面を作ってしまった方が簡単かもしれません。
Blend は当初 Expression Blend という名前で Visual Studio と別売でした。Visual Studio にはプログラミング環境とそのデバック用の簡単なGUIを作るための画面エディターが含まれ、Blend には、簡単なプログラミング環境と、アニメーションまで作れるフルスペックの画面エディターが含まれるという役割分担がなされています。とはいえ、想定していたようなユーザービリティー開発をしてくれるUIデザイナーがあまり現れなかった為か、今では Blend の単体売りはなくなって Visual Studio に同梱されています。画面作成を解説しているほとんどの Blog で XAML を打ち込むかの如く書かれていますが、せっかく同梱されているので 画面は Blend で作りましょう。
ユーザービリティ―開発にはアジャイル開発の様に試作とテストを何度も繰り返す反復デザインが必要なので、簡単に修正と置き換えができる事が大切となります。画面を Blend でお絵描きで作るのもその助けになります。ロジック側に画面Viewとのインターフェース部分であるViewModelと言われる層を設け、View と ViewModel を、名前のみで繋ぐ疎結合と言う方法(バインディング)で接続します。相手方がいなくても問題ないので名前を1文字間違えてもエラーにならない分、デバッグが大変という事もあるので、キー入力せずに Blend で相手先を選択する方が間違がありません。
プログラマーが行うのはデータ提供までなので、画面は知らないですし、画面のことを考えて ViewModel を作るのではなく、データの本質のみに着目してViewModel を作成する必要があります。こう考えると、一番大切なのはどんなデータを ViewModel から提供するかという初めの設計だという事が分かると思います。個人でアプリを作る時に、そこまで順序立てて考えたりしない人が多いのではないでしょうか。なんとなく作って改善していくという感じではないかなと思います。そういう作り方の時にはわざわざ画面表示用のデータを VeiwModel に作って、画面側でそれを受けるという View と ViewModel のやり取りを大量に書くことがばかばかしくなるように思います。ばかばかしいだけでなく、一人二役をすることになるので、今どっちの立場?と訳が分からなくなりかねません。
要するに、MVVMは手段であって目的ではありません。ユーザビリティー開発のための MVVM と考えると、ビハインドコードには何も書いてはいけないとかいう縛りで悩むこともなくなるのではないでしょうか。デザイナーはビハインドコードは書かない、書けないというただそれだけの話です。ビハインドコードが必要な画面の部品は、汎用的な機能を持たせてユーザーコントロール化して部品として渡すなら、ユーザーコントロールのビハインドコードはいくら書いても問題ないという事です。汎用的な部品にすることが大切で、そのアプリだけの部品として作ってしまうと、デザイナーに渡せなくなってしまいます。
プログラマーが画面を作ってユーザビリティーを考えているようだと、滝川クリステルさんに「ねえ、あなた今違う競技をやってるの。」と言われかねません。けれども、画面を Blend で作りこむのは、結構楽しい作業です。

  • ユーザービリティ―開発から見たポイント
    • 画面が XAML で書かれているのは Blend を使用して画面設計する為である
    • ビハインドコードを書いてはいけないのは Blend が使える環境を保つ為である
    • View と ViewModel でわざわざ同じプロパティーを作って、それを疎結合バインディング)で繋ぐのは、View を簡単に入れ替える為である

ユーザビリティー開発

ユーザビリティー開発のための評価方法には、定量的と定性的な方法があり、デザイン時にもいくつかの手法があります。

定量的手法

ごく一般的な手法にアンケートという方法があります。意外と簡単そうで難しいのがこの手法でしょう。質問の仕方でいくらでも誘導できます。

定性的手法

ガイドラインチェック
どうすべきだ的な事が書かれているのがガイドラインです。2つほど参加までにリンクを貼っておきます。
 
[ヤコブニールセンの10原則]
Jacob Nielsen の「ユーザビリティに関する10のヒューリスティクス (問題解決に役立つ知見) / Ten Usability Heuristics」 — Website Usability Info
すごく有名な10原則ですが、当たり前と言ってしまえば当たり前の内容です。

[ユーザーエクスペリエンスガイドライン]
Windows アプリ UX デザイン ガイドライン | MSDN
パソコンが趣味のプログラマーなら、何も考えなくても当たり前のことをすればいいだけですが、中には仕事以外ではパソコンを触らないプログラマーも存在しているようで、そういう人には世の中のアプリの常識が身についていません。そういう人はきちっとPCアプリがどういうルールで作られているか、どういう風に作らなくてはいけないかを書いたガイドラインに従ってもらう事が大切です。普通と違う操作性を作られると大変使いにくいソフトになってしまいます。

ヒューリスティック評価
ヒューリスティックとは経験則に基づくものという事です。3~5人の専門家に依頼して評価してもらうのが普通の様です。

③ユーザーテスト
実際のユーザーに評価してもらいます。その為には、本物の様に操作できるモックを簡単に早く用意する必要があり、その為のMVVMでもあるわけです。

④ウォークスルー評価
想像力を働かせて、具体的なユーザー(ペルソナ)を想定して、その人ならどの様に操作するかを考えるのがウォークスルー評価です。ペルソナはなるべく具体的な人物を想定する事が大切です。そして、それは上司とか社長ではなく、典型的なユーザーという事になります。その様なペルソナを仮想的に想定し、すべてそのペルソナがどう感じてどう考えるかという事が指針となります。ユーザーから何か言われても、上司に何を言われても、それを安易に受け入れることなくペルソナに従いましょう。すべての要望を取り入れることはできないので、言われるたびに対応したソフトは一貫性のない継ぎ接ぎだらけのソフトになりかねません。

デザイン時の手法

①ペーパープロトタイプ
本格的にソフトを作り始める前に、こんな感じという物をでっちあげるのがペーパープロトタイピングです。具体的に動く必要もなく、紙に書いたものでも十分ですが、具体的な内容をイメージできるものでなくてはいけません。逆に、あまりきれいに作ってしまうと、完成品のような感覚になってしまい、新しいアイデアが出てこなくなるので逆効果になることもあります。Expression Blend にも当初 スケッチ機能なるものがありました。わざと手書き風の画面イメージを簡単に作るための機能でした。

②プロトタイピング
実際に動くものを早期に作成し、ユーザーテストを繰り返すことで完成度を高めていく手法になります。ユーザービリティ―改善のために、どんどん画面を修正して、ある時には全面変更するための手法がMVVMによる View の切り離しと、ツールによる画面作成です。

③パラレルデザイン
予め、このデザインと言うように決め打ちするのではなく、複数のデザインを用意して、どちらが良いか選択する手法です。複数の画面デザインを用意するためには、簡単に作成できること、画面を入れ替えることができる事が必要で、その為の MVVM デザインパターンという事になります。

MVVMデザインパターン

全体像

f:id:feynman911:20190225164212j:plain
MVVM Total Image

MVVMデザインパターンの全体像を描いてみると上図の様になると思います。上部がユーザーエクスペリエンスを設計するデザイナー領域、下部がプログラマーが作成するプログラミング領域という事になります。
MVVMデザインパターンでアプリを作る時に、ダイアログをどうやって出すかが議論になると思います。ダイアログは View の範疇なのか、コードからプログラマーが出すものなのか。そんな時にもユーザービリティ―視線で考えると、ダイアログと言ってもその一言で済むものではないという事が分かると思います。

  • エラーが発生した時
  • ファイルを開く時とかユーザーに選択をさせる時
  • 操作手順をガイドする時

等々、いろいろな目的があると思います。考えるべきことは、デザイナーがユーザーエクスペリエンスを高めるために出すダイアログなのかどうかという事です。ファイル選択等は、独自のデザインとか独自の選択方式はかえってユーザーエクスペリエンスを阻害します。ですので、コードからプログラマーが出せば十分です。エラーが発生した時も同じです。デザイナーが使うダイアログは、画面操作を分かりやすくガイドしたい等、アプリの本質とは関係ないところのはずで、そういうところは View 側で行うべきでしょう。ダイアログも画面だから、View 側で何とかしなくてはいけないと考えるのは硬直した考え方だと思います。

開発フロー

f:id:feynman911:20190225180117j:plain
Development Flow
ViewModel で提供するプロパティーがきっちり決められれば、画面とコードの開発は並行して進めることができます。

ViewModelで提供するプロパティー

ViewModel で View に提供するプロパティーは、表示のことを考えてはいけません。例えば、スピードを表示する画面を想定してみましょう。ユーザーテストを行うと、mph 表示が良いとか、km/h 表示が良いとか、WPF で画面を作るのだからアナログメータが良いとか、デジタルメータで表示したいとか色々と画面デザインの意見が出るかもしれません。従来の作り方では、意見が変わるたびに マイル から キロメートル への変換だから0.621で割るとか、アナログ表示の針の角度を計算しなおすとか、いろいろとプログラマーの手を煩わせた事と思います。MVVMで画面を分離してUIデザイナーに任せた場合には、これはUIデザイナーの仕事となります。
今まで画面を変えるたびにプログラミングしていた手間(左側)をなくして、UIデザイナー(右側)に丸投げできます。
f:id:feynman911:20190225205204j:plain

それでは、OpenGLとかDirectXの3Dグラフィックスを埋め込みたい時には、どう考えたらいいでしょうか。これは、Blendを使って作れるものではなく、プログラミングが必要ですから、UIデザイナーができるのは、表示エリアをどこに置くかぐらいのものです。3D表示のデザインもしたいのなら、デザイナーの指示でプログラマーがプログラミングするしか方法がありません。
Chart(グラフ)表示の時にはどうでしょうか。もしも初めからグラフの表示データ(6種類の商品の日にち毎の売り上げデータとか)がはっきりしているならば、データだけ公開してChart表示のライブラリーを使用してデザイナーにデザインしてもらう事も可能です。しかし、Blendでデザインできるのは静的な画面(後からオブジェクトを生成したりできない画面)なので、何種類の商品か不明だと、画面が作れません。6種類以下とか限定をかければ、6種類まで表示できるようにデザインしておき、3種類しかない時には残り3種類は表示を消しておく等での対応は可能です。
仕組みの限界と、何を誰がデザインするかで切り分けていけば良いでしょう。

Blend

画面は Blend で作ると言いましたが、Blend の解説はあまりないようです。ツールの操作の話になるので、文章での説明に手間がかかる為かもしれません。下記に、解説をリンクしておきます。

www.youtube.com
c-mitsuba.hatenablog.com

MVVM用ライブラリー

MVVMデザインパターンを作るためのライブラリーが存在します。これらを使用するとプログラミングが簡単になります。

Livet

Livet はすごく簡単にMVVMデザインパターンを実現できるライブラリーです。Visual Studio 2017 の 機能拡張と更新プログラム で Livet で検索して「Livet プロジェクトテンプレート・アイテムテンプレート・コードスニペット拡張機能」を導入すると、簡単に使う事ができます。
blog.okazuki.jp

Prism

Prism はもともとマイクロソフトのプロジェクトですが、独立して開発が進められているようです。MVVMのライブラリーですが、Composite Application Library だと言っています。Pluginで画面を埋め込んで拡張可能なアプリケーションを作るためのひな型です。
これも同じく Visual Studio 2017 の 機能拡張と更新プログラム で Prism Template Pack をインストールすると使えるようになります。
github.com
github.com
Prism の導入についてまとめていただいているBlogがありましたので、リンクさせてもらいます。
elf-mission.net

まとめ

MVVMデザインパターンでViewを切り離すことの意味を中心に述べてきました。XAMLはツールを使って画面を作るための言語なので、キー入力しないで Blend で画面を作りましょう。初めは大変ですが、慣れると楽しいですよ。