楽水

人々の創造が自由に表現できる舞台づくり

DX アプリケーション

モデルドリブン開発で創るマイクロサービス

投稿日:


ここでは、モデルドリブン開発でマイクロサービスを開発する手順について説明します。
ここでいうモデルドリブン開発とは、MDAの考え方で、次の3つのモデルを創れば、PSMから自動的にソースコードを生成するという開発方法のことです。

  • CIM(Computation Independent Model)
    計算機処理に依存しないモデル。
  • PIM(Platform Independent Model)
    IT基盤に依存しないモデル。
  • PSM(Platform Specific Model)
    IT基盤に特化したモデル。

MDAは、システムを開発するとき、開発対象をCIM、PIM、PSMに分けて設計することで、変わりにくい本質の部分と、変わりやすい現象の部分を切り分けて考えることができ、環境の変化に合わせて変えるべき部分だけ変えることができるので、変化に強い堅牢なシステムを創ることができるという思想です。
しかし、MDAが提唱された2000年代初頭の技術では、PSMから自動的にソースコードを生成することが難しく、モデルドリブン開発は絵に描いた餅で終わっていました。
ところが、最近の生成AIの目覚ましい進歩によって、PSMを生成AIが理解できるアプリケーション仕様として定義することでPSMから自動的にソースコードを生成することができるようになりました。



ここでは、MDAに、次の考え方を適用して、どのようにモデルドリブン開発を進めるのか解説します。

  1. ベースとなる技術
  2. アプリケーションアーキテクチャの設計
  3. アプリケーションの開発

次の動画も参考にしてください。
動画「生成AIによるモデルドリブン開発」

ベースとなる技術

ここでは、モデルドリブン開発のベースとなる、次の技術について簡単に解説します。

ドメイン駆動設計

ドメイン駆動設計とは、ドメイン(開発対象の業務領域)を中心に据えてシステムを設計・開発する手法です。
これによって、業務の本質を表すドメインの構造や振る舞い(業務のルールや機能)を正確に実現でき、再利用性・拡張性が高く、変化に強く堅牢なシステムを構築することができます。

ドメイン駆動設計の階層

ドメイン駆動設計では、ドメイン層とアプリケーション層を設け、業務領域の知識(ドメイン知識)を、それをどのように活用するかというアプリケーションの処理から分離することで、ドメイン層の再利用性や保守性を高めています。
アプリケーション層のビジネスロジックは、アプリケーションごとのユースケースに応じて変化しますが、ドメイン層に定義される業務の本質的なビジネスロジック(ビジネスルールや制約)は、アプリケーションに依存せず不変です。

ドメイン駆動設計の構成

ドメイン駆動設計の構造ですが、ドメイン層はドメインオブジェクト(集約、エンティティ、値オブジェクト)を中心に、ドメインサービス、ドメインイベント、リポジトリ、ファクトリなどで構成され、アプリケーション層はアプリケーションサービスによってユースケースを実現します。
それぞれ見ていきましょう。

  • ドメイン層
    • ドメインオブジェクト
      ドメインとは、開発対象となる業務領域のことです。
      ドメインオブジェクトとは、ドメインを構成する業務要素を表すオブジェクトで、集約、エンティティ、値オブジェクトから構成されます。
      ドメインオブジェクトのドメイン知識がアプリケーション層にが流出しないように注意します。
      アプリケーション層のアプリケーションサービスがドメイン知識を持つと、アプリケーションサービスとドメインオブジェクトの結合度が上がり、ドメインオブジェクトのモジュール性、再利用性が下がります。

      • エンティティ
        同一性(IDを持つ)と連続性(状態が変化する:mutable)を持つオブジェクト。
        参照オブジェクトともいいます。
      • 値オブジェクト
        事物の性質を表現するもので、等価性(同じオブジェクトは等価である)と不変性(状態を変えない:immutable)を持つオブジェクトのことです。
      • 集約
        ドメインオブジェクトのライフサイクルの単位のことです。
        集約の中核を担うエンティティのことを集約ルートといいます。

      ドメインオブジェクトをモデルとして表したものをドメインモデルといいますが、次の図は、UMLのクラス図で記述した法人顧客管理ドメインのドメインモデルです。

      これを見ると、中心に集約ルートである法人顧客があり、その周辺を、法人顧客に関係する他のエンティティや値オブジェクトが取り巻いていることがわかります。

    • ドメインサービス
      ドメインに存在する概念の中には、1つの機能が単体で存在していて、エンティティや値オブジェクトなどのクラスのメソッドに属さない場合があります。
      そのような場合、その機能をドメインサービスという状態を持たない(statelessな)オブジェクトとして分類します。
      例えば、注文や契約に基づいて請求金額を計算する処理を料金計算サービス(BillingService )というドメインサービスとして抽出することができます。
      料金計算は「契約」や「料金プラン」「利用実績」など複数のエンティティをまたぐため、どれか1つのエンティティに属させるのは不自然です。
      public class BillingService {
      public Money calculateCharge(Contract contract, Usage usage) {
      // 契約条件・利用量に応じて料金を算出
      }
      }
      このような、複数のオブジェクトに跨る振舞をドメインサービスとして抽出することができます。
    • ドメインイベント
      ドメインイベントとは、ドメイン内で起きた重要な出来事(業務上の事実)」を表すオブジェクトのことです。
      ドメインイベントは、マイクロサービス間、あるいは、アプリケーション間の非同期メッセージングや、イベントソーシングのとき使います。


      マイクロサービス間の非同期メッセージングの例


      イベントソーシングの例

    • リポジトリ
      集約の生存期間中、それを一時的にデータベース上に保管・問い合わせするための役割がリポジトリです。
      リポジトリは、DAO(Data Access Object)のようにデータをアクセスする機能ではなく、オブジェクトを保管する機能を抽象化したもので、メモリ上にあるコレクションを扱うように操作することができます。
    • ファクトリ
      集約の複雑な生成過程をカプセル化する役割がファクトリです。
  • アプリケーション層
    アプリケーションサービス
    アプリケーションサービスは、ドメインオブジェクトの直接のクライアントで、ユースケースのシナリオを実現するためにドメインオブジェクトのメソッドを調整するだけの役割を担います。
    ファクトリを介して、ドメインオブジェクトを生成し、リポジトリを介して、ドメインオブジェクトを保管、取得、削除するなどドメインオブジェクトのライフサイクルを管理するのはアプリケーションサービスの役割です。
    また、アプリケーションサービスは、各種アダプタを介して、外部要素と連携して、ユースケースを実現します。

