コンテンツにスキップ

ドメイン駆動設計@アーキテクチャ

はじめに

本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。


01. ドメイン駆動設計とは

オブジェクト指向分析設計から派生した分析設計の手法の一種。

オブジェクト指向分析設計のベタープラクティスを集め、より強化するために提唱された。

特に機能要件の多いアプリケーションに有効である。

必ずしもオブジェクト指向設計でドメイン駆動設計に沿う必要はなく、通常のオブジェクト指向分析設計をしても問題はない。


02. ドメイン駆動設計の手順例

戦略的設計の手順例

ddd_strategic_design_flow

戦略的設計では、ドメイン全体から境界づけられたコンテキストを明確にする。

(1)

ドメインエキスパートと話し合い、ドメイン全体の中からコアドメインとサブドメインを切り分ける。

(2)

ドメインエキスパートの部署や業務フローの立ち位置によっては、同じ『名詞』や『動詞』であっても、意味合い/定義づけが異なる場合もある。その場合、それぞれを異なる名前からなるユビキタス言語として定義づける。

(3)

ユビキタス言語を元に、境界づけられたコンテキストを定義づける。

(4)

コンテキストマップを作成し、境界づけられたコンテキスト間の関係を明らかにする。


戦術的設計の手順例

戦術的設計では、境界づけられたコンテキストをアーキテクチャやデザインパターンに落とし込む。

ここでは、SUDOモデリングを採用するものとする。

(1)

ドメインエキスパートと話し合いにドメインルールや振る舞いをヒアリングする。

(2)

オブジェクトの具体化のためにユースケース図やオブジェクト図でオブジェクトを作成し、抽象化のためにドメインモデル図も作成する。

(3)

必要であればドメインエキスパートに再ヒアリングを行い、特にオブジェクト図とドメインモデル図を改善する。

(4)

ドメインモデル図を元に、クラス図を作成する。この時、モデルをエンティティや値オブジェクトを切り分けるようにする。

(5)

アーキテクチャ (レイヤード型、ヘキサゴナル型、オニオン型、クリーンアーキテクチャ) を決め、クラス図を元にドメイン層を実装する。

(6)

運用後に問題が発生した場合、特にオブジェクト図とドメインモデル図を修正する。場合によっては、デザインパターンに切り分ける。


03. 戦略的設計

ドメイン

▼ ドメインとは

ビジネスモデル全体で見たときに、ソフトウェア化の対象となる業務領域のこと。

▼ ドメインの分割方法

業務領域を分割するときの粒度は小さいほど良い。

業務領域を細分化するうえで境目を見分ける方法として、会社の組織図から、部署ごとに担当する業務の種類を確認すると良い。

また、ビジネスモデルの一連の業務フローの中で、業務の担当者の属性が変化するタイミングに着目すると良い。

担当者が変われば、業務をより小さな単位で抽出できるはずである。例えば、コールセンター部 (電話対応業務、顧客管理業務) や法人営業部 (受注業務) がある。また、マーケティング部 (ユーザー集客業務、広告運用業務) や管理部 (会計業務、財務業務、採用業務) がある。

この時の注意点として、業務領域は、ToBやToCに関わらないことである。

例えば、ToCなドメインとしては、マーケーティング部による業務 (ユーザー集客業務、広告運用業務) がある。

▼ 例:インターネット広告代理店

インターネット広告代理店の例。

ビジネスモデルに基づく複数のドメインを以下に示す。

業務フローの担当者の変化として、まず問い合わせで注文を受けて広告アカウントを作成する『営業担当者』、制作した広告をアカウントに入稿する『制作担当者』、入稿された広告を運用して広告効果を高める『マーケティング担当者』、最後に広告の依頼者に料金を請求する『経理担当者』が挙げられる。

これにより、インターネット広告代理店のビジネスモデルは、各担当者に対応するドメインへ分割できる。

internet_advertising_agency_domain

▼ 例:完全個室ジムを運営するハコジム

hacogym_business_model

完全個室ジムを運営するハコジムの例。

ビジネスモデルに基づく複数のドメインを以下に示す。

業務フローの担当者の変化として、まず個室ジムに適する物件を探す『物件担当者』、ジムのトレーナーを採用して会員に紹介する『採用担当者』、個室ジムの利用会員を獲得する『営業担当者』が挙げられる。

