アーキテクチャパターンとDDDの関係

DDDの中核原則は「ドメインモデルをシステムの中心に据える」ことです。 しかし、Evansの原典ではアーキテクチャの具体的な実装について詳しく述べられていません。 その後、複数のアーキテクチャパターンがDDDと組み合わせて提唱され、 「ドメインを外部関心事から隔離する」方法が洗練されてきました。

本章では、レイヤードアーキテクチャからクリーンアーキテクチャまでの進化を辿り、 DDDとの相性、それぞれの長所・短所、そして実践的なディレクトリ構造を解説します。

レイヤードアーキテクチャ — DDDの古典的基盤

Eric Evansが『Domain-Driven Design』で推奨したのが4層のレイヤードアーキテクチャです。 各層は明確な責務を持ち、上位層から下位層への一方向の依存を許可します。

graph TB
  P[Presentation Layer\nUI・API] --> A[Application Layer\nユースケース調整]
  A --> D[Domain Layer\nビジネスロジック]
  D --> I[Infrastructure Layer\nDB・外部API・メッセージング]

  style P fill:#3b82f6,stroke:#1d4ed8,color:#fff
  style A fill:#8b5cf6,stroke:#6d28d9,color:#fff
  style D fill:#f97316,stroke:#ea580c,color:#fff
  style I fill:#6366f1,stroke:#4f46e5,color:#fff
古典的レイヤードアーキテクチャ: 上から下への一方向依存。ドメイン層がインフラ層に依存する点が課題
責務 含まれるもの
Presentation ユーザーとの入出力 コントローラ、ビュー、APIエンドポイント
Application ユースケースの調整 アプリケーションサービス、DTO、コマンド/クエリ
Domain ビジネスロジック エンティティ、値オブジェクト、集約、ドメインサービス
Infrastructure 技術的関心事 リポジトリ実装、ORM、メッセージブローカー、外部API

ヘキサゴナルアーキテクチャ(Ports and Adapters)

2005年にAlistair Cockburnが提唱したヘキサゴナルアーキテクチャは、 アプリケーションをポート(インターフェース)アダプタ(実装)で外部世界と接続する設計です。 「六角形」という名称は、ポートが任意の数だけ存在し得ることを幾何学的に表現しただけで、6つに限定する意味はありません。

核心は依存の方向を反転させることです。 アプリケーション(内側)がポートを定義し、インフラ(外側)がそのポートを実装するアダプタを提供します。 これにより、ドメインはインフラに一切依存しません。

graph LR
  subgraph outside_left[駆動する側 Driving]
    REST[REST API\nAdapter]
    CLI[CLI\nAdapter]
  end
  subgraph core[アプリケーション Core]
    IP[入力ポート\nPort] --> APP[Application\nService]
    APP --> DOM[Domain\nModel]
    APP --> OP[出力ポート\nPort]
  end
  subgraph outside_right[駆動される側 Driven]
    DB[DB\nAdapter]
    MQ[Message Queue\nAdapter]
  end

  REST --> IP
  CLI --> IP
  OP --> DB
  OP --> MQ

  style core fill:#1e1e2e,stroke:#f97316,color:#94a3b8
  style outside_left fill:#1e1e2e,stroke:#3b82f6,color:#94a3b8
  style outside_right fill:#1e1e2e,stroke:#3b82f6,color:#94a3b8
  style REST fill:#3b82f6,stroke:#1d4ed8,color:#fff
  style CLI fill:#3b82f6,stroke:#1d4ed8,color:#fff
  style IP fill:#8b5cf6,stroke:#6d28d9,color:#fff
  style APP fill:#f97316,stroke:#ea580c,color:#fff
  style DOM fill:#f97316,stroke:#ea580c,color:#fff
  style OP fill:#8b5cf6,stroke:#6d28d9,color:#fff
  style DB fill:#3b82f6,stroke:#1d4ed8,color:#fff
  style MQ fill:#3b82f6,stroke:#1d4ed8,color:#fff