ヘキサゴナルアーキテクチャ

ヘキサゴナルアーキテクチャとは、アリスター・コーバーン(Alistair Cockburn)によって提唱されたアプリケーションアーキテクチャで、アプリケーションの中心にドメインを置き、その周囲を「ポート(Port)」と「アダプタ(Adapter)」で囲むことで、外部システム(UI・DB・API など)との依存度を下げるアーキテクチャのことです。



ヘキサゴナルアーキテクチャは、ドメイン駆動設計のドメイン層とアプリケーション層の周りをアダプタ層で囲み、外部システム(UI・DB・API など)の脱着を柔軟にできるようにすることで、アプリケーションシステムを変化に強く堅牢なものにします。
なお、ヘキサゴナルアーキテクチャの構造を反映したパッケージ構造は次のようになります。

  • ベースパッケージ
    com.x.y
  • アプリケーション層
    com.x.y.application.service
    アプリケーションサービス(ユースケースレベルの処理)を格納。
    アプリケーション層では、依存性逆転の法則(DIP)を適用するために、ユースケース実現のための外部サービスのインフラ実装に対する抽象(インターフェース)を定義し、その具象実装はアダプタ層で提供します。これにより、インフラに依存しない柔軟でテストしやすい設計が実現します。
    また、コマンド・クエリ責務分離(CQRS)パターンを適用することで、コマンド処理(状態変更)とクエリ処理(読み取り)を責務ごとに分離することが可能です。
    その場合、以下のようにパッケージを分けて構成します。
    com.x.y.application.command.service
    com.x.y.application.query.service
  • ドメイン層
    • com.x.y.domain.model
      エンティティ、値オブジェクトを格納。
    • com.x.y.domain.service
      ドメインサービスを格納。
    • com.x.y.domain.event
      ドメインイベントを格納。
    • com.x.y.domain.repository
      リポジトリのインターフェースを格納。
      ドメイン層では、依存性逆転の法則(DIP)を適用するために、リポジトリのインフラ実装に対する抽象(インターフェース)を定義し、その具象実装はアダプタ層で提供します。これにより、インフラに依存しない柔軟でテストしやすい設計が実現します。
    • com.x.y.domain.factory
      ファクトリを格納。
  • アダプタ層

    • com.x.y.adapter.db.rdb
      RDB用のリポジトリ(Spring Data JPA)を格納。
      com.x.y.domain.repositoryに格納さえたリポジトリインターフェースの実装になります。
    • com.x.y.adapter.db.nosql
      NoSQL用のリポジトリを格納(必要な場合のみ)。
      com.x.y.domain.repositoryに格納さえたリポジトリインターフェースの実装になります。
    • com.x.y.adapter.messaging
      メッセージングに関するクラス(Event、Sender、Receiver)を格納。
    • com.x.y.adapter.rest
      REST API 関連のクラス(RestController、RestTemplateなど)を格納。
  • 共通構成
    com.x.y.config
    アプリケーション全体に関わる設定クラスを格納します。以下のような構成を含めます。
    SecurityConfig:CORSや認証フィルターの設定。
    OpenApiConfig:OpenAPI 3 に基づくAPIドキュメントの設定。
    AuditingConfig:作成日時・更新日時を自動記録するJPA監査設定。
  • 例外処理
    com.x.y.exception
    共通の例外クラスや例外ハンドリングクラスを格納します。以下のような構成を含めます。
    BusinessException:業務例外(ビジネスルール違反)。
    DomainException:ドメイン層での不整合やバリデーションエラー。
    GlobalExceptionHandler:@ControllerAdvice による全体的な例外ハンドリング。

契約による設計

さて、ヘキサゴナルアーキテクチャでは、ドメイン層とアプリケーション層がアプリケーションのビジネスロジックを実現し、アダプタ層は外部世界(UI、DB、メッセージング、外部APIなど)との入出力変換の役割を果たします。
このように、ドメイン層とアプリケーション層がアプリケーションではビジネスロジックを実現しますが、ここでは、それぞれのビジネスロジックを、ドメインロジックとアプリケーションロジックと分けて考えます。
ドメインロジックは、ドメイン(業務領域)の業務ルールや機能を表し、アプリケーションロジックは、アプリケーションのユースケースを実現するための処理の流れ(オーケストレーション)を表します。
ここでは、ドメインロジックとアプリケーションロジックを、契約による設計の事前条件、事後条件、不変条件によって整理します。


ドメインロジック