これにより、ハコジムのビジネスモデルは、各担当者に対応するドメインへ分割できる。

hacogym_domain

▼ 例:監視SaaS

プラットフォームエンジニアリングでは、エンジニアの技術的な業務がドメインになる。

例えば、監視SaaSでは監視業務領域がドメインになる。

適切な監視手法の選択、適切なTCP/IPのプロトコルの選択、アラートの巡回が業務である。

▼ 例:オンライン書店

  • カタログ管理
  • 在庫管理
  • 顧客分析
  • 決済管理

▼ 例:病院システム

  • 情報管理
  • 予約管理


コアドメイン、サブドメイン、ドメインエキスパート

▼ コアドメイン、サブドメインとは

core-domain_sub-domain_bounded-context

▼ ドメインエキスパートとは

各ドメインのドメインエキスパートと、エンジニアが話し合いながら、ドメイン内の主要業務をコアドメイン、補助的な業務をサブドメインに分類する。

コアドメインやサブドメイン相当の業務に詳しい人 (アプリケーションの利用者本人、利用者の関心が高い人) がドメインエキスパートになることが多い。

*具体例*

業務アプリケーションの開発では、ビジネス業務(決済、請求、送金など)がドメインになる。

実際にビジネス側の人がドメインエキスパートを担ってもよいが、プロジェクトマネージャーがドメインエキスパートになるほうが現実的である。

*具体例*

プラットフォームエンジニアリングでは、エンジニアの技術的な業務 (監視業務、セキュリティ対策など) がドメインになる。

そのため、プラットフォームSaaSではドメインエキスパートはエンジニア(SREなど)になる。

▼ サブドメインの委譲

コアドメインのソフトウェアは内製である必要があるが、サブドメインのソフトウェアは外製/内製のいずれでも問題ない。

必要であれば、他の業務系パッケージや業務系SaaS (例:決済代行のベリトランス、経理SaaSのマネーフォワード、総務人事SaaSのサイボウズなど) にドメインロジックを委譲し、これのAPIをコールしてデータを取得するような設計でもよい。

ただ、コアドメインが外部に依存すると、そのSaaSで障害が起こったときにコアドメインのシステムも停止する可能性があるため、注意が必要である。

▼ 例:完全個室ジムを運営するハコジム

完全個室ジムを運営するハコジムの例。

ドメインのうちで、個室ジムドメインに基づくコアドメインとサブドメインを以下に示す。

コアドメインは予約ドメイン、それ以外はサブドメインとしている。

hacogym_subdomain

*例*

ECサイトを運営するアスクルの例。

ドメインのうちで、個人向け販売ドメイン (サイト名はLOHACO) に基づくコアドメインとサブドメインを以下に示す。

配送/注文/商品/ユーザ管理/在庫/受注をそれぞれサブドメインとしている (コアドメインは明言されていない) 。


ユビキタス言語

▼ ユビキタス言語とは

同じ境界づけられたコンテキスト内で 1 個の意味合い/定義付けを持った『名詞』や『動詞』のこと。

ドメインエキスパート間で、特定の『名詞』や『動詞』の意味合い/定義づけが異なる場合、これを異なる名前からなるユビキタス言語として定義づける。

domain-model

▼ ユビキタス言語を見つける議論フレームワーク

イベントストーミングを実施し、業務フローやその中でドメインイベントの名詞や動詞から、ユビキタス言語を見つける。

議論の中で発生したドメインイベントを線で結ぶ。

event-storming_domain-event.png

Figmaなどのツールを使用して、画面ごとにドメインイベントをつなげ、フロントエンドやバックエンドの機能ロジックを設計していく。

event-storming_domain-event.png

▼ 抽出例

単語 意味合い 対応するドメインモデル
... ... ...
... ... ...


境界づけられたコンテキスト

▼ 境界づけられたコンテキストとは

ドメインエキスパートの業務フローの立ち位置が異なれば、同じ『名詞』や『動詞』であっても、異なる意味合い/定義づけのユビキタス言語が使用される。

異なるユビキタス言語を元にして、境界づけられたコンテキストを設定する。

