連載
|
|
|
■横断的関心事
横断的関心事は、複数の論理階層や物理階層にまたがり、アプリケーション全体に影響を与えるような設計・実装上の課題である。
AAGでは多数の横断的関心事について設計上の注意点を示しているが、正式公開版では「キャッシュ」「例外管理」「入力値とデータの検証」について、具体的な設計ステップの説明が追加された。本項ではそれら3つについて解説する。
●キャッシュ
アプリケーションで一度扱った情報をキャッシュして再利用することで、アプリケーションのパフォーマンスと応答性が大きく改善される可能性がある。しかし、キャッシュの設計が不適切だと、逆にパフォーマンスや応答性を悪化させてしまう危険性もある。
キャッシュの利用を最適化するため、以下のステップに沿って設計する。
(1)キャッシュするデータを決定する:アプリケーションの論理階層ごとに、キャッシュするデータを洗い出す。一般的には、以下のようなデータをキャッシュすることを検討するとよい。
-
すべてのユーザーが共通的に使用するデータ――例えばECサイトなら「製品一覧」や「製品詳細」などのように、すべてのユーザーが共通的に使用するような、あまり変更されないデータをキャッシュする。
-
あまり変更されないデータ――完全に静的なデータか、あるいはほとんど変更されないようなデータ。例えば構成情報やデータベースから読み取った定数や固定値など。
-
更新される部分の少ないWebページ――更新の少ないWebページは、出力全体か、あるいはその一部をキャッシュするとよい。
-
ストアド・プロシージャのパラメータやクエリの結果セット――データ・ソースに対するクエリで頻繁に使われるものがある場合は、そのパラメータや結果をキャッシュする。
(2)キャッシュする場所を決定する:データを「どこに」キャッシュするか、および「どこで」キャッシュするかを検討する。
「どこに」というのは、メモリ上にキャッシュするのか、それともファイル・システム上にキャッシュするのか、ということである。メモリ上のキャッシュに適したデータは、比較的少量で、割と頻繁に更新されるようなものである。一方、ファイル・システム上のキャッシュに適したデータは、比較的大きなデータや、プロセスの再起動を越えて引き継がれるような更新の少ないデータである。特に、本来のデータ・ソースに対するアクセスに時間がかかる場合、またはデータ・ソースにアクセスできない可能性がある場合などは、ファイル・システム上でのキャッシュが有効である。
「どこで」というのは、アプリケーションロジックのどの部分でデータをキャッシュするかということである。下記の表を参考にするとよい。
キャッシュする場所 | 適したデータ |
クライアント | 画面やユーザーに依存したデータ。比較的少量で、セキュリティ上の問題がないもの |
プロキシ・サーバやWebサーバ | 頻繁に要求される、変更の少ない画面。あるいは、HTTP要求に含まれるパラメータだけを基に生成可能なデータ |
プレゼンテーション層 | 比較的変更の少ない画面で使われるデータや、ユーザー情報だけに依存したデータや、生成にコストがかかるようなUIコントロールなど |
ビジネス層 | サービスやビジネス・プロセスやワークフローの状態。あるいは、比較的変更が少ないが、プレゼンテーション層からの要求ごとに生成するのにはコストがかかるようなデータ |
データ・アクセス層 | 頻繁に呼び出されるクエリのパラメータや、戻り値そのもの。あるいは、型付データセットのスキーマ情報 |
データベース | 非常に時間がかかるようなクエリの結果。場合によっては別のテーブルに保存しておく |
データをキャッシュする場所と、その場所に適したデータの例 |
(3)データの形式を決定する:アプリケーションのプロセスが管理するメモリ上にキャッシュする場合は、最も利用しやすい形式、取得してそのまま使える形式でキャッシュするとよい。キャッシュのために通信やファイル・アクセスが必要な場合は、データのシリアライズ/デシリアライズを考慮に入れる必要がある。
(4)キャッシュの管理方針を決定する:キャッシュの破棄や入れ替えに関する方針を選択する。破棄とは、更新されたり削除されたりして不適切になったデータをキャッシュから取り除くことである。入れ替えとは、適切ではあるが使用頻度の少ないデータを使用頻度の高いデータと置き換えることである。
キャッシュを破棄するには、期限切れをきっかけとする場合と、通知をきっかけとする場合が考えられる。期限切れベースの破棄は、更新の頻度が高いか、定期的に更新されるようなデータに適している。ただし、有効期限の延長についても検討する必要がある。通知ベースの破棄は、更新の頻度が低いか、不定期に更新されるようなデータに適している。
キャッシュを入れ替えるには、明示的に入れ替える場合と、自動的に入れ替える場合が考えられる。明示的な入れ替えでは、入れ替えタイミングを完全に制御できる。キャッシュの容量に余裕がある場合に適している。自動的な入れ替えは、キャッシュの容量が限られている場合に適している。よく使われる戦略は、「使用されていない期間が長いデータから削除する」「使用頻度が低いデータから削除する」「あらかじめ設定された優先度が低いデータから削除する」といったものである。
(5)いつキャッシュにデータをロードするかを決定する:データのロードは、事前に行う場合と、事後に行う場合が考えられる。事前ロードの典型例は、アプリケーションの起動時にデータをロードすることであり、キャッシュするデータの量があらかじめ分かっている場合や、データ・ストアへのアクセスに時間がかかる場合に適している。一方、事後ロードの典型例は、一度要求されたデータを、次に再び要求されるまでキャッシュすることであり、データが比較的頻繁に更新される場合や、データ量が多い場合、データ・ストアへのアクセスが容易な場合に適している。
●例外管理
例外管理の方針を統一させることは、アプリケーションのセキュリティや信頼性や運用性を高めるうえで非常に重要である。また、アプリケーション開発とテストを容易にし、導入コストを下げる効果もある。
(1)処理すべき例外を特定する:一般的には、アプリケーション例外とシステム例外に分類される。アプリケーション例外の中には、業務処理の不整合を表すビジネス例外が含まれることもある。
(2)例外検出の方針を決定する:原則として、システム全体で構造化例外処理機構を活用する。そのうえで例外をキャッチするときは、ログ出力の情報を集める場合、例外が保持する情報に追加する場合、リソースを解放する場合、例外が発生した処理を再実行する場合など、意味のある処理を実行する場合に限るべきである。
(3)例外を伝播(でんぱ)させる方針を決定する:状況に合わせて、キャッチしない、キャッチして再スローする、キャッチして別の例外でラップする、キャッチして握りつぶす、の中から選択する。
(4)カスタム例外の仕様や方針を決定する:一般的には、.NET Frameworkに含まれる例外と同じ意味を持つカスタム例外は作成しない。新しい例外を作成する必要がある場合は、.NET Frameworkの標準的な例外実装規約(例えば、クラス名を「〜Exception」とする、標準的なコンストラクタを実装するなど)に従う。
(5)収集すべき情報を決定する:例外が保持する情報の典型例が、例外メッセージである。ただし、その例外メッセージを見るのは誰なのかを認識しておく必要がある。ユーザーに表示する情報なのか、開発者がテストやデバッグに利用する情報なのか、運用管理者がシステムの状態を把握するための情報なのか、利用形態に応じて適切な情報を含めること。
(6)例外をログ出力する方式を決定する:ログ出力先として、Windowsのイベント・ログ、データベース、ログ・ファイル、メッセージ・キューなどが考えられる。例外の種類に応じて出力先を選択するとよい。例えば、セキュリティ例外はイベント・ログに出力するなどである。
(7)例外の通知方式を決定する:例外発生を運用管理者に通知する場合はログ出力だけでは不十分な場合もある。WMI、電子メール、携帯電話のショート・メッセージなどが考えられる。サード・パーティによる統合運用管理システムを利用してもよい。
(8)未処理例外の対処方針を決定する:システム境界では、そこに到達したすべての例外を処理する必要がある。一般的には、ログに出力した後、ユーザーにメッセージを伝えるための処理を行う。その際、システム内部の情報や機密情報を不用意に公開することがないように注意する。
●入力値とデータの検証
入力値とデータを適切に検証することで、アプリケーションの信頼性とセキュリティを高めるだけでなく、ユーザビリティを高くすることもできる。
検証を設計する際には以下のステップに沿うことを推奨する。
(1)信頼境界を特定する:未検証のため信頼できないデータがシステムに入ってくる可能性がある場所が信頼境界である。例としては、ファイアウォール、Webサーバとデータベース・サーバの間、アプリケーションと外部サービスの間、などがある。原則として、すべての信頼境界でデータを検証する必要がある。
(2)重要なシナリオを抽出する:例えば、ユーザーの入力値は、許容されない値が入っていたり、改ざんされていたりする危険性があるため、検証されるまでは危険なものと見なさないといけない。また、ビジネス層では、ビジネス・ルールに不整合を起こす値はエラーとして扱わなければならない。
(3)検証を実行する場所を決定する:サーバ上で検証する場合や、クライアントとサーバの両方で検証する場合が考えられる(クライアント上の検証だけに頼ってはいけない)。検証する場所に応じて、実装のためのテクノロジがいくつか存在する。
(4)検証の方針を決定する:一般的には、「既知の安全な値だけを受け入れる」「既知の危険な値をエラーにする」「危険な値を取り除くかエスケープする」といった方針が採られる。ただし、ブラックリスト方式ともいわれる上記の2番目と3番目の方式は、当初想定していなかった入力の危険性が後から判明することがあるため、アプリケーション開発者による独自の実装は推奨されない。値をエスケープする処理は、ライブラリなどで提供される専用のAPIを使うべきである。
最後にクラウド・サービスを説明する。
INDEX | ||
連載:アプリケーション・アーキテクチャ・ガイド2.0解説 | ||
第7回 補遺:AAG正式版について | ||
1.ドメイン駆動設計 | ||
2.横断的関心事 | ||
3.クラウド・サービス | ||
「アプリケーション・アーキテクチャ・ガイド2.0解説」 |
- 第2回 簡潔なコーディングのために (2017/7/26)
ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている - 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう - 第1回 明瞭なコーディングのために (2017/7/19)
C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える - Presentation Translator (2017/7/18)
Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|