ここでは、ドメインオブジェクトが実現すべくドメインロジックを、契約による設計の、事前条件、事後条件、不変条件という観点で説明します。

  • 事前条件
    ドメインオブジェクトの各メソッドを呼び出す側(アプリケーションサービス)が満たすべき条件のことです。
  • 事後条件
    ドメインオブジェクトが各メソッドを実行した後、満たすべき条件のことです。
  • 不変条件
    ドメインオブジェクト全体が常に満たすべき条件のことです。
    これは、集約のメソッドを通じて、特定の集約インスタンスの整合性を保持するための条件になります。
    例えば、注意番号には必ず値が設定されている必要があるなど、ある特定の注文オブジェクトに閉じた整合性の保証は、ドメインロジックの不変条件になります。
    主なドメインオブジェクトの不変条件は次のようになります。

    • データ品質保証条件
      データマネジメントのデータ品質評価項目で管理されるデータ品質を保証するための条件です。
      例えば、集約(エンティティ)が関連するエンティティの一意性や集約のデータの完全性、有効性は、集約がどのように操作されても保持しなければならい条件になります。
    • ライフサイクル一貫性保証条件
      集約のライフサイクルの状態遷移が定義された通り正しく行われていることを保証するための条件になります。
      これは、集約がどのように操作されても、定義された状態遷移に従った状態になっていなければならないので不変条件になります。

アプリケーションロジック

ここでは、アプリケーションサービスが実現すべくアプリケーションロジックを、契約による設計の、事前条件、事後条件、不変条件という観点で説明します。

  • 事前条件
    アプリケーションサービスの各メソッドを呼び出す側(アダプタ)が満たすべき条件のことです。
  • 事後条件
    アプリケーションサービスが各メソッドを実行した後、満たすべき条件のことです。
  • 不変条件
    アプリケーションシステム全体が常に満たすべき条件のことです。
    ユースケース(アプリケーションサービスのメソッド)を通じて、複数の集約種類間のトランザクション整合性や、複数の集約インスタンス全体のトランザクション整合性を保持するための条件になります。
    例えば、注文の状態と在庫の状態の間の整合性の保証、注文番号は一意でなければならないなど、リポジトリを介したすべての注文オブジェクト間の整合性の保証はアプリケーションロジックの不変条件になります。
    主なアプリケーションサービスの不変条件は次のようになります。

    • データ品質保証条件
      データマネジメントのデータ品質評価項目で管理されるデータ品質を保証するための条件です。
      例えば、集約(エンティティ)の一意性や、集約のデータの一貫性は、集約がどのように操作されても保持しなければならい条件になります。
    • トランザクション整合性保証条件
      メソッドのトランザクション整合性制約
      アプリケーションサービスを構成する各メソッドで、トランザクション整合性を保持する必要がある。
      サービス間のトランザクション整合性制約
      複数のアプリケーションサービス間で連携処理を行う場合(例:PersonService → CorporateService など)、サービス間のトランザクション整合性を保持する必要がある。
      同一トランザクションで整合性を保証できない場合(マイクロサービス間通信など)、最終的整合性(eventual consistency) を確保する設計(イベント駆動/補償トランザクション等)を採用しなければならない。
    • 履歴整合性保証条件
      過去の利用履歴状況との整合性を保証するための条件になります。
      これは、集約がどのように操作されても、集約が持つ「過去の利用実績」と矛盾しないことを保証しなければならないので不変条件になります。

アプリケーションアーキテクチャの設計

まず、次の手順で、マイクロサービスの単位を決めます。

  1. アプリケーションポートフォリオの設計
  2. アプリケーション戦略の策定
  3. ドメインの分析

アプリケーションポートフォリオの設計

まず、企業全体のアプリケーションタイプを洗い出します。
アプリケーションタイプは、概念レベルの本質的な(製品や技術に左右されない)アプリケーションの型で、ビジネスアーキテクチャの一つ、ジョブ(職務)を支援する役割を表します。
なので、会社のジョブと一対一の関係でアプリケーションタイプを洗い出します。
詳細は、アプリケーションポートフォリオの設計を参照してください。

アプリケーション戦略の策定

次に、アプリケーションポートフォリオを構成するアプリケーションタイプのどれにマイクロサービスを適用するか戦略を策定します。
詳細は、アプリケーション戦略の策定を参照してください。
それから、基幹システムをマイクロサービス化する場合は、ストラングラーアプリケーションパターンを適用して、具体的にマイクロサービス化するアクションプランを策定します。

ドメインの分析

最後に、マイクロサービスを適用するアプリケーションタイプのドメイン(開発対象の領域)を明確にします。

ドメインは次のように分類することができます。

  • ビジネスドメイン
    業務の領域。

    • ビジネス固有ドメイン
      「販売管理」、「購買管理」など業務固有の活動領域。
    • ビジネス共通ドメイン
      「単位」など業務に共通した管理領域。
  • システムドメイン
    セキュリティや可用性などシステム品質を担保するためのシステムの機能領域。

アプリケーションタイプのドメインは、このうち、ビジネス固有ドメインになります。
例えば、アプリケーションタイプが顧客管理システムである場合、ドメインを、法人顧客管理と個人顧客管理に分割して、それぞれのマイクロサービスを法人顧客管理サービスと個人顧客管理サービスにするかなど、ドメインを詳細に分析します。

アプリケーションの開発

