コンテンツにスキップ

戦術的設計

はじめに

本サイトにつきまして、【IT技術の知見】はじめに - 俺の技術ノート をご認識のほど宜しくお願いいたします。


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

MVC と問題点

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

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

MVCモデル

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

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

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

ドメイン駆動設計


02. ドメインモデル

ドメインモデルとは

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

ドメインモデル図

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

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

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

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

ドメインオブジェクト図

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

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

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

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

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

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

    ticket-modeling_little-hands_domain-model-diagram_example-2

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

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

    ticket-modeling_little-hands_domain-model-diagram_example-3

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

    ticket-modeling_little-hands_enum_example

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

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

    ticket-modeling_little-hands_domain-model-diagram_example-4

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

    ticket-modeling_little-hands_domain-model-diagram_example-4


03. ドメインモデリング手法の種類

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

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

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

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

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

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

  • 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. アーキテクチャの種類

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

▼ 4層の場合

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

layered-architecture

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

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

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

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

▼ 3層の場合

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

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


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

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

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

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


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

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

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

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


オニオンアーキテクチャ

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

onion-architecture


クリーンアーキテクチャ

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

clean-architecture