この時、ユビキタス言語は、他の境界づけられたコンテキストでは通じないものであればあるほど良い。

境界づけられたコンテキストそれぞれのユビキタス言語に合わせて、異なる名前でモデリングしていく。

境界づけられたコンテキストを定義しない場合、異なるユビキタス言語をコアドメインやサブドメイン間で共有することとなり、それぞれの関心に無関係なデータを保持することになってしまう。

▼ 考え方

アプリケーションがモデリングしている業務フローを考えるとわかりやすい。

ビジネス全体のどの部分をアプリケーションにしているのかによるが、例えばAmazonで以下の登場人物がいるとする。

  1. 受注管理する人は、商品ドメインモデルが持つ注文内容/値段に関する状態に関心がある。
  2. 在庫管理する人は、商品ドメインモデルが持つ在庫数に関する状態に関心がある。
  3. 発送管理する人は、商品ドメインモデルが持つ発送状況に関する状態に関心がある。
  4. 請求管理する人は、商品ドメインモデルが持つ請求状況に関する状態に関心がある。
  5. 仕入れ管理する人は、商品ドメインモデルが持つ仕入れ状況に関する状態に関心がある。

商品 (Item) というオブジェクトがあったときに、業務フローの中で商品を扱う人の文脈 (コンテキスト) によって、商品ドメインモデルの持つ状態への関心が変わる。

ここでいう状態とは、具体的に商品ドメインモデルを実装したときにプロパティとしてオブジェクトに持たせている状態である。

上記の1-4は、同じ商品ドメインモデルに対して関心の内容が異なるので、境界づけられたコンテキストが異なるとみなしたほうが良い。

別々のマイクロサービスとして分割し、それぞれのマイクロサービス上で異なる商品ドメインモデルを定義し、異なる状態を持たせることになる。

反対にモノリスだと、1つの商品ドメインモデルにコンテキスト関係なく全ての種類の状態を持たせて、全てのコンテキストで再利用する。

*表*

境界づけられたコンテキスト名 マイクロサービス名 集約名 集約内のエンティティ

▼ 例:書籍ECサイト

書籍ECサイトの例。

コアドメインとサブドメインに基づいたユビキタス言語と境界づけられたコンテキストを以下に示す。

バイヤー (仕入れ) 部、マーケティング部、在庫管理部のドメインエキスパートは、『本 (商品) 』という名詞に対する意味合い/定義づけが異なる。

そのため、それぞれを『本』『クーポン』『在庫』というユビキタス言語として定義できる。モデル名/データ名は、それぞれのユビキタス言語へ合わせた名前になる。

例えば、マーケの境界づけられたコンテキストでは、モデル名はCouponとなる。また、割引期間データを保持する必要がある。一方で、仕入部や在庫部ではこのデータは不要である。

一方、書籍のISBNは全ての境界づけられたコンテキストのモデルに必要なデータである。

境界づけられたコンテキストを定義しない場合、1 個の商品モデルが全てのデータを保持することとなり、それぞれのドメインエキスパートが関心を持たないデータも保持することになってしまう。

*表*

境界づけられたコンテキスト名 マイクロサービス名 集約名 集約内のエンティティ

book_ec_ubiquitous_language

書籍モデルの実装例は次のとおりである。

/** カタログコンテキストの書籍モデル */
class Book {
  constructor(
    /** 書籍の一意の識別子 */
    public isbn: string,
    /** 書籍のタイトル */
    public title: string,
    /** 書籍の著者 */
    public author: string,
    /** 書籍の説明 */
    public description: string,
    /** 書籍の販売価格 */
    public price: number,
  ) {}
}
/** 在庫コンテキストの書籍モデル */
class Book {
  constructor(
    /** 書籍の一意の識別子 */
    public isbn: string,
    /** 書籍のタイトル */
    public title: string,
    /** 書籍の在庫数 */
    public quantityAvailable: number,
    /** 保管場所 */
    public location: string,
    /** 書籍の在庫ステータス */
    public status: "IN_STOCK" | "OUT_OF_STOCK",
  ) {}
}

▼ 例:完全個室ジムを運営するハコジム

完全個室ジムを運営するハコジムの例。

個室ジムドメインのコアドメインとサブドメインに基づく境界づけられたコンテキスト。

