ソフトウェア システムのアーキテクチャのモデリング
ユーザーのニーズに対応するソフトウェア システムまたはアプリケーションを開発できるように、Visual Studio Ultimate では、ソフトウェア システムまたはアプリケーションの全体的な構造と振る舞いの記述の一部として、モデルを生成できます。モデルを使用すると、設計全体で使用されるパターンも記述できます。これらのモデルは、既存のアーキテクチャの理解、変更についての話し合い、および意図の明確な伝達に役立ちます。
モデルの用途は、自然言語による記述のあいまいさを減らすことと、設計を視覚化し、代替の設計について効率的に話し合いができるようにすることです。モデルが使用される場では、他のドキュメントの使用または話し合いも必要です。モデルだけでは、アーキテクチャの仕様全体を表すことができません。
[!メモ]
このトピックでは、"システム" は開発中のソフトウェアのことを表します。多数のソフトウェア コンポーネントとハードウェア コンポーネントの大規模なコレクション、または単一のアプリケーション、アプリケーションのパーツなども、まとめて "システム" と呼びます。
システムのアーキテクチャは、2 つの領域に分けることができます。
大まかな設計。主要なコンポーネントについて説明し、各要求を満たすためにそれらがどのように相互作用するかを示します。大規模なシステムの場合、コンポーネントが小さいコンポーネントからどのように構成されるかを示す大まかな設計が、コンポーネント単位で作成されることがあります。
コンポーネントの設計全体で使用されるデザイン パターンと規則。パターンは、プログラミングの目的を達成するための特定の方法を示します。設計全体で同じパターンを使用することにより、変更の適用および新しいソフトウェアの開発に伴うコストを削減できます。
大まかな設計
大まかな設計は、システムの主要なコンポーネントと、それらのコンポーネントが設計の目標を達成するためにどのように相互作用するかを示します。次の一覧は、大まかな設計の作成に必要なアクティビティを示しています。一覧に示されている順序は実際の手順の順序と必ずしも同じではありません。
既存のコードを更新する場合は、一般的に、主要なコンポーネントの記述から開始します。ユーザー要求に対する変更を把握したうえで、コンポーネント間の相互作用を追加または変更してください。新しいシステムを開発する場合は、ユーザーのニーズの主要な特性を理解することから始めます。その後で、主要なユース ケースについて相互作用のシーケンスを模索し、そのシーケンスをコンポーネントの設計にまとめることができます。
どの場合も、複数の異なるアクティビティを並行して開発し、コードとテストを早い段階で作成しておくと効果的です。1 つのアクティビティを完了してから別のアクティビティを開始することは回避してください。通常、要求の内容とシステムの最適な設計方法に対する認識は、コードを作成したりテストを行ったりしている間に変化します。したがって、まず要求と設計の主要な特性を理解してからコーディングする必要があります。詳細は、プロジェクトの後期のイテレーションで補います。
要求の把握。設計は常に、ユーザーのニーズを明確に把握することから始まります。
アーキテクチャ パターン。選択したシステムのコア テクノロジとアーキテクチャ要素です。
コンポーネントとそのインターフェイス。システムの主要なパートと、それらの相互作用に使用されるインターフェイスを示すためにコンポーネント図を描画できます。各コンポーネントのインターフェイスには、シーケンス図で指定したすべてのメッセージが含まれます。
コンポーネント間の相互作用。ユース ケース、イベント、または受信メッセージごとに、必要な応答を返すためにシステムの主要コンポーネントがどのように相互作用するかを示すシーケンス図を描画できます。
コンポーネントとインターフェイスのデータ モデル。コンポーネント間でやり取りされ、コンポーネントの内部に格納される情報を示すクラス図を描画できます。
要求の把握
アプリケーション全体の大まかな設計は、要求モデルなどのユーザーのニーズを示す記述と組み合わせることで、効果的に作成できます。要求モデルの詳細については、「ユーザー要求のモデリング」を参照してください。
開発中のシステムがより大きなシステムに属するコンポーネントである場合は、要求の一部またはすべてをプログラミング インターフェイスに埋め込むことができます。
要求モデルは、次のような非常に重要な情報を提供します。
提供インターフェイス。提供インターフェイスは、システムまたはコンポーネントがそのユーザー (人間のユーザーおよび他のソフトウェア コンポーネント) に提供する必要のあるサービスまたは操作を列挙します。
要求インターフェイス。要求インターフェイスは、システムまたはコンポーネントが使用できるサービスまたは操作を列挙します。これらすべてのサービスは、独自のシステムの一部として設計できることもあります。また、特に、多数の構成で他のコンポーネントと結合できるコンポーネントを設計する場合などには、外部の考慮事項を基に要求インターフェイスが設定されます。
サービス品質要求。満たす必要のあるシステムのパフォーマンス、セキュリティ、保全性などの目標と制約です。
要求モデルは、システムのユーザーの観点から記述されます。ユーザーが人間のユーザーであるか、他のソフトウェア コンポーネントであるかは問いません。システムのユーザーは、システムの内部動作には一切関知しません。これとは対照的に、アーキテクチャ モデルの目的は、内部動作を記述し、その動作がユーザーのニーズをどのように満たしているかを示すことです。
要求についてユーザーと効率的に話し合いができるように、要求モデルとアーキテクチャ モデルを切り離すことをお勧めします。これは、要求を変更することなく設計をリファクタリングし、代替のアーキテクチャを検討するのにも役立ちます。
要求モデルとアーキテクチャ モデルは、次の 2 つの方法のいずれかで切り離すことができます。
要求モデルとアーキテクチャ モデルを同じソリューション内の異なるプロジェクトに保持する方法。これらは、UML モデル エクスプローラーでは個別のモデルとして表示されます。複数のチーム メンバーが並行してモデルを操作できます。モデル間で生成できるトレースの種類は限られます。
要求モデルとアーキテクチャ モデルを同じ UML モデルの異なるパッケージに配置する方法。これにより、モデル間の依存関係を簡単にトレースできるようになりますが、複数のメンバーが同時にモデルを操作することはできません。また、モデルのサイズが非常に大きい場合は、Visual Studio に読み込むのに時間がかかります。したがって、この方法は大規模なプロジェクトには適していません。
要求モデルまたはアーキテクチャ モデルに追加する必要のある詳細の量は、プロジェクトの規模と、チームのサイズおよび分散具合に応じて決定されます。短いプロジェクトの小規模なチームはことができます。業務概念といくつかのクラス ダイアグラムにアクセスするデザイン パターン スケッチより、その後に; 複数の領域に分布した大規模なプロジェクトは多くの詳細を必要とします。
アーキテクチャ パターン
開発プロセスの早い段階で、設計の基礎として使用する主要なテクノロジと要素を選ぶ必要があります。このような選択を行う必要のある領域は、次のとおりです。
ベース テクノロジ。データベースかファイル システムかの選択、ネットワーク接続されたアプリケーションか Web クライアントかの選択など。
フレームワーク。Windows Workflow Foundation か ADO.NET Entity Framework かの選択など。
統合方法。エンタープライズ サービス バスかポイント ツー ポイント チャネルかの選択など。
こうした選択は、多くの場合、規模や柔軟性などのサービス品質要求によって決定され、要求の詳細が明らかになる前に行うことができます。大規模なシステムでは、ハードウェアとソフトウェアの構成は密接に相関しています。
こうした選択は、アーキテクチャ モデルの使用と解釈の方法に影響を与えます。たとえば、データベースを使用するシステムの場合、クラス図の関連でデータベースにおける関係または外部キーが表されることがあります。また、XML ファイルに基づくシステムの場合、関連で XPath を使用するクロス リファレンスが示されることがあります。分散システムの場合は、シーケンス図内のメッセージで送信対象のメッセージを表現でき、自己完結型アプリケーションの場合は、シーケンス図内のメッセージで関数呼び出しを表現できます。
コンポーネントとそのインターフェイス
このセクションの主な推奨事項は、次のとおりです。
システムの主要なパートを示すコンポーネント図を生成する。
コンポーネント間、またはコンポーネントのインターフェイス間の依存関係を描画し、システムの構造を示す。
コンポーネントのインターフェイスを使用して、各コンポーネントが提供または要求するサービスを示す。
大規模な設計の場合は、複数の個別の図を描画して、各コンポーネントをより小さなパートに分解できる。
これらの点については、このセクションの残りの部分で詳しく説明します。
コンポーネント
アーキテクチャ モデルの最も重要なビューは、システムの主要なパートとそれらの相互依存関係を示すコンポーネント図です。コンポーネント図の詳細については、「UML コンポーネント図: リファレンス」を参照してください。
大規模なシステム用のコンポーネント図には、通常、次のようなコンポーネントが含まれます。
プレゼンテーション。ユーザーにアクセスを提供するコンポーネント。通常は Web ブラウザーで実行されます。
Web サービス コンポーネント。クライアントとサーバーの間の接続を提供します。
ユース ケース コントローラー。各シナリオの手順をユーザーに示します。
ビジネス コア。主要な操作を実装し、ビジネス上の制約を課す要求モデルのクラスに基づくクラスを格納します。
データベース。ビジネス オブジェクトを格納します。
コンポーネントのログ記録とエラー処理。
コンポーネント間の依存関係
コンポーネントそのものに加えて、コンポーネント間の依存関係も示すことができます。2 つのコンポーネント間の依存関係矢印は、一方の設計を変更すると、もう一方の設計にその影響が及ぶ可能性があることを表します。これは、通常、一方のコンポーネントが直接的または間接的に提供するサービスまたは関数をもう一方のコンポーネントが使用しているために生じます。
適切に構成されたアーキテクチャでは、依存関係が明確に整理されており、次の条件が満たされています。
依存関係グラフにループがない。
コンポーネントがレイヤーに配置され、すべての依存関係が 1 つのレイヤーのコンポーネントから次のレイヤーのコンポーネントに向かって設定されている。レイヤー間の依存関係の方向がすべて同じです。
コンポーネント間の依存関係を直接示すことも、コンポーネントに接続されている要求インターフェイスと提供インターフェイスの間の依存関係を示すこともできます。インターフェイスを使用すると、各依存関係で使用される操作を定義できます。通常、図が最初に描画されるとき、依存関係はコンポーネント間に示されます。情報が追加されるにつれ、それはインターフェイス間の依存関係に置き換えられます。どちらもソフトウェアの記述としては適切ですが、インターフェイス間に依存関係を示すほうが、コンポーネント間に示すよりも多くの詳細を提供できます。
保守が容易なソフトウェアを開発する場合、依存関係の管理は非常に重要です。コンポーネント図には、コード内のすべての依存関係を反映させる必要があります。コードが既に存在する場合は、すべての依存関係が図に示されていることを確認してください。コードを開発中の場合は、コンポーネント図で計画されていない依存関係がコードに含まれないようにしてください。コード内の依存関係を検出するには、レイヤー図を生成します。コードをレイヤー図と照らし合わせて検証すると、計画した依存関係の制約が満たされていることを確認できます。詳細については、「レイヤー図: リファレンス」を参照してください。
インターフェイス
コンポーネントにインターフェイスを配置することで、各コンポーネントが提供する主要な操作のグループを分離し、それに名前を付けることができます。たとえば、Web ベースの販売システムのコンポーネントには、顧客が商品を購入するときに使用するインターフェイス、業者がカタログを更新するのに使用するインターフェイス、およびシステムの管理に使用するインターフェイスを配置できます。
コンポーネントには、任意の数の提供インターフェイスと要求インターフェイスを配置できます。提供インターフェイスは、コンポーネントが他のコンポーネントが使用できるように提供するサービスを示します。要求インターフェイスは、コンポーネントが他のコンポーネントで使用するサービスを示します。
提供インターフェイスと要求インターフェイスの両方を定義すると、コンポーネントを設計の残りの部分から明確に切り離すことができます。これにより、次の手法を使用できます。
コンポーネントをテスト ハーネスに配置する。周囲のコンポーネントは、このテスト ハーネスによってシミュレートされます。
コンポーネントを他のコンポーネントから切り離して開発する。
コンポーネントのインターフェイスを他のコンポーネントに結合することにより、コンポーネントを他のコンテキストで再利用する。
操作の一覧をインターフェイスで定義する場合は、UML クラス図でそのインターフェイスの別のビューを生成できます。これを行うには、UML モデル エクスプローラーでインターフェイスを探し、クラス図にドラッグします。こうすると、操作をインターフェイスに追加できます。
UML インターフェイスに追加した操作によって、コンポーネントの振る舞いを呼び出すことのできるあらゆる方法を表現できます。たとえば、Web サービス要求、その他の種類のシグナルまたは相互作用、通常のプログラムの関数呼び出しなどを表すことができます。
追加する操作を決定するには、コンポーネント間の相互作用を示すシーケンス図を生成します。詳細については、「コンポーネント間の相互作用」を参照してください。これらのシーケンス図には、それぞれ異なるユース ケースで発生する相互作用が示されます。この方法を用いると、ユース ケースを模索しながら、各コンポーネントのインターフェイスに追加した操作の一覧に操作を随時追加できます。
コンポーネントのパートへの分解
前のセクションで説明した手順は、各コンポーネントに適用できます。
各コンポーネントの中で、そのサブコンポーネントをパートとして表現することができます。パートは、実質的には親コンポーネントの属性であり、一種のクラスです。各パートは独自の型を持ち、それをコンポーネントにすることもできます。このコンポーネントを図に配置し、そのパートを示すことができます。詳細については、「UML コンポーネント図: ガイドライン」を参照してください。
この手法をシステム全体に適用すると効果的です。これを行うには、システム全体を単一のコンポーネントとして描画し、その主要なコンポーネントをパートとして示します。そうすれば、外部とのシステムのインターフェイスを明確に区別できます。
コンポーネントの設計で別のコンポーネントを使用する場合、さまざまな状況において、そのコンポーネントをパートとして表現するか、要求インターフェイスを通じてアクセスする別のコンポーネントとして表現するかを選択できます。
パートは、次の状況において使用します。
親コンポーネントの設計でパートのコンポーネント型を必ず使用する必要がある。そのため、パートの設計が親コンポーネントの設計に不可欠である。
親コンポーネントが抽象的な存在である。たとえば、ビューおよびユーザーとの相互作用を処理する実際のコンポーネントのコレクションを表すプレゼンテーション層と呼ばれる概念的なコンポーネントなどがこれに該当します。
要求インターフェイスを通じてアクセスされる独立したコンポーネントは、次の状況において使用します。
要求側コンポーネントを、そのインターフェイスを通じて実行時に別の提供側コンポーネントに結合できる。
設計がプロバイダーを別のプロバイダーに簡単に置き換えることのできる設計である。
通常は、パートよりも要求インターフェイスを使用する方が適しています。設計に時間はかかりますが、より柔軟性のあるシステムを構築できます。また、コンポーネントを別々にテストするのも容易です。これにより、開発計画での結合を少なくすることができます。
コンポーネント間の相互作用
このセクションの主な推奨事項は、次のとおりです。
システムのユース ケースを識別する。
システムのコンポーネントが他のコンポーネントおよびユーザーとの相互作用によって必要な結果をどのように達成しているかを示す図を、ユース ケースごとに 1 つ以上描画する。通常は、シーケンス図かアクティビティ図を描画します。
インターフェイスを使用して、各コンポーネントが受信するメッセージを指定する。
インターフェイス内の操作の効果を記述する。
コンポーネントごとにこの手順を繰り返し、そのパートの相互作用を示す。
たとえば、Web ベースの販売システムの場合、顧客による購入を要求モデルでユース ケースとして定義できます。さらに、シーケンス図を生成し、プレゼンテーション層での顧客とコンポーネントの相互作用を示したり、顧客と倉庫コンポーネントおよび会計コンポーネントの相互作用を示したりできます。
開始イベントの識別
ほとんどのソフトウェア システムが行う処理は、さまざまな入力またはイベントに対するシステムの応答ごとに簡単に分割できます。開始イベントには、次のようなものがあります。
ユース ケースの最初のアクション。要求モデルでは、これはユース ケースの手順か、アクティビティ図のアクションとして表示されます。詳細については、「UML ユース ケース図: ガイドライン」および「UML アクティビティ図: ガイドライン」を参照してください。
プログラミング インターフェイスのメッセージ。開発中のシステムがより大きなシステムのコンポーネントである場合は、それをコンポーネントのいずれかのインターフェイスに操作として記述する必要があります。詳細については、「コンポーネントとそのインターフェイス」を参照してください。
システムが監視する特定の状態、または時刻などの一般的なイベント。
計算の記述
コンポーネントが開始イベントに対してどのように応答するかを示すには、シーケンス図を描画します。
典型的なシーケンスで使用されているコンポーネント インスタンスごとに生存線を描画します。それぞれの型のインスタンスが複数存在することもあります。システム全体を単一のコンポーネントとして記述した場合は、含まれるパートごとに生存線が 1 つ存在する必要があります。
詳細については、「UML シーケンス図: ガイドライン」を参照してください。
場合によっては、アクティビティ図も役立ちます。たとえば、コンポーネントでデータのフローが途切れない場合は、それをオブジェクト フローとして記述できます。コンポーネントに複雑なアルゴリズムがある場合は、それを制御フローとして記述できます。コメントを使用するなどして、各アクションを実行するコンポーネントを明確にしてください。詳細については、「UML アクティビティ図: ガイドライン」を参照してください。
操作の指定
図には、各コンポーネントが実行する操作が示されます。この操作は、シーケンス図ではメッセージとして表現され、アクティビティ図ではアクションとして表現されます。
これらの操作は、コンポーネントごとにまとめて収集してください。コンポーネントに提供インターフェイスを生成し、操作をそのインターフェイスに追加します。通常は、クライアントの種類ごとに別のインターフェイスを使用します。UML モデル エクスプローラーを使用すると、ごく簡単に操作をインターフェイスに追加できます。同じように、各コンポーネントが使用する他のコンポーネントの操作を収集し、コンポーネントに接続されている要求インターフェイスに配置します。
アクティビティ図またはシーケンス図にコメントを追加し、各操作によって達成された結果をメモしておくと効果的です。各操作の効果を、その Local Postcondition プロパティに記述することもできます。
コンポーネントとインターフェイスのデータ モデル
コンポーネントのインターフェイスで各操作のパラメーターと戻り値を定義します。操作が Web サービス要求などの呼び出しを表している場合、パラメーターは、要求の一部として送信される情報です。操作によって複数の値が返される場合は、Direction プロパティ セットを Out に設定してパラメーターを使用できます。
各パラメーターと戻り値には型があります。これらの型は、UML クラス図を使用して定義できます。実装の詳細をこれらの図で表現する必要はありません。たとえば、XML として送信されるデータを記述する場合は、関連を使用して XML のノード間のあらゆる種類のクロス リファレンスを表現し、クラスを使用してノードを表現することができます。
関連と属性に対するビジネス上の制約を記述するには、コメントを使用します。たとえば、顧客の注文に含まれる品目がすべて同じ販売業者の品目であることが必要な場合には、注文品目と商品カタログ品目の間の関連、および商品カタログ品目とその販売業者の間の関連への参照を使用して、これを記述できます。
デザイン パターン
デザイン パターンは、ソフトウェアの特定の特性 (特に、システムのさまざまなパートで繰り返し発生するもの) を設計する方法のアウトラインです。プロジェクト全体で統一された方法を採用することで、設計コストを削減したり、ユーザー インターフェイスの一貫性を確保したりできるほか、コードの理解と変更に要するコストを削減できます。
オブザーバーなどの一般的なデザイン パターンは、よく知られており、幅広く適用できます。また、特定のプロジェクトにのみ適用できるパターンもあります。たとえば、Web 販売システムの場合、コードにいくつかの操作が含まれ、それによって顧客の注文に変更が加えられるとします。注文の状態がすべての段階で正確に表示されるようにするには、これらすべての操作が特定のプロトコルに従ってデータベースを更新する必要があります。
ソフトウェア アーキテクチャに関する作業には、設計全体で採用する必要のあるパターンを決定する作業も含まれます。通常、これは、プロジェクトの進行と共に新しいパターンが出現したり、既存のパターンが変更されたりするため、継続的に行われます。主要なデザイン パターンをそれぞれ早い段階で適用できるように、開発計画を策定することをお勧めします。
ほとんどのデザイン パターンは、部分的にフレームワーク コードに埋め込むことができます。パターンの一部を削って、データベースの適切な処理を確保するデータベース アクセス層などの特定のクラスまたはコンポーネントを開発者が使用するように要求するだけのパターンに変更できます。
デザイン パターンはドキュメントに記述され、一般的に、次の内容で構成されます。
名前。
このデザイン パターンを適用できるコンテキストの説明。開発者がこのパターンを適用するときに検討する必要のある基準です。
このデザイン パターンが解決する問題の簡潔な説明。
主要なパートとその関係のモデル。相互に関連および依存関係を持つクラスまたはコンポーネントとインターフェイスなどがこれに該当します。通常、これらの要素は次の 2 つのカテゴリに分けられます。
パターンが使用されるコードのすべての部分で開発者が繰り返し使用する必要のある要素。これらの要素を記述するために、テンプレートの型を使用できます。詳細については、「UML ユース ケース図: リファレンス」を参照してください。
開発者が使用する必要のあるフレームワーク クラスを記述する要素。
パート間の相互作用のモデル (シーケンス図またはアクティビティ図を使用)。
名前付け規則。
パターンによる問題の解決方法の説明。
開発者が採用できる可能性のあるバリエーションの説明。