ここでは、次の手順でアプリケーションシステム(マイクロサービス、および、フロントエンドアプリケーション)を開発する方法について説明します。
ここでは、法人顧客管理サービスを例にして説明します。

    CIM

  1. ドメインモデル(概念モデル)の設計
  2. 集約のライフサイクル分析
  3. ユースケース(業務機能レベル)の設計
  4. ドメインモデルの妥当性分析
  5. PIM

  6. ドメインモデル(論理モデル)の設計
  7. ユースケース(システム機能レベル)の設計
  8. 画面構成の設計
  9. 画面遷移の設計
  10. アプリケーション連携モデルの設計
  11. ユースケースの実現性検証
  12. マイクロサービス

  13. マイクロサービスの内部設計
  14. PSM
    マイクロサービス

  15. ドメインオブジェクトの不変条件の定義
  16. ドメインオブジェクトのメソッド(事前条件・事後条件)の定義
  17. アプリケーションサービスの不変条件の定義
  18. アプリケーションサービスのメソッド(事前条件・事後条件)の定義
  19. アダプタの設計
  20. マイクロサービスの仕様の定義
  21. フロントエンドアプリケーション

  22. アプリケーション仕様の定義

なお、このアプリケーション開発のプロセスは、フロントエンドアプリケーションとマイクロサービスの開発がふくまれており、ユースケースの実現性検証までが共通です。



ドメインモデル(概念モデル)の設計

下図は、UMLのクラス図で描いた法人顧客のドメインモデルです。

このドメインモデルを見ると、このビジネスでは、次のような観点で法人顧客を管理することがわかります。

  • 法人番号を持つ法人をベースに法人顧客を管理する。
  • 国税庁が管理する13桁の法人番号や、全世界の企業を一意に識別できる9桁のDUNSナンバーを法人番号の候補として考えることができます。
  • 法人は、関連会社の関係もわかるようにする。
  • 法人顧客ごとに複数の顧客担当者を定義できるようにする。
  • 法人顧客ごとに複数、支払方法を設定できるようにする。
  • 同じ法人顧客でも、契約先、出荷先、請求先など役割の違いが識別できるようにする。
  • すでに取引がある顧客かまだ取引がない潜在的な顧客かなど顧客のステータスが識別できるようにする。
  • 例えば、業種、規模、地域など様々な切り口で法人顧客を分類できるようにする。

本ドメインモデルは、業務の概念構造を表したもので、システムでどう実現されるかは考慮されていません。
なので、ドメインモデルを構成する各エンティティがリレーショナルデータベースのテーブルとして実現される場合もあれば、非構造化データの文書として実現される場合もあります。

集約のライフサイクル分析

下図は、法人顧客の概念データモデルの法人顧客エンティティのライフサイクルを分析したステートマシンです。

これをみると、次のことがわかります。

  • 未登録の状態の顧客は、登録されることによって未取引の状態になり、取引開始によって取引中状態になる。
  • また、取引停止によっって停止中状態になり、取引終了によって取引終了状態になる。
  • それから、未登録の状態の顧客を登録することで、取引中にすることもできるし、取引中の顧客を取引終了にすることもできる。
  • 逆に、取引停止中の顧客の取引を再開することもできるし、取引中の顧客の取引を取消すこともできる。
  • また、未取引中と取引中の顧客のみ、顧客情報を変更することができる。
  • なお、顧客情報を変更する一環として、顧客担当者と支払方法を設定することができる。
    顧客担当者は、未取引中と取引中の顧客に対して設定できるが、支払方法は、取引中の顧客でないと設定することができない。

ユースケース(業務機能レベル)の設計

システム開発するときは、まず、ビジネスアーキテクチャのビジネスプロセスからユースケースを洗い出します。
下図は、産業機械を製造、販売する会社のバリューチェーンの例です。

このバリューチェーンを見ると、顧客管理の主なプロセスは、「顧客の獲得」、「顧客の活性化」、「顧客の維持」、「顧客の処分」であることがわかります。
これから、法人顧客管理の主なユースケースは次のようになると考えられます。


このユースケースは、ビジネスプロセスを構成するアクション、あるいは、顧客管理者というジョブのタスクと同義であり、システムでどう実現されるかは考慮されていません。
なので、このユースケースが業務パッケージの機能として実現される場合もあれば、スクラッチ開発のシステムの機能として実現される場合もあります。
さらに、上述した法人顧客のライフサイクルを考えると、 顧客の登録、顧客情報の変更、顧客の取引終了ユースケースだけでなく、業務上、次のようなユースケースがあることがわかります。

なお、ここでは、顧客担当者の設定ユースケースと支払方法を設定ユースケースは、顧客情報の変更ユースケースを拡張した形にしています。
さらに、顧客をさまざまな分析軸で分類することがあると考え、顧客情報の変更ユースケースの一環として、顧客の分類ユースケースを追加しています。

ドメインモデルの検証

次に、ユースケースごとにドメインオブジェクトの状態を分析し、ドメインモデルの構造でユースケースが実現できるか、その妥当性を検証します。
次の図は、UMLのオブジェクト図を使って、「顧客の登録」ユースケース、「顧客との取引開始」ユースケース、「支払方法の設定」ユースケース、「顧客担当者の設定」ユースケース、「顧客の分類」ユースケースでドメインオブジェクトの状態がどうなるのか分析してものです。


「顧客の登録」ユースケースにおけるドメインオブジェクトの状態


上記、法人顧客エンティティのライフサイクルと整合して、顧客ステータスが未取引になっていることがわかります。


「顧客との取引開始」ユースケースにおけるドメインオブジェクトの状態


上記、法人顧客エンティティのライフサイクルと整合して、顧客ステータスが取引中になっていることがわかります。


「支払方法の設定」ユースケースにおけるドメインオブジェクトの状態


支払方法として銀行口座が設定されていることがわかります。