ヘキサゴナルアーキテクチャ: 入力ポート(駆動する側)と出力ポート(駆動される側)を通じて外部と接続。ドメインは外部に依存しない

オニオンアーキテクチャ

2008年にJeffrey Palermoが提唱したオニオンアーキテクチャは、 ヘキサゴナルの考え方を同心円状のレイヤーとして表現し直したものです。 最内層にDomain Modelを配置し、外側に向かってDomain Services、Application Services、 そして最外層にInfrastructureとUIを配置します。

重要なルールは「依存は常に内側に向かう」ことです。 外側の層は内側の層を知っていますが、内側は外側を一切知りません。 これにより、ドメインモデルが最も安定し、インフラの変更がドメインに波及しなくなります。

クリーンアーキテクチャ

2012年にRobert C. Martin(Uncle Bob)が提唱したクリーンアーキテクチャは、 ヘキサゴナルやオニオンの原則を統合し、4つの同心円で表現したものです。

層(内側→外側) 役割 DDDとの対応
Entities ビジネスルール(最も安定) ドメインモデル(集約、エンティティ、値オブジェクト)
Use Cases アプリケーション固有のロジック アプリケーションサービス、コマンド/クエリハンドラ
Interface Adapters 外部との変換 コントローラ、プレゼンタ、ゲートウェイ
Frameworks & Drivers 外部ツール・フレームワーク DB、Web Framework、外部API

4つのパターンの比較

観点 レイヤード ヘキサゴナル オニオン クリーン
提唱者 Eric Evans (2003) Alistair Cockburn (2005) Jeffrey Palermo (2008) Robert C. Martin (2012)
依存の方向 上→下(一方向) 外→内(DIP) 外→内(DIP) 外→内(DIP)
ドメインの位置 中間層 中心 最内層 最内層(Entities)
インフラとの関係 ドメインが依存 ポート/アダプタで分離 最外層に配置 最外層に配置
テスト容易性 中程度 高い 高い 高い
学習コスト 低い 中程度 中程度 中〜高

Explicit Architecture — DDDとの統合

Herberto Gracaが提唱したExplicit Architectureは、 ヘキサゴナル・オニオン・クリーンの各パターンとDDDの戦略的・戦術的設計を 1つの実践的なフレームワークに統合したものです。

主な特徴は以下の通りです。

  • コア(内側): Application LayerとDomain Layerを明確に分離
  • ポート: Primary(駆動する側)とSecondary(駆動される側)に分類
  • アダプタ: 各ポートに対する具体的な技術実装
  • Bounded Contextごとにヘキサゴンを1つ: 戦略的設計と直接対応

推奨ディレクトリ構造

DDDとヘキサゴナルアーキテクチャを組み合わせた場合の推奨ディレクトリ構造です。 Bounded Context単位でトップレベルを分割し、各コンテキスト内でレイヤーを配置します。

src/
├── order/                    # Bounded Context: 注文
│   ├── domain/               # ドメイン層
│   │   ├── model/            #   集約、エンティティ、値オブジェクト
│   │   ├── service/          #   ドメインサービス
│   │   ├── event/            #   ドメインイベント
│   │   └── port/             #   出力ポート(リポジトリIF等)
│   ├── application/          # アプリケーション層
│   │   ├── command/          #   コマンドハンドラ
│   │   ├── query/            #   クエリハンドラ
│   │   └── port/             #   入力ポート(ユースケースIF)
│   └── infrastructure/       # インフラ層
│       ├── persistence/      #   リポジトリ実装
│       ├── messaging/        #   メッセージング実装
│       └── web/              #   コントローラ・APIルート
├── shipping/                 # Bounded Context: 配送
│   ├── domain/
│   ├── application/
│   └── infrastructure/
└── shared/                   # 共有カーネル
    └── kernel/

理解度チェック

問題 0 / 40%
Q1

ヘキサゴナルアーキテクチャ(Ports and Adapters)を提唱したのは誰ですか?

キーボード: 1〜4 で選択、Enter で回答