認証コンテキスト、予約コンテキスト、顧客管理コンテキスト、銀行支払いコンテキスト、クレジットカード支払いコンテキストがある。

*表*

境界づけられたコンテキスト名 マイクロサービス名 集約名 集約内のエンティティ
認証
予約
顧客管理
銀行支払い
クレジットカード支払い

hacogym_bounded-context

▼ 例:契約請求管理アプリケーションを提供するアルプ

契約請求管理アプリケーションを提供するアルプの例。

コアドメインとサブドメインに基づいたユビキタス言語と境界づけられたコンテキストを以下に示す。

契約管理コンテキスト、商品管理コンテキスト、請求管理コンテキストがある。

アルプでは、ユビキタス言語を定期的に認識合わせするために、週次でユビキタス言語を追加し、また定義を更新している。

*表*

境界づけられたコンテキスト名 マイクロサービス名 集約名 集約内のエンティティ
契約管理
商品管理
請求管理

contract_billing_management_ubiquitous_language

▼ 例:会計アプリケーションを提供するfreee

会計アプリケーションを提供するfreeeの例。

財務会計コンテキスト、会計ワークフローコンテキスト、従業員管理コンテキストがある。

境界づけられたコンテキスト名 マイクロサービス名 集約名 集約内のエンティティ
財務会計
会計ワークフロー
従業員管理

freee_bounded-context

▼ 個人間送金ドメイン

個人間送金業務の担当者が変わる境目を見つけ、それを境界づけられたコンテキストにする。

ユーザー:利用者の登録、本人確認、利用停止を扱う。
↓
口座:送金元口座や受取口座の登録、有効性確認を扱う。
↓
支払依頼:受取人から送金人への請求や支払依頼を扱う。
↓
送金取引:送金依頼の作成、送金実行、送金ステータス更新を扱う。
↓
送金精算:送金結果を集計し、参加金融機関間の受け払い金額を確定する。
↓
送金照合:自システムの送金記録と外部データを突き合わせ、差分を確認する。
↓
レポーティング:送金履歴、送金明細、精算結果、照合結果を出力する。
↓
送金取引管理ポータル:管理者が送金取引を照会し、例外対応や再処理を行う。

*表*

境界づけられたコンテキスト名 マイクロサービス名 集約名 集約内のエンティティ
送金取引 remittance 送金 Remittance(送金)、RemittanceHistories(送金履歴)、RemittanceStatuses(送金ステータス)
請求 payment 請求 Payment(請求)、TransactionHistory(取引履歴)
銀行口座 BankAccount 銀行口座 BankAccount(銀行口座)
ユーザー user ユーザー User(ユーザー)
精算 settlement 精算 Settlement(精算)
送金照合 reconciliation 照合 Reconciliation(照合)、ReconciliationResult(照合結果)、Difference(差分)
レポーティング reporting レポーティング RemittanceHistory(送金履歴)、RemittanceDetailFile(送金明細ファイル)
送金取引管理ポータル web-portal 送金取引管理 webポータルのフロントエンドアプリケーション

▼ QR決済ドメイン

QR決済業務の担当者が変わる境目を見つけ、それを境界づけられたコンテキストにする。

ユーザー:利用者の登録、本人確認、利用停止を扱う。
↓
加盟店契約:加盟店との契約、利用可能な決済手段、精算条件を扱う。
↓
QR決済取引:QRコードを使った決済要求、決済実行、取引ステータス更新を扱う。
↓
QR決済精算:QR決済結果を集計し、加盟店への支払額や手数料を確定する。
↓
QR決済照合:自システムの取引記録と決済事業者や外部ファイルを突き合わせ、差分を確認する。
↓
QR決済取引管理ポータル:管理者がQR決済取引を照会し、例外対応や再処理を行う。

*表*

境界づけられたコンテキスト名 マイクロサービス名 集約名 集約内のエンティティ
QR決済取引 transaction 取引 Transaction(取引)
加盟店契約 merchant 契約 MerchantContract(加盟店契約)、Merchant(加盟店)
精算 payment 精算 Payment(清算)
ユーザー user ユーザー User(ユーザー)
QR決済照合 reconciliation 照合 Reconciliation(照合)、ReconciliationResult(照合結果)、Difference(差分)
QR決済取引管理ポータル web-portal QR決済取引管理 webポータルのフロントエンドアプリケーション


