設計編の構成
前述の構成は、アーキテクチャ設計書としては読みやすいと思います。しかし実際にアーキテクチャ設計を行っていく場合、各ビューを頻繁に行ったり来たりしながら記述します。いずれかを先に完璧に書きあげるという訳には行きません。
たとえば論理ビューから実装ビュー・配置ビューは概ねその方向に流れて設計しますが、論理ビュー自体がユースケースビューや非機能要件ビューの設計に伴い頻繁に更新されるため、ウォーターフォール的な流れにはならず、インクリメンタルなプロセスになります。
本稿では「アーキテクチャ設計書はこうなります」という設計結果をお見せするのではなく、どのようにアーキテクチャを設計していくか解説したいと考えています。そのため設計書としてのアーキテクチャ設計とは、やや異なったアプローチで記載します。
そこで設計編では、次の構成で記載していきたいと思います。
-
前編
- 初期ドメインビューの設計
- 初期ユースケースビューの設計
- 初期非機能要件ビューの設計
- 初期配置ビューの設計
- 初期論理ビューの設計
- 初期実装ビューの設計
- データビューの設計
- プロセスビューの設計
-
後編
- 非機能要件の実現
- 代表的なユースケースの実現
- 開発者ビューの設計
前編
本稿、前編ではまずはざっくりしたアーキテクチャの概略を設計します。
この段階ではあまり正確なものを作ることに拘る必要はありません。正確なアーキテクチャはすべてのユースケースや非機能要件が実現されるまで完成しません。そのため、まずは後編に記載があるような代表的なユースケースの実現に着手できる状態とします。速度を優先し、正確性はある程度目をつぶりましょう。
これはいい加減で良いという意味ではありません。とくに類似のアーキテクチャに対する経験が多い方は、この段階でかなり正確な設計が可能です。ただ、悩んで何日も手が止まってしまうくらいなら、先に進めてからフィードバックすれば良いと思います。
後編
後編では非機能やユースケースの実現を設計します。
ユースケースの設計をしていく場合、机上ですべて設計するのは難しくて、仮実装しながら設計していくことも多いと思います。その場合に、認証やロギングの機能が実装されていないと、そもそもユースケースを実装できなかったり、エラーの解析が困難になったりします。そこで非機能のうち重要な部分を、ユースケースより先に設計します。
非機能要件は、アーキテクチャに影響があるすべての非機能要件について設計する必要があります。ただ紙面の都合もありますので、今回は普遍的に活用できそうないくつかの非機能に絞って設計したいと思います。
ユースケースの実現は、必ずしもすべてのユースケースを同じ粒度でアーキテクチャ設計書に記載する必要はありません。ユースケースをアーキテクチャ的な視点でパターン分けして、同一パターンの中から代表的なユースケースを選定します。その代表的なユースケースに絞って記載する形とします。
これらの中で、各ビューにフィードバックしていき、アーキテクチャ全体の精度を上げていきます。そして最後に開発者ビューを設計します。本稿の構成上最後に記載しますが、実際には最後に書かないといけないという訳ではありません。書けるタイミングで順次記載していき、開発上必要になるタイミングまでに完成させれば良いかと思います。
では、いってみましょう!
初期ドメインビューの設計
本章では購買ドメインのドメインビューを設計します。ドメインビューでは次の2つのモデルを設計します。
- 境界付けられたコンテキスト
- コンテキストマップ
境界付けられたコンテキストを利用して、購買ドメインを中心とみたときに、関連するドメイン・コンテキストを抽出して、それぞれのドメインがどのような役割を持つのか設計します。そこで抽出されたコンテキスト間の関係を、コンテキストマップをつかって設計します。
境界付けられたコンテキスト
予算編で記載したように、Adventure Works Cycles社全体の境界付けられたコンテキストは下記のとおりです。
Adventure Works Cycles社はワールドワイドな自転車製造・販売メーカーです。そのためビジネス全体をみたとき、コアとなるのは販売ドメインです。販売ドメインを提供するために、購買・製造・配送ドメインが支援します。
ただし本稿の開発対象は購買ドメインです。購買ドメインからみた境界付けられたコンテキストは下記のとおりです。
予算編で記載したものとほぼ同じですが、下記の2点を変更しています。
- 業務横断に共通する概念として、AdventureWorksドメインとコンテキストを定義
- 製造・販売コンテキストから認証コンテキストの依存線を削除
前者については、AdventureWorks全社に共通するオブジェクトを定義するコンテキストとして導出しました。基本的に企業にとってプリミティブなオブジェクトを定義し、複雑なオブジェクトはそれぞれの業務ドメイン内で定義することも検討してください。詳細はコンテキストマップの中で説明します。後者は、購買コンテキストに集中し、他のコンテキスト間の依存関係は意識しないようにするため、あえて削除しました。
コンテキストマップ
コンテキストが導かれたら、次はコンテキスト間の関係を整理します。ドメイン駆動設計のコンテキストマップを利用して整理したモデルが下記のとおりです。
コンテキスト間の関係を整理するためには、次の2つを明確にする必要があります。
- 関係の向き
- 関係の性質
矢印の向きが上流下流を表していて、矢印の向いている先が上流、矢印の根元が下流です。コアとなる購買コンテキストと、それ以外のコンテキストの関係について順に整理しながら、それらをどう考えればよいか説明していきましょう。
販売コンテキストと製造コンテキスト
たとえば購買コンテキストで他社の部品などを発注する場合、どれだけ発注するべきか判断するためには、販売情報が必要です。つまり購買コンテキストは販売コンテキストに依存します。そのため購買コンテキストが下流で、販売コンテキストが上流になります。
関係が決まったらその性質を決定します。ドメイン駆動設計では次のような関係の中から、いずれの関係に該当するか決定します。
- 共有カーネル
- カスタマー・サプライヤー
- 順応者
- 腐敗防止層
- 別々の道
- 公開ホストサービス
関係の性質はこれだけではありませんし、既存の性質で表現できない場合は、あたらしく定義してもかまいません。ただ多くの場合は上記のいずれかから選べば十分でしょう。さて、購買コンテキストと販売コンテキストを見た場合、どういった関係になるでしょうか?
購買コンテキストと販売コンテキストの開発は平行に行われます。スケジュールなどにつねに余裕があるとは限りません。あまり密に結合していると、販売コンテキストの変更に購買コンテキストが、追随できない可能性があります。またリリース後に販売コンテキストの改修が入った場合、購買コンテキストへの影響はできる限り限定したいところです。
そもそも購買コンテキストで必要な販売情報は、販売コンテキストほど詳細な情報は必要ありません。このような場合、販売コンテキストと購買コンテキストの「販売」オブジェクトは、別々に設計・実装したほうが良さそうです。
そのうえで、販売コンテキストで「販売」された場合、その情報を適宜変換して購買コンテキストに取り込み、購買コンテキストの「販売」オブジェクトとして扱うのが好ましいです。つまり「腐敗防止層」の関係とします。
製造コンテキストについても同様です。購買のためには、現在製造中の製品も考慮して必要な購買量を決定する必要があります。そのため製造コンテキストは購買コンテキストの上流となり、性質も腐敗防止層とするのが良いでしょう。
なお今回は購買コンテキストからみた関係性だけ記載しています。実際には逆から見たときの関係性も検討する必要がありますが、今回は購買ドメインにスコープを絞っているため、ここでの説明は割愛します。
AdventureWorksコンテキスト
さて、購買コンテキストと販売コンテキストにはどちらも「販売」オブジェクトが登場することを説明しました。販売オブジェクトは、一見共通のオブジェクトのように見えますが、購買コンテキストと販売コンテキストで必要になる属性や振る舞いが異なることから、それぞれのコンテキストに別々に定義することとしました。
しかし逆に直接共有したほうが好ましいモデルやコードもあります。そういったオブジェクトをAdventureWorksコンテキストに定義します。AdventureWorksコンテキストには、具体的には次のようなオブジェクトを定義します。
オブジェクト | 説明 |
---|---|
Date | 時刻を持たない年月日 |
Days | 日数 |
Dollar | 通貨(日本企業の場合はYenなど) |
Gram | 重量グラム |
DollarPerGram | グラム当たりの料金 |
これらは少なくともAdventureWorks内ではプリミティブなオブジェクトで、直接共有したほうが生産性も品質も高めることができます。これらのオブジェクトは、購買・販売・製造コンテキストの開発者で合意のもと協力して開発します。そのため「共有カーネル」という関係を選択しました。
これらのオブジェクトをドメイン駆動設計のValue ObjectやEntityとしてAdventureWorksコンテキストに実装します。複雑なオブジェクトは個別の業務ドメイン内に実装したほうが良いため、ほとんどはValue Objectになるでしょう。
ただこれらも、変更容易性を優先する場合は、上記のオブジェクトも業務コンテキストにあえて定義する方式も考えられます。生産性と変更容易性はトレードオフの関係になりやすいです。この辺りは共通部分に破壊的変更が入りやすいかどうか判断したらよいと思います。
なお共有カーネルのVisual Studio上のプロジェクトは、プロジェクト参照として実装するのが扱いやすいです。各ドメインで共有して実装していくためです。
認証コンテキスト
認証はとくにセキュリティ上、非常に重要なコンテキストになります。そのため個別のコンテキストで実装することはリスクが高く、慎重に作られたものを共有することが好ましいと判断しました。
ただAdventureWorksコンテキストのように複数のコンテキスト間で共有して継続的に開発するというより、共通の仕様を規定して作られたコンポーネントをそれぞれが利用するという形をとることとしました。そのため関係の性質としてはカスタマー・サプライヤーを選択しました。
カスタマー・サプライヤーのVisual Studio上のプロジェクトは、安定するまではプロジェクト参照として実装したほうが扱いやすいですが、実装が安定したら別のソリューションに移動し、NuGetパッケージとして参照することを検討しても良いでしょう。