「顧客担当者の設定」ユースケースにおけるドメインオブジェクトの状態


顧客担当者が設定されていることがわかります。


「顧客の分類」ユースケースにおけるドメインオブジェクトの状態


顧客が3つの分類基準値で分類されていることがわかります。

ドメインモデル(論理モデル)の設計

ドメインモデル(概念モデル)の妥当性が検証できたら、次は、それをドメインモデル(論理モデル)に展開します。
ドメイン駆動設計の考えか方を適用して、CIMの、法人顧客の概念レベルのドメインモデルを、PIMの論理レベルのドメインモデルに展開すると下図のようになります。

まず、ドメイン駆動設計の考えか方を適用して、概念レベルのドメインモデルを構成しているエンティティが、集約なのか、エンティティなのか、値オブジェクトなのか、列挙型なのか識別されていることがわかります。
※参考情報
値オブジェクトとエンティティ
また、住所や電話番号、電子メールなど、これまでエンティティの属性として定義されていた要素が列挙型として抽出されていることもわかります。
このPIMの論理レベルのドメインモデルは、マイクロサービスのドメインオブジェクトとして実装されます。
なので、マイクロサービスで管理すべきデータ項目がすべて洗い出されている必要があります。

ユースケース(システム機能レベル)の設計

これまでは、業務的視点でユースケースを考えてきましたが、ここで、「システムのユーザーがシステムをどう使うか」という視点でユースケースを分析し、さらに洗練させてみましょう。
次の図は、システムの視点でユースケースを洗練したモデルです。

これを見ると、顧客情報の照会ユースケースが起点となって、顧客情報の変更ユースケース、顧客担当者の設定ユースケース、顧客の分類ユースケース、支払方法を設定ユースケースが拡張されていることがわかります。
また、顧客との取引開始や取引停止など顧客の状態変化をともなうものは、顧客のステータスの変更と考え、顧客取引の変更ユースケースとして汎化し、顧客情報の変更ユースケースに包含させています。
それから、顧客情報の照会ユースケースと顧客の登録ユースケースは、ともに、顧客一覧の照会ユースケースから派生することがわかります。

画面構成の設計

下図は、法人顧客管理の画面構成になります。

法人顧客管理システムのユースケースモデルを反映して、法人顧客一覧画面から、法人顧客登録画面と法人顧客詳細画面が分岐し、法人顧客詳細画面から、それぞれ、顧客担当者一覧画面、法人顧客分類一覧画面、支払方法選択画面、法人顧客更新画面が分岐していることがわかります。
それから、画面構成を設計するときは、個々の画面の画面項目も定義します。
画面項目を定義するときは、論理レベルのドメインモデルを構成する各エンティティの属性で表示されるものが、漏れなく、画面の項目として定義されている必要があります。

画面遷移の設計

画面構成の設計が終わったら、ユースケース単位に画面遷移を設計します。
次の図は、UMLのステートマシン図で描いた「顧客の登録」ユースケースの画面遷移です。

法人顧客一覧画面で顧客の追加すると、法人顧客登録画面に遷移し、必要な情報を設定し、顧客を登録すると、法人顧客一覧画面に戻ることがわかります。

アプリケーション連携モデルの設計

ここでは、下図のようにフロントエンドアプリケーションや他のシステムとマイクロサービスの連携の流れを設計します。

これを見ると、次のことがわかります。

  • 法人顧客管理サービスは、法人顧客を登録する際、法人情報を法人管理サービスに連携する。
  • 法人顧客管理サービスは、外部の郵便番号データ配信サービスを利用して住所情報を検証する。
  • 法人管理サービスは、国税庁の法人番号システムから法人情報を取得する。
  • 法人顧客管理サービスは、ActiveMQと非同期メッセージングを行う。
    ここでは、非同期メッセージングによって次の送受信を行うことを想定しています。

    • 支払方法が使用されたというメッセージの受信
    • 顧客担当者が使用されたというメッセージの受信
    • 法人顧客が使用されたというメッセージの受信
    • 支払方法が追加されたというメッセージの送信
    • 支払方法が無効化されたというメッセージの送信
    • 支払方法が有効化されたというメッセージの送信
    • 顧客担当者が追加されたというメッセージの送信
    • 顧客担当者が無効化されたというメッセージの送信
    • 顧客担当者が有効化されたというメッセージの送信
    • 法人顧客が変更されたというメッセージの送信

ユースケースの実現性検証

次に、上記画面遷移の設計結果を基に、フロントエンドアプリケーションや他システムとマイクロサービスの連携によって各ユースケースが実現できるか検証します。
これは、UMLのシーケンス図でユースケースの実現性を検証した例です。
各マイクロサービスに対するメッセージが、そのマイクロサービスが実現すべきAPIになります。

これは、上記アプリケーション連携モデルの構成で、「顧客の登録」ユースケースが実現できるか検証している例です。
これを見ると、次のことがわかります。

  • 法人顧客管理サービスは、法人顧客を登録する際、法人情報を法人管理サービスに登録する。
  • その際、法人管理サービスは、国税庁の法人番号システムから法人情報を取得して法人情報を検証する。
  • また、法人顧客管理サービスは、外部の郵便番号データ配信サービスを利用して住所情報を検証する。

なお、次のゆーすけーす別API一覧で、各ユースケースのアクション別APIを定義することで、簡易的に、ユースケースの実現性を検証することができます。

マイクロサービスの内部設計

ここでは、ここでは、PIMのユースケース、および、ユースケースの実現性検証の結果を受けて、それをマイクロサービス内部でどう実現するか設計します。
マイクロサービスのIT基盤は構築されていることを前提とします。