ドメインモデルの種類

▼ 隠蔽モデル

特定の境界づけられたコンテキストのみで使用するドメインモデルのこと。

bounded-context_domain-model_type

▼ 共有モデル

異なる境界づけられたコンテキスト間で、一部の状態を共有ドメインモデルのこと。

図では、在庫品目モデルがそれに相当する。

bounded-context_domain-model_type


コンテキストマップ

▼ コンテキストマップとは

広義のドメイン全体の俯瞰する図のこと。

コアドメイン、サブドメイン、境界づけられたコンテキストを定義した後、これらの関係性を視覚化する。

異なるサブドメインの間で異なるユビキタス言語を使用する場合、境界づけられたコンテキストはサブドメインをまたがない。

一方で、同じユビキタス言語を使用する場合、境界づけられたコンテキストは複数のサブドメインにまたがる。

できる限り、各境界づけられたコンテキストでは異なるユビキタス言語を使用する。そして、境界づけられたコンテキストが複数のサブドメインへまたがらないようにしたほうが良い (これ重要) 。

context-map

▼ 記法

*例*

完全個室ジムを運営するハコジムの例。

個室ジムドメインのそれぞれの境界づけられたコンテキストに基づくモデリング。

コアドメインの予約コンテキストとスマートロックコンテキストは、1 個のマイクロサービスとして内製化している。

一方で、それ以外の境界づけられたコンテキストは外製化している。

hacogym_subdomain_modeling


04. 戦術的設計

MVCからレイヤードアーキテクチャへの変遷

▼ MVCと問題点

ドメイン駆動設計が提唱される以前、MVCの考え方が主流であった。

しかし、特にModelの役割が抽象的過ぎたため、開発規模が大きくなるにつれて、Modelに役割を集中させ過ぎてしまうことがあった。

MVCモデル

▼ MVCからレイヤードアーキテクチャへの移行

ドメイン駆動設計が登場したことによって、MVCは発展し、M・V・Cそれぞれの役割がより具体的で精密になった。

Modelの肥大化は、Modelが持つビジネスロジックをドメイン層、またCRUD処理をインフラストラクチャ層として分割することによって、対処された。

ドメイン駆動設計


ドメインモデル

▼ ドメインモデルとは

現実の業務を抽象化した概念のこと。

▼ ドメインモデル図

ドメインモデルの図のこと。

基本的にオブジェクト指向分析設計では、分析のためにユースケース図やオブジェクト図を作成し、その後に設計のためにクラス図やシーケンス図を作成する。

一方でドメイン駆動設計の分析では、オブジェクトの具体化のためにユースケース図やオブジェクト図でオブジェクトを作成し、抽象化のためにドメインモデル図も作成する。

この『具体例から抽象を導く』という作業により、オブジェクト思考分析よりも現実に沿ったモデリングが可能になる。

▼ ドメインオブジェクト図

ドメインモデルを具体的に実装した図のこと。

▼ コアドメイン/サブドメインのモデリング

ドメインモデル図を基に、コアドメイン/サブドメインのモデリングを実行する。

core-domain_sub-domain_bounded-context_modeling

▼ 記法

クラス図と同様にして、オブジェクト図のインスタンス間の関係性を参考にして、ドメインモデル間の関係性を設定する。

オブジェクト間がIDのみを使用する関係であれば『点線矢印』とし、加えてオブジェクト全体を使用する関係であれば『白塗りの菱形』とする (記号の表記方法は個人差がある) 。

この時、点線矢印の関係性であれば異なる集約に所属し、加えて白塗りの菱形であれば同じ集約に所属しているため、これらから集約の境界を設定する。

インスタンス間のリンク記号数を参考にして、多重度を付記する。

ドメインルールを吹き出しに書き込むことにより、ソフトウェアの構造のみでなくドメインルールも表す。

*例*

  1. 業務内容をヒアリングし、ユースケース図を作成する
  2. ヒアリング内容からユビキタス言語を抽出し、ドメインモデル図を作成する
  3. ドメインモデル図からエンティティと値オブジェクトを含むルートエンティティを作成する

