ここでは、ドメイン駆動設計でマイクロサービスを開発する手順について説明します。
また、ここでは、次の考え方を適用して開発します。
アプリケーションアーキテクチャの設計
まず、次の手順で、マイクロサービスの単位を決めます。
アプリケーションポートフォリオの設計
まず、企業全体のアプリケーションタイプを洗い出します。
アプリケーションタイプは、概念レベルの本質的な(製品や技術に左右されない)アプリケーションの型で、ビジネスアーキテクチャの一つ、ジョブ(職務)を支援する役割を表します。
なので、会社のジョブと一対一の関係でアプリケーションタイプを洗い出します。
詳細は、アプリケーションポートフォリオの設計を参照してください。
アプリケーション戦略の策定
次に、アプリケーションポートフォリオを構成するアプリケーションタイプのどれにマイクロサービスを適用するか戦略を策定します。
詳細は、アプリケーション戦略の策定を参照してください。
それから、基幹システムをマイクロサービス化する場合は、ストラングラーアプリケーションパターンを適用して、具体的にマイクロサービス化するアクションプランを策定します。
ドメインの分析
最後に、マイクロサービスを適用するアプリケーションタイプのドメイン(開発対象の領域)を明確にします。
ドメインは次のように分類することができます。
- ビジネスドメイン
業務の領域。- ビジネス固有ドメイン
「販売管理」、「購買管理」など業務固有の活動領域。 - ビジネス共通ドメイン
「単位」など業務に共通した管理領域。
- ビジネス固有ドメイン
- システムドメイン
セキュリティや可用性などシステム品質を担保するためのシステムの機能領域。
アプリケーションタイプのドメインは、このうち、ビジネス固有ドメインになります。
例えば、アプリケーションタイプが顧客管理システムである場合、ドメインを、法人顧客管理と個人顧客管理に分割して、それぞれのマイクロサービスを法人顧客管理サービスと個人顧客管理サービスにするかなど、ドメインを詳細に分析します。
アプリケーションの開発
マイクロサービスのドメインが決まったら、ドメイン駆動設計で、各マイクロサービスを開発します。
ここでは、法人顧客管理サービスを例にして説明します。
-
CIM
- ドメインモデル(概念モデル)の作成
- 集約のライフサイクル分析
- 集約(概念モデル)の不変条件の定義
- 集約の操作(概念モデル)の定義
- ユースケース(業務機能レベル)の設計
- ドメインモデル(論理モデル)の作成
- 集約(論理モデル)の不変条件の定義
- 集約の操作(論理モデル)の定義
- ユースケース(システム機能レベル)の設計
- 画面構成の設計
- 画面遷移の設計
- アプリケーション連携モデルの設計
- ユースケースの実現性検証
- マイクロサービスの内部設計
- アプリケーションサービスの設計
- アダプタの設計
- マイクロサービスの仕様の定義
- フロントエンドアプリケーションの仕様の定義
PIM
PSM
ドメインモデル(概念モデル)の作成
下図は、UMLのクラス図で描いた法人顧客のドメインモデルです。
このドメインモデルを見ると、このビジネスでは、次のような観点で法人顧客を管理することがわかります。
- 法人番号を持つ法人をベースに法人顧客を管理する。
- 国税庁が管理する13桁の法人番号や、全世界の企業を一意に識別できる9桁のDUNSナンバーを法人番号の候補として考えることができます。
- 法人は、関連会社の関係もわかるようにする。
- 法人顧客ごとに複数の顧客担当者を定義できるようにする。
- 法人顧客ごとに複数、支払方法を設定できるようにする。
- 同じ法人顧客でも、契約先、出荷先、請求先など役割の違いが識別できるようにする。
- すでに取引がある顧客かまだ取引がない潜在的な顧客かなど顧客のステータスが識別できるようにする。
- 例えば、業種、規模、地域など様々な切り口で法人顧客を分類できるようにする。
本ドメインモデルは、業務の概念構造を表したもので、システムでどう実現されるかは考慮されていません。
なので、ドメインモデルを構成する各エンティティがリレーショナルデータベースのテーブルとして実現される場合もあれば、非構造化データの文書として実現される場合もあります。
集約のライフサイクル分析
下図は、法人顧客の概念データモデルの法人顧客エンティティのライフサイクルを分析したステートマシンです。
これをみると、次のことがわかります。
- 未登録の状態の顧客は、登録されることによって未取引の状態になり、取引開始によって取引中状態になる。
- また、取引停止によっって停止中状態になり、取引終了によって取引終了状態になる。
- それから、未登録の状態の顧客を登録することで、取引中にすることもできるし、取引中の顧客を取引終了にすることもできる。
- 逆に、取引停止中の顧客の取引を再開することもできるし、取引中の顧客の取引を取消すこともできる。
- また、未取引中と取引中の顧客のみ、顧客情報を変更することができる。
- なお、顧客情報を変更する一環として、顧客担当者と支払方法を設定することができる。
顧客担当者は、未取引中と取引中の顧客に対して設定できるが、支払方法は、取引中の顧客でないと設定することができない。
集約(概念モデル)の不変条件の定義
ここで、ドメインモデル(概念モデル)の不変条件を定義します。
不変条件とは、契約による設計で保証すべき条件の一つで、ドメインの集約がライフサイクルを通して保証すべき不変的な制約のことです。
つまり、集約がどのように操作されても変わらない条件になります。
集約(概念モデル)の不変条件は、PIMやPSMが変更されても不変です。
主な不変条件は次のようになります。
- データ品質保証条件
データマネジメントのデータ品質評価項目で管理されるデータ品質を保証するための条件です。
例えば、集約(エンティティ)の一意性や一貫性は、集約がどのように操作されても保持しなければならい条件になります。 - ライフサイクル一貫性保証条件
集約のライフサイクルの状態遷移が定義された通り正しく行われていることを保証するための条件になります。
これは、集約がどのように操作されても、定義された状態遷移に従った状態になっていなければならないので不変条件になります。 - 履歴整合性保証条件
過去の利用履歴状況との整合性を保証するための条件になります。
これは、集約がどのように操作されても、集約が持つ「過去の利用実績」と矛盾しないことを保証しなければならないので不変条件になります。
法人顧客管理の集約である法人顧客の不変条件は次のようになります。
- データ品質保証条件
-
データ一意性保証条約
データの一意性を保証する条件です。- 法人顧客の顧客番号に対する一意性制約
法人顧客の顧客番号は一意でなければならない - 顧客担当者に対する一意性制約
同一メールまたは電話番号の担当者が存在してはならない - 顧客分類に対する一意性制約
同一顧客に同じ顧客分類が存在してはならない
- 法人顧客の顧客番号に対する一意性制約
-
データ有効性保証条約
データが定義域に準拠していることを保証する条件です。
事前にデータドメインを定義しておく必要があります。- 法人顧客の顧客住所に対する有効性制約
法人顧客の顧客住所はデータドメインに定義された形式に準拠していなければならない。 - 顧客担当者の電話番号に対する有効性制約
顧客担当者の電話番号はデータドメインに定義された形式に準拠していなければならない。 - 顧客担当者の電子メールアドレスに対する有効性制約
顧客担当者の電子メールアドレスはデータドメインに定義された形式に準拠していなければならない。
- 法人顧客の顧客住所に対する有効性制約
-
データ一貫性保証条件
データの一貫性を保証する条件です。-
法人顧客に対する法人の存在制約
法人顧客には、それに対応する法人が存在する必要がある。 -
法人顧客に対する属性間の一貫性制約
法人番号が指定されていれば、DUNSナンバー・名前・住所は任意。
海外の企業の場合でも登録できるようにしたいので、法人番号が未指定の場合、DUNSナンバー・名前・住所が必須。 -
法人顧客に対する支払方法の存在制約
法人顧客が削除されたら、それに関連するすべての支払方法が削除される。
例えば、次のような実装で保証することができます。
@OneToMany(mappedBy = “customer”, cascade = CascadeType.ALL, orphanRemoval = true)
@JsonManagedReference
private ListpaymentMethods = new ArrayList(); -
法人顧客に対する顧客担当者の存在制約
法人顧客が削除されたら、それに関連するすべての顧客担当者が削除される。
例えば、次のような実装で保証することができます。
@OneToMany(mappedBy = “customer”, cascade = CascadeType.ALL, orphanRemoval = true)
@JsonManagedReference
private Listrepresentatives = new ArrayList();
-
法人顧客に対する法人の存在制約
-
データ一意性保証条約
- ライフサイクル一貫性保証条件
上記、法人顧客のライフサイクルから次のライフサイクル一貫性保証条件を定義することができます。- 未登録の場合、未取引から取引中にしか変更できない
- 未取引の場合、未取引、取引中にしか変更できない
- 取引中の場合、取引中、停止中、取引終了、未取引にしか変更できない
- 停止中 の場合、取引終了、取引中にしか変更できない
- 取引終了の場合、ステータスの変更はできない
また、次のようなライフサイクル一貫性保証条件を実現するようにします。
- 顧客情報(名前、住所、役割、ステータス)の変更は、未取引か取引中でなければできない
- 顧客担当者の設定は、未取引と取引中でなければできない
- 支払方法の設定は、取引中でなければできない
- 履歴整合性保証条件
次のような履歴整合性保証条件を実現するようにします。- 他のマイクロサービスの支払方法使用履歴がある場合、支払方法は無効にできない
- 他のマイクロサービスの顧客担当者使用履歴がある場合、顧客担当者は無効にできない
- 他のマイクロサービスの法人顧客使用履歴がある場合、法人顧客は無効にできない
集約の操作(概念モデル)の定義
ここでは、集約の操作(概念モデル)の定義し、事前条件と事後条件を定義します。
事前条件とは、操作の開始時に、操作を呼び出す側で保証すべき条件のことです。
事後条件とは、操作が終了時に、操作を実行する側が保証すべき条件のことです。
上述した不変条件は、事前条件として検証するか、事後条件として保証します。
なお、概念上、事前条件は本来は呼び出し側の責任(契約違反があれば呼び出し側が悪い)ですが、結合度を下げモジュール性を上げる目的で、ドメイン層のドメイン知識をサービス層に漏らしたくない場合、実装上、ドメイン層で操作が呼ばれたとき検証することもできます。
サービス層は、「ユースケースの意図」だけを表現 し、ドメイン層が不変条件を守る「番人」 になることができます。
さて、ドメインモデル(概念モデル)から、法人顧客には、次のような操作が必要であることがわかります。
- 法人顧客の妥当性検証
- 顧客名の変更
- 住所の変更
- 支払方法の追加
- 支払方法の無効化
- 顧客担当者の追加
- 顧客担当者の無効化
- 顧客ステータスの変更
- 顧客役割の変更
- 顧客の分類
それぞれの操作における事前条件と事後条件を定義します。
- 法人顧客の妥当性検証
- 事前条件
なし。 - 事後条件
法人番号が未指定の場合、DUNSナンバー・名前・住所が設定されていること。
上記、法人顧客に対する属性間の一貫性制約の検証になります。
- 事前条件
- 顧客名の変更
- 事前条件
顧客ステータスが未取引か取引中であること。
上記、ライフサイクル一貫性保証条件の検証になります。 - 事後条件
顧客名が変更されること。
- 事前条件
- 住所の変更
- 事前条件
- 顧客ステータスが未取引か取引中であること。
上記、ライフサイクル一貫性保証条件の検証になります。 - 住所が正しい形式で設定されていること。
上記、法人顧客の顧客住所に対する有効性制約の検証になります。
- 顧客ステータスが未取引か取引中であること。
- 事後条件
住所が変更されること。
- 事前条件
- 支払方法の追加
- 事前条件
- 顧客ステータスが取引中であること。
上記、ライフサイクル一貫性保証条件の検証になります。 - 例えば、同じ銀行コード+支店コード+口座番号の組み合わせなど、同じ支払方法(有効)が重複して存在しないこと
これは、ドメイン知識の漏洩を防ぐ目的でドメイン層で検証する事前条件になります。
- 顧客ステータスが取引中であること。
- 事後条件
- 同じ支払方法が無効なら有効に更新されること
- 新規なら追加されること
- 事前条件
- 支払方法の無効化
- 事前条件
-
- 顧客ステータスが取引中であること
上記、ライフサイクル一貫性保証条件の検証になります。 - 他のマイクロサービスの支払方法使用履歴がある場合、支払方法は無効にできない
上記、履歴整合性保証条件の検証になります。
また、これは、ドメイン知識の漏洩を防ぐ目的でドメイン層で検証する事前条件になります。
- 顧客ステータスが取引中であること
- 該当する支払方法が存在すること
データの完全性制約に対する検証になります。
-
- 事後条件
支払方法が無効になること
- 事前条件
- 顧客担当者の追加
- 事前条件
- 顧客ステータスが未取引か取引中であること
上記、ライフサイクル一貫性保証条件の検証になります。 - 同一メールまたは電話番号の担当者が存在しないこと
上記、顧客担当者に対する一意性制約の検証になります。 - 電話番号が正しい形式で設定されていること。
上記、顧客担当者の電話番号に対する有効性制約の検証になります。 - 電子メールアドレスが正しい形式で設定されていること。
上記、顧客担当者の電子メールアドレスに対する有効性制約の検証になります。
- 顧客ステータスが未取引か取引中であること
- 事後条件
顧客担当者が追加されること
- 事前条件
- 顧客担当者の無効化
- 事前条件
-
- 顧客ステータスが取引中であること
上記、ライフサイクル一貫性保証条件の検証になります。 - 他のマイクロサービスの顧客担当者使用履歴がある場合、顧客担当者は無効にできない
上記、履歴整合性保証条件の検証になります。
また、これは、ドメイン知識の漏洩を防ぐ目的でドメイン層で検証する事前条件になります。
- 顧客ステータスが取引中であること
- 該当する顧客担当者が存在すること
データの完全性制約に対する検証になります。
-
- 事後条件
顧客担当者が無効になること
- 事前条件
- 顧客ステータスの変更
- 事前条件
- 上記、ライフサイクル一貫性保証条件を満たしていること
- 他のマイクロサービスの法人顧客使用履歴がある場合、法人顧客は無効にできない
上記、履歴整合性保証条件の検証になります。
- 事後条件
顧客ステータスが変更されること
- 事前条件
- 顧客役割の変更
- 事前条件
顧客ステータスが未取引か取引中であること。
上記、ライフサイクル一貫性保証条件の検証になります。 - 事後条件
顧客役割が変更されること
- 事前条件
- 顧客の分類
- 事前条件
顧客分類が重複していないこと
顧客分類の一意性制約の検証になります。 - 事後条件
顧客が分類されること
- 事前条件
ユースケース(業務機能レベル)の設計
システム開発するときは、まず、ビジネスアーキテクチャのビジネスプロセスからユースケースを洗い出します。
下図は、産業機械を製造、販売する会社のバリューチェーンの例です。
このバリューチェーンを見ると、顧客管理の主なプロセスは、「顧客の獲得」、「顧客の活性化」、「顧客の維持」、「顧客の処分」であることがわかります。
これから、法人顧客管理の主なユースケースは次のようになると考えられます。
このユースケースは、ビジネスプロセスを構成するアクション、あるいは、顧客管理者というジョブのタスクと同義であり、システムでどう実現されるかは考慮されていません。
なので、このユースケースが業務パッケージの機能として実現される場合もあれば、スクラッチ開発のシステムの機能として実現される場合もあります。
さらに、上述した法人顧客のライフサイクルを考えると、 顧客の登録、顧客情報の変更、顧客の取引終了ユースケースだけでなく、業務上、次のようなユースケースがあることがわかります。
なお、ここでは、顧客担当者の設定ユースケースと支払方法を設定ユースケースは、顧客情報の変更ユースケースを拡張した形にしています。
さらに、顧客をさまざまな分析軸で分類することがあると考え、顧客情報の変更ユースケースの一環として、顧客の分類ユースケースを追加しています。
ドメインモデル(論理モデル)の作成
ドメイン駆動設計の考えか方を適用して、CIMの、法人顧客の概念レベルのドメインモデルを、PIMの論理レベルのドメインモデルに展開すると下図のようになります。
まず、ドメイン駆動設計の考えか方を適用して、概念レベルのドメインモデルを構成しているエンティティが、集約なのか、エンティティなのか、値オブジェクトなのか、列挙型なのか識別されていることがわかります。
また、住所や電話番号、電子メールなど、これまでエンティティの属性として定義されていた要素が列挙型として抽出されていることもわかります。
このPIMの論理レベルのドメインモデルは、マイクロサービスのドメインオブジェクトとして実装されます。
また、フロントエンドアプリケーションを設計するときは、各エンティティの属性のうち画面で設定すべきものが、漏れなく、画面の項目として定義されている必要があります。
集約(論理モデル)の不変条件の定義
上記、集約(概念モデル)の不変条件を集約(論理モデル)の不変条件に展開します。
- データ品質保証条件
-
データ一意性保証条約
データの一意性を保証する条件です。- 法人顧客の顧客IDに対する一意性制約
法人顧客の顧客IDは一意でなければならない - 顧客担当者に対する一意性制約
同一メールまたは電話番号の担当者が存在してはならない - 顧客分類に対する一意性制約
同一顧客に同じ顧客分類基準値が存在してはならない
- 法人顧客の顧客IDに対する一意性制約
-
データ有効性保証条約
データが定義域に準拠していることを保証する条件です。
事前にデータドメインを定義しておく必要があります。- 法人顧客の顧客住所に対する有効性制約
法人顧客の顧客住所はデータドメインに定義された形式に準拠していなければならない。 - 顧客担当者の電話番号に対する有効性制約
顧客担当者の電話番号はデータドメインに定義された形式に準拠していなければならない。 - 顧客担当者の電子メールアドレスに対する有効性制約
顧客担当者の電子メールアドレスはデータドメインに定義された形式に準拠していなければならない。
- 法人顧客の顧客住所に対する有効性制約
-
データ一貫性保証条件
データの一貫性を保証する条件です。-
法人顧客に対する法人の存在制約
法人顧客には、それに対応する法人が存在する必要がある。 -
法人顧客に対する属性間の一貫性制約
法人番号が指定されていれば、DUNSナンバー・名前・住所は任意。
海外の企業の場合でも登録できるようにしたいので、法人番号が未指定の場合、DUNSナンバー・名前・住所が必須。 -
法人顧客に対する支払方法の存在制約
法人顧客が削除されたら、それに関連するすべての支払方法が削除される。
例えば、次のような実装で保証することができます。
@OneToMany(mappedBy = “customer”, cascade = CascadeType.ALL, orphanRemoval = true)
@JsonManagedReference
private ListpaymentMethods = new ArrayList(); -
法人顧客に対する顧客担当者の存在制約
法人顧客が削除されたら、それに関連するすべての顧客担当者が削除される。
例えば、次のような実装で保証することができます。
@OneToMany(mappedBy = “customer”, cascade = CascadeType.ALL, orphanRemoval = true)
@JsonManagedReference
private Listrepresentatives = new ArrayList();
-
法人顧客に対する法人の存在制約
-
データ一意性保証条約
- ライフサイクル一貫性保証条件
上記、法人顧客のライフサイクルから次のライフサイクル一貫性保証条件を定義することができます。- 未登録の場合、未取引(PROSPECT)から取引中(ACTIVE)にしか変更できない
- 未取引の場合、未取引(PROSPECT)、取引中(ACTIVE)にしか変更できない
- 取引中の場合、取引中(ACTIVE)、停止中(INACTIVE)、取引終了(CLOSED)、未取引(PROSPECT)にしか変更できない
- 停止中 の場合、取引終了(CLOSED)、取引中(ACTIVE)にしか変更できない
- 取引終了の場合、ステータスの変更はできない
また、次のようなライフサイクル一貫性保証条件を実現するようにします。
- 顧客情報(名前、住所、役割、ステータス)の変更は、未取引か取引中でなければできない
- 顧客担当者の設定は、未取引(PROSPECT)と取引中(ACTIVE)でなければできない
- 支払方法の設定は、取引中(ACTIVE)でなければできない
- 履歴整合性保証条件
次のような履歴整合性保証条件を実現するようにします。- 他のマイクロサービスの支払方法使用履歴がある場合、支払方法は無効(INACTIVE)にできない
- 他のマイクロサービスの顧客担当者使用履歴がある場合、顧客担当者は無効(INACTIVE)にできない
- 他のマイクロサービスの法人顧客使用履歴がある場合、法人顧客は無効(INACTIVE)にできない
集約の操作(論理モデル)の定義
集約の操作(概念モデル)の定義を集約の操作(論理モデル)の定義に展開します。
- 法人顧客の妥当性検証
- 事前条件
なし。 - 事後条件
法人番号が未指定の場合、DUNSナンバー・名前・住所が設定されていること。
上記、法人顧客に対する属性間の一貫性制約の検証になります。
- 事前条件
- 顧客名の変更
- 事前条件
顧客ステータスが未取引(PROSPECT)か取引中(ACTIVE)であること。
上記、ライフサイクル一貫性保証条件の検証になります。 - 事後条件
法人顧客名が変更されること。
- 事前条件
- 住所の変更
- 事前条件
- 顧客ステータスが未取引(PROSPECT)か取引中(ACTIVE)であること。
上記、ライフサイクル一貫性保証条件の検証になります。 - 住所が正しい形式で設定されていること。
法人顧客の住所を値オブジェクトにすることで対応する。
上記、法人顧客の顧客住所に対する有効性制約の検証になります。
- 顧客ステータスが未取引(PROSPECT)か取引中(ACTIVE)であること。
- 事後条件
住所が変更されること。
- 事前条件
- 支払方法の追加
- 事前条件
- 顧客ステータスが取引中(ACTIVE)であること。
上記、ライフサイクル一貫性保証条件の検証になります。 - 例えば、同じ銀行コード+支店コード+口座番号の組み合わせなど、同じ支払方法(有効)が重複して存在しないこと
これは、ドメイン知識の漏洩を防ぐ目的でドメイン層で検証する事前条件になります。
- 顧客ステータスが取引中(ACTIVE)であること。
- 事後条件
- 同じ支払方法が無効(INACTIVE)なら有効(ACTIVE)に更新されること
- 新規なら追加されること
- 事前条件
- 支払方法の無効化
- 事前条件
-
- 顧客ステータスが取引中(ACTIVE)であること
上記、ライフサイクル一貫性保証条件の検証になります。 - 他のマイクロサービスの支払方法使用履歴がある場合、支払方法は無効にできない
上記、履歴整合性保証条件の検証になります。
また、これは、ドメイン知識の漏洩を防ぐ目的でドメイン層で検証する事前条件になります。
- 顧客ステータスが取引中(ACTIVE)であること
- 該当する支払方法が存在すること
データの完全性制約に対する検証になります。
-
- 事後条件
支払方法が無効(INACTIVE)になること
- 事前条件
- 顧客担当者の追加
- 事前条件
- 顧客ステータスが未取引か取引中であること
上記、ライフサイクル一貫性保証条件の検証になります。 - 同一メールまたは電話番号の担当者が存在しないこと
上記、顧客担当者に対する一意性制約の検証になります。 - 電話番号が正しい形式で設定されていること。
顧客担当者の電話番号を値オブジェクトにすることで対応する。
上記、顧客担当者の電話番号に対する有効性制約の検証になります。 - 電子メールアドレスが正しい形式で設定されていること。
顧客担当者の電子メールアドレスを値オブジェクトにすることで対応する。
上記、顧客担当者の電子メールアドレスに対する有効性制約の検証になります。
- 顧客ステータスが未取引か取引中であること
- 事後条件
顧客担当者が追加されること
- 事前条件
- 顧客担当者の無効化
- 事前条件
-
- 顧客ステータスが取引中(ACTIVE)であること
上記、ライフサイクル一貫性保証条件の検証になります。 - 他のマイクロサービスの顧客担当者使用履歴がある場合、顧客担当者は無効にできない
上記、履歴整合性保証条件の検証になります。
また、これは、ドメイン知識の漏洩を防ぐ目的でドメイン層で検証する事前条件になります。
- 顧客ステータスが取引中(ACTIVE)であること
- 該当する顧客担当者が存在すること
データの完全性制約に対する検証になります。
-
- 事後条件
顧客担当者が無効(INACTIVE)になること
- 事前条件
- 顧客ステータスの変更
- 事前条件
- 上記、ライフサイクル一貫性保証条件を満たしていること
- 他のマイクロサービスの法人顧客使用履歴がある場合、法人顧客は無効(INACTIVE)にできない
上記、履歴整合性保証条件の検証になります。
- 事後条件
顧客ステータスが変更されること
- 事前条件
- 顧客役割の変更
- 事前条件
顧客ステータスが未取引(PROSPECT)か取引中(ACTIVE)であること。
上記、ライフサイクル一貫性保証条件の検証になります。 - 事後条件
顧客役割が変更されること
- 事前条件
- 顧客の分類
- 事前条件
顧客分類基準値が重複していないこと
顧客分類の一意性制約の検証になります。 - 事後条件
顧客分類基準値が追加されること
- 事前条件
ユースケース(システム機能レベル)の設計
これまでは、業務的視点でユースケースを考えてきましたが、ここで、「システムのユーザーがシステムをどう使うか」という視点でユースケースを分析し、さらに洗練させてみましょう。
次の図は、システムの視点でユースケースを洗練したモデルです。
これを見ると、顧客情報の照会ユースケースが起点となって、顧客情報の変更ユースケース、顧客担当者の設定ユースケース、顧客の分類ユースケース、支払方法を設定ユースケースが拡張されていることがわかります。
また、顧客との取引開始や取引停止など顧客の状態変化をともなうものは、顧客のステータスの変更と考え、顧客取引の変更ユースケースとして汎化し、顧客情報の変更ユースケースに包含させています。
それから、顧客情報の照会ユースケースと顧客の登録ユースケースは、ともに、顧客一覧の照会ユースケースから派生することがわかります。
画面構成の設計
下図は、法人顧客管理の画面構成になります。
画面構成を設計するときは、個々の画面の画面項目も定義します。
画面項目を定義するときは、論理レベルのドメインモデルを構成する各エンティティの属性で表示されるものが、漏れなく、画面の項目として定義されている必要があります。
画面遷移の設計
次の図は、UMLのステートマシン図で描いた「顧客の登録」ユースケースの画面遷移です。
その際、例えば、
顧客登録したときは、API「cregisterCustomer」を呼び、登録後、API「searchCustomers」を呼ぶ。
キャンセルしたときは、API「searchCustomers」を呼ぶ。
などのように、各画面遷移ごとに関連するAPIを定義します。
画面遷移が設計できれば、フロントエンドアプリケーションのPSMの設計および実装を開始することができます。
マイクロサービス側では、それを参考にして、以下のアプリケーション連携モデルの設計、ユースケースの実現性検証を行います。
アプリケーション連携モデルの設計
ここでは、下図のようにフロントエンドアプリケーションとマイクロサービスの連携の流れを設計します。
これを見ると、次のことがわかります。
- 法人顧客管理サービスは、法人顧客を登録する際、法人情報を法人管理サービスに連携する。
- 法人顧客管理サービスは、外部の郵便番号データ配信サービスを利用して住所情報を検証する。
- 法人管理サービスは、国税庁の法人番号システムから法人情報を取得する。
- 法人顧客管理サービスは、ActiveMQと非同期メッセージングを行う。
ここでは、非同期メッセージングによって次の送受信を行うことを想定しています。- 支払方法が使用されたというメッセージの受信
- 顧客担当者が使用されたというメッセージの受信
- 法人顧客が使用されたというメッセージの受信
- 支払方法が追加されたというメッセージの送信
- 支払方法が無効化されたというメッセージの送信
- 支払方法が有効化されたというメッセージの送信
- 顧客担当者が追加されたというメッセージの送信
- 顧客担当者が無効化されたというメッセージの送信
- 顧客担当者が有効化されたというメッセージの送信
- 法人顧客が変更されたというメッセージの送信
ユースケースの実現性検証
次に、下図のようにフロントエンドアプリケーションとマイクロサービスの連携によって各ユースケースが実現できるか検証します。
これは、UMLのシーケンス図でユースケースの実現性を検証した例です。
各マイクロサービスに対するメッセージが、そのマイクロサービスが実現すべきAPIになります。
これは、上記アプリケーション連携モデルの構成で、「顧客の登録」ユースケースが実現できるか検証している例です。
これを見ると、次のことがわかります。
- 法人顧客管理サービスは、法人顧客を登録する際、法人情報を法人管理サービスに登録する。
- その際、法人管理サービスは、国税庁の法人番号システムから法人情報を取得して法人情報を検証する。
- また、法人顧客管理サービスは、外部の郵便番号データ配信サービスを利用して住所情報を検証する。
マイクロサービスの内部設計
ここでは、ここでは、PIMのユースケース、および、ユースケースの実現性検証の結果を受けて、それをマイクロサービス内部でどう実現するか設計します。
マイクロサービスのIT基盤は構築されていることを前提とします。
パッケージの設計
まず、パッケージの構成を設計します。
ここでは、ヘキサゴナルアーキテクチャを適用するため、次のようなパッケージ構成にします。
- ベースパッケージ
com.x.y - アプリケーション層
com.x.y.application.service
アプリケーションサービス(ユースケースレベルの処理)を格納。 - ドメイン層
com.x.y.domain.model
エンティティ、値オブジェクト、ファクトリなど、ドメインモデルを格納。
com.x.y.domain.service
ドメインサービス(エンティティに属さないビジネスルール)を格納。 - アダプター層(外部接続)
com.x.y.adapter.db.rdb
RDB用のリポジトリ(Spring Data JPA)を格納。
com.x.y.adapter.db.nosql
NoSQL用のリポジトリを格納(必要な場合のみ)。
com.x.y.adapter.messaging
メッセージングに関するクラス(Event、Sender、Receiver)を格納。
com.x.y.adapter.rest
REST API 関連のクラス(RestController、RestTemplateなど)を格納。 - createCustomer
まず、集約である法人顧客を生成します。 - isValidCorporateCustomer
次に、法人顧客コントローラから受け取った法人顧客DTOの妥当性を検証します。
これは、上記、不変条件の法人顧客に対する属性間の一貫性制約の検証になります。 - registerCorporation
法人顧客DTOに法人番号がセットされている場合、法人顧客サービスに法人の登録を依頼します。
法人顧客サービスでは、国税庁の法人番号システムから法人番号の法人情報を取得し、法人情報がデータベースにない場合は保存し、ある場合は更新します。 - validateAddress
法人顧客DTOに法人の住所がセットされている場合、法人顧客アプリケーションサービスは、郵便番号データ配信サービスを活用して住所を検証します。 - saveCorporation
次に、法人を法人リポジトリに保存します。 - saveCustomer
最後に、法人顧客を法人顧客リポジトリに保存します。 - 事前条件
呼び出し側が守るべき前提。
これを満たさない場合は即座に例外(BusinessException / IllegalArgumentException など)を投げる。- 必須入力チェック
- customerName, address, corporateNumber, dunsNumber のいずれかが、顧客を識別できる状態で入力されていること
- 法人番号がある場合 → DUNS・名前・住所は任意
- 法人番号がない場合 → DUNS番号、名前、住所が必須
- 住所形式のチェック
address が指定されている場合、郵便番号や都道府県・市区町村・番地などが欠落していないこと(= isEmptyAddress(address) == false なら AddressValidationService がOKを返すこと) - 重複禁止
同じ法人番号、同じ顧客名、同じ住所の顧客が既に存在していないこと - 外部API利用時の前提
法人番号が指定されている場合、国税庁API(corporateRestAdapter.registerCorporation)が利用可能な状態であること
- 必須入力チェック
- 事後条件
メソッド実行後に必ず保証されるべき状態。- 顧客が永続化されていること
- tempCustomer が customerRepository.save() により保存され、永続化されていること
- 保存後に CorporateCustomer がDB上に存在すること
- 法人情報の確定
- 法人番号が指定された場合 → 国税庁APIのレスポンスに基づいて Corporate が確定し、DBに存在していること
- 法人番号がない場合 → 入力された値に基づいて Corporate が保存されていること
- 顧客の整合性
- CorporateCustomer が必ず 有効な法人(confirmedCorporate) と紐付いていること
- CorporateCustomer が確定した住所と顧客名を保持していること
- CorporateCustomer の不変条件(isValidCorporateCustomer())を満たしていること
- 一意性の保証
登録された CorporateCustomer は、同じ法人番号・同じ顧客名・同じ住所を持つ既存顧客と重複していないこと - 返却値の保証
戻り値の CorporateCustomer はDBに保存済みであり、ID(主キー)が発行済みであること
- 顧客が永続化されていること
- 支払方法が使用されたというメッセージの受信
- 顧客担当者が使用されたというメッセージの受信
- 法人顧客が使用されたというメッセージの受信
- 支払方法が追加されたというメッセージの送信
- 支払方法が無効化されたというメッセージの送信
- 支払方法が有効化されたというメッセージの送信
- 顧客担当者が追加されたというメッセージの送信
- 顧客担当者が無効化されたというメッセージの送信
- 顧客担当者が有効化されたというメッセージの送信
- 法人顧客が変更されたというメッセージの送信
クラス構造の設計
次に、法人管理サービスのクラス構造を設計します。
クラス構造の検証
最後に、設計されたクラス構造でユースケースが実現できるか検証します。
次の図は、上記、「顧客の登録」ユースケースのresiterCustomerAPIの実現性を検証した例です。
法人顧客アプリケーションサービスのresiterCustomerは次のような流れになります。
アプリケーションサービスの設計
ここでは、マイクロサービスの内部設計の結果を受けて、アプリケーションサービスのアプリケーションロジックを定義します。
ここでは、サービス層のアプリケーションロジックとドメイン層のドメインロジックを分離しています。
ドメインロジックは、上記で定義した集約の事前条件、事後条件、不変条件で、ドメイン固有のビジネスロジックになります。
それに対し、アプリケーションロジックは、ユースケースを制御するためのシステムロジックです。
次の表は、ドメインロジックとアプリケーションロジックの違いを、目的、主な責務、定義する内容、主な構成要素、外部依存、例という観点で整理したものです。
さて、アプリケーションサービスですが、集約である法人顧客単位にアプリケーションサービスを作成し、ユースケース単位にメソッドを定義します。
ここでは、クラス構造の検証にある「resiterCustomer」メソッドのアプリケーションロジックを、事前条件、事後条件に分けて定義します。
※アプリケーションサービスは、ドメインオブジェクトではないので不変条件はありません。
アダプタの設計
RESTコントローラ
RESTコントローラですが、集約である法人顧客単位にコントローラを作成し、ユースケース単位にメソッドを定義します。
非同期メッセージング
上述した非同期メッセージングによる次の送受信を設計します。
マイクロサービスの仕様の定義
詳細は、生成AIと創るマイクロサービスを参照してください。
フロントエンドアプリケーションの仕様の定義
詳細は、生成AIと創るフロントエンドアプリケーションを参照してください。