パッケージの設計

まず、パッケージの構成を設計します。
ここでは、ヘキサゴナルアーキテクチャを適用するため、上記のようなパッケージ構成にします。

クラス構造の設計

次に、法人管理サービスのクラス構造を設計します。

クラス構造の検証

最後に、設計されたクラス構造でユースケースが実現できるか検証します。
次の図は、上記、「顧客の登録」ユースケースのresiterCustomerAPIの実現性を検証した例です。


法人顧客アプリケーションサービスのresiterCustomerは次のような流れになります。

  • createCustomer
    まず、集約である法人顧客を生成します。
  • isValidCorporateCustomer
    次に、法人顧客コントローラから受け取った法人顧客DTOの妥当性を検証します。
    これは、上記、不変条件の法人顧客に対する属性間の一貫性制約の検証になります。
  • registerCorporation
    法人顧客DTOに法人番号がセットされている場合、法人顧客サービスに法人の登録を依頼します。
    法人顧客サービスでは、国税庁の法人番号システムから法人番号の法人情報を取得し、法人情報がデータベースにない場合は保存し、ある場合は更新します。
  • validateAddress
    法人顧客DTOに法人の住所がセットされている場合、法人顧客アプリケーションサービスは、郵便番号データ配信サービスを活用して住所を検証します。
  • saveCorporation
    次に、法人を法人リポジトリに保存します。
  • saveCustomer
    最後に、法人顧客を法人顧客リポジトリに保存します。

ドメインオブジェクトの不変条件の定義

ドメインオブジェクトの不変条件とは、ドメインオブジェクト全体が常に満たすべき条件のことです。
これは、集約のメソッドを通じて、特定の集約インスタンスの整合性を保持するための条件になります。
例えば、注意番号には必ず値が設定されている必要があるなど、ある特定の注文オブジェクトに閉じた整合性の保証は、ドメインロジックの不変条件になります。
法人顧客管理の集約である法人顧客のドメインオブジェクトの不変条件は次のようになります。

  • データ品質保証条件
    • データ一意性保証条約
      データの一意性を保証する条件です。

      • 顧客担当者に対する一意性制約
        同一メールまたは電話番号の担当者が存在してはならない
      • 顧客分類に対する一意性制約
        同一顧客に同じ顧客分類が存在してはならない
    • データ有効性保証条約
      データが定義域に準拠していることを保証する条件です。
      事前にデータドメインを定義しておく必要があります。

      • 法人顧客の顧客住所に対する有効性制約
        法人顧客の顧客住所はデータドメインに定義された形式に準拠していなければならない。
      • 顧客担当者の電話番号に対する有効性制約
        顧客担当者の電話番号はデータドメインに定義された形式に準拠していなければならない。
      • 顧客担当者の電子メールアドレスに対する有効性制約
        顧客担当者の電子メールアドレスはデータドメインに定義された形式に準拠していなければならない。
    • データ一貫性保証条件
      データの一貫性を保証する条件です。

      • 法人顧客に対する法人の存在制約
        法人顧客には、それに対応する法人が存在する必要がある。
      • 法人顧客に対する属性間の一貫性制約
        法人番号が指定されていれば、DUNSナンバー・名前・住所は任意。
        海外の企業の場合でも登録できるようにしたいので、法人番号が未指定の場合、DUNSナンバー・名前・住所が必須。
      • 法人顧客に対する支払方法の存在制約
        法人顧客が削除されたら、それに関連するすべての支払方法が削除される。
        例えば、次のような実装で保証することができます。
        @OneToMany(mappedBy = “customer”, cascade = CascadeType.ALL, orphanRemoval = true)
        @JsonManagedReference
        private List paymentMethods = new ArrayList<>();
      • 法人顧客に対する顧客担当者の存在制約
        法人顧客が削除されたら、それに関連するすべての顧客担当者が削除される。
        例えば、次のような実装で保証することができます。
        @OneToMany(mappedBy = “customer”, cascade = CascadeType.ALL, orphanRemoval = true)
        @JsonManagedReference
        private List representatives = new ArrayList<>();
  • ライフサイクル一貫性保証条件
    上記、法人顧客のライフサイクルから次のライフサイクル一貫性保証条件を定義することができます。

    • 未登録の場合、未取引から取引中にしか変更できない
    • 未取引の場合、未取引、取引中にしか変更できない
    • 取引中の場合、取引中、停止中、取引終了、未取引にしか変更できない
    • 停止中 の場合、取引終了、取引中にしか変更できない
    • 取引終了の場合、ステータスの変更はできない

    また、次のようなライフサイクル一貫性保証条件を実現するようにします。

    • 顧客情報(名前、住所、役割、ステータス)の変更は、未取引か取引中でなければできない
    • 顧客担当者の設定は、未取引と取引中でなければできない
    • 支払方法の設定は、取引中でなければできない

ドメインオブジェクトのメソッド(事前条件・事後条件)の定義

ここでは、ドメインオブジェクトのメソッドごとに、ドメインオブジェクトの事前条件、事後条件を定義します。
ドメインオブジェクトの事前条件とは、ドメインオブジェクトの各メソッドを呼び出す側(アプリケーションサービス)が満たすべき条件のことです。
ドメインオブジェクトの事後条件とは、ドメインオブジェクトが各メソッドを実行した後、満たすべき条件のことです。
さて、ドメインモデルから、法人顧客には、次のような操作が必要であることがわかります。

  • 法人顧客の妥当性検証
  • 顧客名の変更
  • 住所の変更
  • 支払方法の追加
  • 支払方法の無効化
  • 顧客担当者の追加
  • 顧客担当者の無効化
  • 顧客ステータスの変更
  • 顧客役割の変更
  • 顧客の分類

