MVVM と言語のパフォーマンスに関するヒント

このトピックでは、ソフトウェアの設計パターンとプログラミング言語の選択に関連するいくつかのパフォーマンスの考慮事項について説明します。

Model-View-ViewModel (MVVM) パターン

Model-View-ViewModel (MVVM) パターンは、多くの XAML アプリで共通です。 (MVVM は、Fowler の Model-View-Presenter パターンの説明によく似ていますが、これは XAML に合わせて調整されました)。 MVVM パターンの問題は、このパターンが原因となり、誤ってアプリのレイヤーおよび割り当てが過剰になる可能性があることです。 MVVM を使用する利点は次のとおりです。

  • 懸念事項の分離。 問題を細かく分割することは常に有用であり、MVVM や MVC などのパターンは、アプリ (または 1 つのコントロール) を、実際のビュー、ビューの論理モデル (ビュー モデル)、ビューに依存しないアプリのロジック (モデル) に細かく分割するための方法です。 具体的には、設計者は 1 つのツールを使ってビューを所有する、開発者は別のツールを使ってモデルを所有する、デザイン インテグレーターは両方のツールを使ってビュー モデルを所有することが、一般的なワークフローです。
  • 単体テスト。 ビューに依存せずに、つまりウィンドウの作成や入力の促進などに依存せずに、ビュー モデル (および結果としてモデル) の単体テストを実行できます。 ビューを小さく保つことにより、ウィンドウを作成することなく、アプリの大部分をテストできます。
  • ユーザー エクスペリエンスの変化に対する機敏性。 ユーザー エクスペリエンスがエンド ユーザーからのフィードバックに基づいて調整されるため、ビューは最も頻繁に変更され、最新の変更が加えられる傾向があります。 ビューを分離しておくことにより、これらの変更に、より迅速に、アプリへの影響を抑えて対応することができます。

MVVM パターンには、複数の具体的な定義と、それを実装するためのサード パーティのフレームワークがあります。 ただし、パターンのすべてのバリエーションに厳密に準拠すると、アプリのオーバーヘッドが必要以上に増大します。

  • XAML データ バインディング ({Binding} マークアップ拡張) は、1 つにはモデル/ビュー パターンを有効にするために設計されました。 {Binding} により、重大なワーキング セットと CPU オーバーヘッドが生じます。 {Binding} を作成すると一連の割り当てが行われるほか、バインディング ターゲットの更新がリフレクションやボックス化の原因となる可能性があります。 これらの問題は、ビルド時にバインディングをコンパイルする、{x:Bind} マークアップ拡張によって対処されています。 推奨事項: {x:Bind} を使用します。
  • MVVM では、一般的な DelegateCommand または RelayCommand ヘルパーなどの ICommand を使用して、ビュー モデルに Button.Click を接続することが一般的です。 ただし、これらのコマンドは、CanExecuteChanged イベント リスナー、ワーキング セットの増加、ページの起動/ナビゲーション時間の増加など、余分な割り当てとなります。 推奨事項: 便利な ICommand インターフェイスを使用する代わりに、分離コードにイベント ハンドラーを配置し、ビュー イベントにイベント ハンドラーを接続することを検討して、それらのイベントが発生したときに、ビュー モデルでコマンドを呼び出します。 コマンドが利用できない場合、ボタンを無効にするコードを追加する必要があります。
  • MVVM では、UI の使用可能なすべての構成でページを作成し、Visibility プロパティを VM でのプロパティにバインドすることによって、ツリーの一部を折りたたむことが一般的です。 これにより、起動時間と、場合によってはワーキング セットが不必要に増加します (ツリーの一部は表示されない可能性があるため)。 推奨事項:x:Load 属性または x:DeferLoadStrategy 属性を使って、ツリーの不要な部分をスタートアップから延期します。 また、ページのさまざまなモードについて個別のユーザー コントロールを作成し、分離コードを使って必要なコントロールのみを読み込みます。

C++/CX の推奨事項

  • 最新バージョンを使います。 C++/CX コンパイラは継続的にパフォーマンスが向上しています。 アプリが最新のツールセットを使ってビルドされていることを確認します。
  • RTTI (/GR-) を無効にします。 RTTI はコンパイラで既定でオンになっているため、ビルド環境でオフにしない限り、RTTI を使用している可能性があります。 RTTI には大きなオーバーヘッドがあるため、コードが RTTI に大きく依存していない限り、オフにしてください。 XAML フレームワークには、コードで RTTI を使用するという要件はありません。
  • ppltasks を使いすぎないようにします。 ppltasks は、非同期 WinRT API を呼び出すときに非常に便利ですが、重大なコード サイズのオーバーヘッドが生じます。 C++/CX チームは、パフォーマンスを大幅に向上させる言語機能 (await) の開発を進めています。 当面の間、コードのホット パスでの ppltasks の使用を調整してください。
  • アプリの "ビジネス ロジック" での C++/CX の使用を避けます。 C++/CX は、C++ アプリから WinRT API にアクセスするための便利な方法として設計されています。 これは、オーバーヘッドがあるラッパーを利用します。 クラスのビジネス ロジック/モデル内で C++/CX を使用することを避け、コードと WinRT の間の境界で使用するために予約しておきます。