*例*

とある映画チケット料金を題材に、ハッシュタグチケット料金モデリングとして、色々なほうがユースケース図とドメインモデル図を作成されている。

いずれの方も非常に参考になる (モデリングは難しい) 。

(1)

映画チケット購入者の受注管理システムを開発する例を考える。

(2)

ドメインエキスパートへの要件定義が終えた想定で、ユースケース図を作成する。オブジェクト図は省略する。

ticket-modeling_little-hands_usecase-diagram_example

(3)

暫定的なドメインモデル図を作成する。little_hands_s さんは、IDのみを使用する関係であれば『実線矢印』とし、加えてオブジェクト全体を使用する関係であれば『黒塗りの菱形』としている。ユースケースから以下のオブジェクトを抽出する。この時、実装パターンをおおまかに予想しておく。また、矢印と菱形の関係性から、集約の境界を設定する。

ユースケース 抽出されたオブジェクト例 実装パターン 抽出された集約
映画、上映日時、枚数を選択する 上映時間帯オブジェクト、上映オブジェクト、映画オブジェクト エンティティ、値オブジェクト 上映集約、映画集約

ticket-modeling_little-hands_domain-model-diagram_example-1

(3)

ドメインモデル図を更新する。

ユースケース 抽出されたオブジェクト例 実装パターン 抽出された集約
映画、上映日時、枚数を選択する 上映時間帯オブジェクト、上映オブジェクト、映画オブジェクト エンティティ、値オブジェクト 上映集約、映画集約
同上 予約オブジェクト エンティティ 予約集約
割引を選択する 適用割引オブジェクト 値オブジェクト 予約集約
支払い金額を確認する 支払料金オブジェクト 値オブジェクト 支払い料金集約

ticket-modeling_little-hands_domain-model-diagram_example-2

(4)

ドメインモデル図を更新する。

ユースケース 抽出されたオブジェクト例 実装パターン 抽出された集約
映画、上映日時、枚数を選択する 上映時間帯オブジェクト、上映オブジェクト、映画オブジェクト エンティティ、値オブジェクト 上映集約、映画集約
同上 予約オブジェクト エンティティ 予約集約
割引を選択する 適用割引オブジェクト 値オブジェクト 予約集約
支払い金額を確認する 支払料金オブジェクト 値オブジェクト 支払い料金集約
同上 料金区分オブジェクト 区分オブジェクト (Enum) 料金設定集約

ticket-modeling_little-hands_domain-model-diagram_example-3

実装フェーズに入ってからの話になるが、料金区分オブジェクトはenum型として実装することになり、以下の様になる。

ticket-modeling_little-hands_enum_example

(5)

ドメインモデル図を更新する。

ユースケース 抽出されたオブジェクト例 実装パターン 抽出された集約
映画、上映日時、枚数を選択する 上映時間帯オブジェクト、上映オブジェクト、映画オブジェクト エンティティ、値オブジェクト 上映集約、映画集約
同上 予約オブジェクト エンティティ 予約集約
割引を選択する 適用割引オブジェクト 値オブジェクト 予約集約
支払い金額を確認する 支払料金オブジェクト 値オブジェクト 支払い料金集約
同上 料金区分オブジェクト 区分オブジェクト (Enum) 料金設定集約
同上 料金区分計算オブジェクト 値オブジェクト 料金区分計算集約

ticket-modeling_little-hands_domain-model-diagram_example-4

(6)

集約間の関係性のみに着目する、オブジェクト間の関係性は複雑であるが、集約間は単純であることが分かる。

ticket-modeling_little-hands_domain-model-diagram_example-4


04-02. ドメインモデリング手法の種類

ステートソーシングパターン

▼ ステートソーシングパターンとは

ドメインモデル(ミュータブルモデル)の最新の状態を永続化する。

過去の状態は上書きしてしまう。

通信方式がリクエスト/レスポンス方式の場合に適する。

▼ モデリングフレームワーク

  • SUDOモデリング (システム関連図、ユースケース図、ドメインモデル図、オブジェクト図)
  • RDRA
  • ICONIX (ユースケース駆動)
  • イベントストーミング (これはイベントソーシングでも使える)

▼ テーブル構造