それぞれの操作における事前条件と事後条件を定義します。

  • 法人顧客の妥当性検証
    • 事前条件
      なし。
    • 事後条件
      法人番号が未指定の場合、DUNSナンバー・名前・住所が設定されていること。
      上記、法人顧客に対する属性間の一貫性制約の検証になります。
  • 顧客名の変更
    • 事前条件
      顧客ステータスが未取引か取引中であること。
      上記、ライフサイクル一貫性保証条件の検証になります。
    • 事後条件
      顧客名が変更されること。
  • 住所の変更
    • 事前条件
      • 顧客ステータスが未取引か取引中であること。
        上記、ライフサイクル一貫性保証条件の検証になります。
      • 住所が正しい形式で設定されていること。
        上記、法人顧客の顧客住所に対する有効性制約の検証になります。
    • 事後条件
      住所が変更されること。
  • 支払方法の追加
    • 事前条件
      • 顧客ステータスが取引中であること。
        上記、ライフサイクル一貫性保証条件の検証になります。
      • 例えば、同じ銀行コード+支店コード+口座番号の組み合わせなど、同じ支払方法(有効)が重複して存在しないこと
        これは、ドメイン知識の漏洩を防ぐ目的でドメイン層で検証する事前条件になります。
    • 事後条件
      • 同じ支払方法が無効なら有効に更新されること
      • 新規なら追加されること
  • 支払方法の無効化
    • 事前条件
        • 顧客ステータスが取引中であること
          上記、ライフサイクル一貫性保証条件の検証になります。
        • 他のマイクロサービスの支払方法使用履歴がある場合、支払方法は無効にできない
          上記、履歴整合性保証条件の検証になります。
          また、これは、ドメイン知識の漏洩を防ぐ目的でドメイン層で検証する事前条件になります。
      • 該当する支払方法が存在すること
        データの完全性制約に対する検証になります。
    • 事後条件
      支払方法が無効になること
  • 顧客担当者の追加
    • 事前条件
      • 顧客ステータスが未取引か取引中であること
        上記、ライフサイクル一貫性保証条件の検証になります。
      • 同一メールまたは電話番号の担当者が存在しないこと
        上記、顧客担当者に対する一意性制約の検証になります。
      • 電話番号が正しい形式で設定されていること。
        上記、顧客担当者の電話番号に対する有効性制約の検証になります。
      • 電子メールアドレスが正しい形式で設定されていること。
        上記、顧客担当者の電子メールアドレスに対する有効性制約の検証になります。
    • 事後条件
      顧客担当者が追加されること
  • 顧客担当者の無効化
    • 事前条件
        • 顧客ステータスが取引中であること
          上記、ライフサイクル一貫性保証条件の検証になります。
        • 他のマイクロサービスの顧客担当者使用履歴がある場合、顧客担当者は無効にできない
          上記、履歴整合性保証条件の検証になります。
          また、これは、ドメイン知識の漏洩を防ぐ目的でドメイン層で検証する事前条件になります。
      • 該当する顧客担当者が存在すること
        データの完全性制約に対する検証になります。
    • 事後条件
      顧客担当者が無効になること
  • 顧客ステータスの変更
    • 事前条件
      • 上記、ライフサイクル一貫性保証条件を満たしていること
      • 他のマイクロサービスの法人顧客使用履歴がある場合、法人顧客は無効にできない
        上記、履歴整合性保証条件の検証になります。
    • 事後条件
      顧客ステータスが変更されること
  • 顧客役割の変更
    • 事前条件
      顧客ステータスが未取引か取引中であること。
      上記、ライフサイクル一貫性保証条件の検証になります。
    • 事後条件
      顧客役割が変更されること
  • 顧客の分類
    • 事前条件
      顧客分類が重複していないこと
      顧客分類の一意性制約の検証になります。
    • 事後条件
      顧客が分類されること

アプリケーションサービスの不変条件の定義