id order_name
1 foo
2 bar
3 baz
4 qux
5 quux

▼ イベント仲介システム

ステートソーシングパターンの場合、ドメインオブジェクトを状態に着目してモデリングしている。

ステートソーシングパターンでは、必要な箇所でイベント仲介システムを任意に使用することもできる。

通知処理をステートソーシングパターンでモデリングし、イベント仲介システムにメールを送信する。


イベントソーシングパターン

▼ イベントソーシングパターンとは

ドメインモデル(イミュータブルモデル)の状態の履歴を永続化する。

通信方式がパブリッシュ/サブスクライブ方式の場合に適する。

CQRSと相性が良い。

▼ モデリングフレームワーク

業務フローやその中でドメインイベントを見つけるための方法として、イベントストーミングがある。

ただ、イベントソーシングパターンだけでなく、ステートソーシングパターンでも使える。

▼ テーブル構造

イベントソーシングは、ステートソーシング (CRUD) とは異なり、データの参照/作成しかない。

event_entity_id カラムを使えば、特定のドメインモデル (event_entity カラム) の状態の履歴を追跡できる。

そのため、ステートソーシングではドメインモデル(ミュータブルモデル)の最新の状態しか永続化できない一方で、イベントソーシングパターンはドメインモデル(ミュータブルモデル)の状態の履歴が残る。

そのため、Gitのようにして過去の状態を参照できる。

テーブル構造は以下のとおりになり、イベントデータが参照/作成されるだけである。

id event_name event_entity_name event_entity_id event_data
1 OrderCreated Order 1 OrderCreatedオブジェクトをJSONに変換したもの
2 OrderUpdated Order 1 OrderUpdatedオブジェクトをJSONに変換したもの
3 OrderCreated Order 2 OrderCreatedオブジェクトをJSONに変換したもの
4 OrderCanceled Order 1 OrderCanceledオブジェクトをJSONに変換したもの
5 OrderCreated Order 3 OrderCreatedオブジェクトをJSONに変換したもの
... ... ... ... ...

▼ イベント仲介システム

イベントソーシングパターンの場合、ドメインオブジェクトをイベントに着目してモデリングしている。

そのため、イベント仲介システムを使用する必要がある。

通知処理をイベントソーシングパターンでモデリングし、イベント仲介システムにメールを送信する。


04-03. アーキテクチャの種類

レイヤードアーキテクチャ

▼ 4層の場合

最初に提唱された実現方法。

layered-architecture

レイヤードアーキテクチャのインフラストラクチャ層に対して、依存性逆転を組み込むかどうかには言及していない。

  • インターフェース層 (コントローラー、認証)
  • ユースケース層 (ユースケース)
  • ドメイン層 (ドメインモデル、認可)
  • インフラストラクチャ層 (永続化)

MVCとの関係は次のとおりである。

MVCアーキテクチャ レイヤードアーキテクチャ
Model ドメイン層、インフラストラクチャ層
Controller インターフェース層
View インターフェース層
- ユースケース層 (新しく実装する)

▼ 3層の場合

4層のときにあったユースケース層とドメイン層をビジネスロジック層として統合する。

  • インターフェース層 (コントローラー、認証)
  • ビジネスロジック層 (ユースケース、ドメインモデル、認可)
  • インフラストラクチャ層 (永続化)


レイヤードアーキテクチャに依存性逆転を組み込む

レイヤードアーキテクチャのインフラストラクチャ層に対して、依存性逆転を組み込んだもの。

ドメイン層のオブジェクトは、ドメイン層の他のオブジェクトに依存する以外、他のオブジェクトや外部パッケージに依存しない。

逆に考えれば、これらに依存するものはドメイン層に配置する必要はないと判断できる。


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

別名『ポートアンドアダプターアーキテクチャ』という。

レイヤードアーキテクチャ

本質的には、他の『オニオンアーキテクチャ』『クリーンアーキテクチャ』に同じである。


オニオンアーキテクチャ

本質的には、他の『ヘキサゴナルアーキテクチャ』『クリーンアーキテクチャ』に同じである。

onion-architecture


クリーンアーキテクチャ

本質的には、他の『ヘキサゴナルアーキテクチャ』『オニオンアーキテクチャ』に同じである。

clean-architecture