アプリケーションサービスの不変条件とは、アプリケーションシステム全体が常に満たすべき条件のことです。
ユースケース(アプリケーションサービスのメソッド)を通じて、複数の集約種類間のトランザクション整合性や、複数の集約インスタンス全体のトランザクション整合性を保持するための条件になります。
例えば、注文の状態と在庫の状態の間の整合性の保証、注文番号は一意でなければならないなど、リポジトリを介したすべての注文オブジェクト間の整合性の保証はアプリケーションロジックの不変条件になります。
法人顧客管理の集約である法人顧客のアプリケーションサービスの不変条件は次のようになります。

  • データ品質保証条件
    • データ一意性保証条約
      データの一意性を保証する条件です。

      • 法人顧客に対する一意性制約
        法人顧客の顧客番号は一意でなければならない
    • トランザクション整合性保証条件
      法人顧客管理サービスを構成する各メソッドで、トランザクション整合性を保持する必要がある。
    • 履歴整合性保証条件
      次のような履歴整合性保証条件を実現するようにします。

      • 他のマイクロサービスの支払方法使用履歴がある場合、支払方法は無効にできない
      • 他のマイクロサービスの顧客担当者使用履歴がある場合、顧客担当者は無効にできない
      • 他のマイクロサービスの法人顧客使用履歴がある場合、法人顧客は無効にできない

    アプリケーションサービスのメソッド(事前条件・事後条件)の定義

    ここでは、アプリケーションサービスのメソッドごとに、アプリケーションサービスの事前条件、事後条件を定義します。
    アプリケーションサービスの事前条件とは、アプリケーションサービスの各メソッドを呼び出す側(アダプタ)が満たすべき条件のことです。
    アプリケーションサービスの事後条件とは、アプリケーションサービスが各メソッドを実行した後、満たすべき条件のことです。
    法人管理サービスのアプリケーションサービスを構成するメソッドにおける事前条件と事後条件を定義します。
    以下は、事前条件と事後条件の例です。

    • 顧客の登録
      • 事前条件
        法人番号が指定されている場合、法人管理サービスから有効な法人情報(name, addressなど)が取得できること 。
        法人番号が指定されていない場合、DUNSナンバー、名前、住所が取得できること。
      • 事後条件
        同じ法人番、または、DUNSナンバーの法人が既に存在する場合、名前、住所、DUNSナンバーに差分があれば既存の法人が更新されて保存される。
        差分がなければそのまま返却され、更新は行われない。
        同じ法人番号 or DUNS番号の法人が既に存在しない場合、新しい法人が作成されて保存される。
    • 顧客情報の更新
      • 事前条件
        顧客番号が指定されており、顧客番号の法人顧客が存在していること。
        住所が指定されている場合、郵便番号、国、都道府県、市区町村、番地はいずれも null や空ではないこと。
      • 事後条件
        先に法人顧客情報が更新される前に、既に他者により更新されている場合、更新されてはならない。
        法人顧客情報が更新される。
    • 支払方法の追加
      • 事前条件
        顧客番号が指定されており、顧客番号の法人顧客が存在していること。
        銀行口座の場合、適切な銀行コード、支店コード、口座番号が取得できること。
      • 事後条件
        支払方法が追加される。
    • 支払方法の有効化・無効化
      • 事前条件
        顧客番号が指定されており、顧客番号の法人顧客が存在していること。
        支払方法が指定されており、存在していること。
        無効化の場合、支払方法の使用履歴がないこと。
      • 事後条件
        無効の支払方法が有効化される。
        有効の支払方法が無効化される。
    • 顧客担当者の追加
      • 事前条件
        顧客番号が指定されており、顧客番号の法人顧客が存在していること。
        電話番号が指定されている場合、国際電話番号の標準形式(E.164形式)に則っていること。
        メールアドレスが指定されている場合、メールアドレスのルールに則っていること。
      • 事後条件
        担当者が追加される。
    • 顧客担当者の有効化・無効化
      • 事前条件
        顧客番号が指定されており、顧客番号の法人顧客が存在していること。
        顧客担当者が指定されており、存在していること。
        無効化の場合、顧客担当者の使用履歴がないこと。
      • 事後条件
        無効の支払方法が有効化される。
        有効の支払方法が無効化される。
    • 顧客の分類
      • 事前条件
        顧客番号が指定されており、顧客番号の法人顧客が存在していること。
        適切な顧客分類値が取得されること。
      • 事後条件
        顧客が分類される。

    アダプタの設計

    RESTコントローラ

    RESTコントローラですが、集約である法人顧客単位にコントローラを作成し、ユースケース単位にメソッドを定義します。

    非同期メッセージング

    上述した非同期メッセージングによる次の送受信を設計します。

    • 支払方法が使用されたというメッセージの受信
    • 顧客担当者が使用されたというメッセージの受信
    • 法人顧客が使用されたというメッセージの受信
    • 支払方法が追加されたというメッセージの送信
    • 支払方法が無効化されたというメッセージの送信
    • 支払方法が有効化されたというメッセージの送信
    • 顧客担当者が追加されたというメッセージの送信
    • 顧客担当者が無効化されたというメッセージの送信
    • 顧客担当者が有効化されたというメッセージの送信
    • 法人顧客が変更されたというメッセージの送信

    マイクロサービスの仕様の定義

    マイクロサービスの設計仕様は次の観点で定義します。

    詳細は、生成AIと創るマイクロサービスを参照してください。

    フロントエンドアプリケーションの仕様の定義

    詳細は、生成AIと創るフロントエンドアプリケーションを参照してください。

-DX, アプリケーション

執筆者:

関連記事

エンタープライズアーキテクチャ(EA)とは【わかりやすく解説】

ここでは、以下の観点で、エンタープライズアーキテクチャ(EA)について解説します。 エンタープライズアーキテクチャ(EA)とは エンタープライズアーキテクチャ(EA)の重要性 エンタープライズアーキテ …

実践!DX(デジタルトレンスフォーメーション)

ここでは、架空の会社、左川産業株式会社を例に、デザイン思考経営をベースとしたDXをどう進めるのか、DX成熟度ごとのフェーズに分けて説明します。 なお、ここでは、DXを、 企業を データやデジタル技術を …

クラス図を使った概念モデルの作り方

ここでは、UMLのクラス図を使って概念モデルをどう作るか、次の順で説明します。 抽象化 一般化 構造化 関連動画 関連記事 データマネジメントの導入方法 抽象化 私たちが人や物事を認識するときは、それ …

データマネジメント

これは、データマネジメントの全体像を表した図です。 ここでは、データマネジメントについて次の観点で解説します。 データの重要性 データマネジメントとは何か データマネジメントはなぜ必要なのか データマ …

事業ライフサイクル

これは、事業ライフサイクルを表した図です。 ここでは、事業ライフサイクルについて次の観点で解説します。 事業パーパス 戦略サイクル マネジメントサイクル 事業の成長ステージ 事業のポートフォリオ 関連 …