注意;この記事は裏付けのないポエムです。
---
title: クリーンアーキテクチャとドメイン駆動設計の矛盾ない実践
description: |
近頃の生成AIの発展は凄まじいですね!
なんか使ってみたくて、今回は掲題の件について尋ねてみました。
なお私はこの件に無知です。教えてもらおうというスタンスです。
統合層マッピングのくだりが、たしかにするよねっ!と意識的になれて面白かったです。
---
プロンプトざっくり;
> Answer in Japanese.
> 名著「クリーンアーキテクチャ」について詳細に述べよ。マークダウンに保存。Think hard.
> 名著「ドメイン駆動設計」について詳細に述べよ。マークダウンに保存。Think hard.
> 二つのマークダウンを統合して実践することは可能か? 矛盾は何か? Think hard.
> 要約を冒頭に挟め。計画を提示
> マークダウンに保存。Pls
そのあと手で修正
クリーンアーキテクチャとドメイン駆動設計の矛盾ない実践は可能である。
両者は異なる次元の問題を扱うため論理的矛盾はないが、
しかし実践上は緊張点が存在し、無批判に両方を適用すると混乱する。
つまり「自動的に統合される」わけではない。意識的な統合設計が必要である。
以下は実践上生じる緊張点:
- 用語の混乱: エンティティ、サービスなどの用語が異なる意味で使われる
- 責務の配置: ドメインサービスをどこに置くか、ユースケースとの境界はどこか
- 層の粒度: CAは4層、DDDは4層だが対応が曖昧
- 設計の優先順位: DDDはドメインモデル優先、CAは依存構造優先
そこで、両者を併用するベストプラクティス(具体的実践)として以下の統合指針を提案する:
- 層のマッピングを明示的に定義する
- 用語を統一する
- 責務の境界を明確にする(特にユースケース vs ドメインサービス)
- チームで共通理解を形成する(本文書の目的)
統合の指針(および統合層マッピング・統合用語ルール)
- 以下を統合した実践のための指針とする
-
Clean Architectureで全体構造を設計する
- 依存性ルールに従い層を分離する
- 内側の層が外側を知らないようにする
-
DDDでドメイン層(エンティティ層・ユースケース層の一部)を設計する
- 集約でトランザクション境界を定義する
- 値オブジェクトで概念を明確化する
- リポジトリのインターフェースをドメイン層に置く
-
境界づけられたコンテキストをモジュール境界とする
- 各コンテキストがClean Architectureの層構造を持つ
- コンテキスト間は腐敗防止層で連携する
統合層マッピング(統合アーキテクチャ)
═══════════════════════════════════════════════════════════════
【最内層】エンティティ/ドメインモデル層
└─ DDDパターン適用
├─ エンティティ(識別子を持つ)
├─ 値オブジェクト(不変)
├─ 集約(整合性境界)
└─ ドメインサービス(ドメインルールのみ)
───────────────────────────────────────────────────────────────
【第2層】ユースケース/アプリケーション層
└─ 処理フローの調整
├─ リポジトリインターフェース定義
├─ 外部サービスインターフェース定義
└─ アプリケーションサービス(ユースケース実行)
───────────────────────────────────────────────────────────────
【第3層】インターフェース・アダプター層
└─ データ形式変換
├─ コントローラー(入力変換)
├─ プレゼンター(出力変換)
├─ リポジトリ実装(ドメイン↔永続化変換)
└─ 腐敗防止層(外部システム変換)
───────────────────────────────────────────────────────────────
【最外層】フレームワーク&ドライバ層
└─ 技術的詳細
├─ Webフレームワーク
├─ データベースドライバ
└─ 外部API接続
═══════════════════════════════════════════════════════════════
統合用語ルール
| 使用する用語 | 意味 | 避ける曖昧さ |
|---|---|---|
| ドメインエンティティ | DDDの識別子を持つオブジェクト | 「エンティティ」単体で使わない |
| ドメインモデル層 | CAのエンティティ層 + DDDの戦術的パターン | 層の名前を明示する |
| アプリケーションサービス | CAのユースケース | 「サービス」単体で使わない |
| ドメインサービス | ドメインルールのみ担う | 処理調整はアプリケーションサービスへ |
以上
解説
以下で両者の本質的な違い、緊張点の詳細分析、統合のための指針を解説する。
- 両者の本質的な違い(関心の次元・スケールの違い、補完関係(図解))
- 緊張点の詳細分析(4つの緊張点と解決策)
- したがって緊張点から導き出された両者の補完関係
両者の本質的な違い - 関心の次元が異なる
| 次元 | Clean Architecture | DDD |
|---|---|---|
| 問い | 依存関係をどう制御するか | ドメインをどう表現するか |
| 価値 | 技術的詳細からの独立 | ビジネスとコードの一致 |
| 成果物 | 層構造・依存性ルール | コンテキストマップ |
| コンテキスト毎ドメインモデル | ||
| コンテキスト毎ユビキタス言語 |
- これらは異なる問いに答えているため、論理的に矛盾しない(いわば直交する概念である)
両者の本質的な違い - マクロとミクロで取り扱うスケールが異なる
| 観点 | Clean Architecture | DDD |
|---|---|---|
| 主な関心 | システム全体の層構造と依存方向 | ドメインモデルの内部構造 |
| スコープ | アプリケーション全体 | 境界づけられたコンテキスト内 |
| 提供するもの | 層間の依存性ルール | ドメイン層の構築パターン |
- 両者は入れ子構造として機能する
- Clean Architectureの「エンティティ層」の中身を DDDのパターンで構築するのが
実践上の統合方法である。
緊張点の詳細分析(4つの緊張点と解決策)
1. レイヤー構造の不一致
両者とも4層だが、1対1対応しない。
Clean Architecture(CA) DDD
──────────────────── ──────────────────────────
エンティティ層 インフラストラクチャ層
ユースケース層 ←?→ ドメイン層
インターフェース・アダプター層 ←?→ アプリケーション層
フレームワーク&ドライバ層 UI層
問題: CAのどの層に DDDのドメイン層が対応するか?
- CAの「エンティティ層」は「全社的ビジネスルール」
- DDDの「ドメイン層」には集約・ドメインサービス・リポジトリインターフェースが含まれる
解決: DDDのドメイン層は、CAの「エンティティ層」と「ユースケース層の一部」に
またがると解釈する。
2. ユースケース vs ドメインサービス の境界
CAではユースケースがエンティティへのデータの流れを調整・指揮する。
DDDではドメインサービスは複数の集約にまたがる操作を実行し、ドメイン層に属する。
緊張点: 複数の集約を操作する処理は、ドメインサービスか?ユースケースか?
例: 銀行の送金処理「口座Aから口座Bへ1万円移動する」
- ドメインサービス?(送金はドメインの概念だから)
- ユースケース?(複数集約の調整だから)
解決策:
| 責務 | 所属 | 例 |
|---|---|---|
| ドメインルールの判定 | ドメインサービス | 送金可否の判定、手数料計算 |
| 処理フローの調整 | ユースケース | 残高確認→引落→入金→通知の順序制御 |
3. トランザクション境界の所有者
CAにはトランザクションの明示的な言及がない。
DDDでは集約への変更はアトミックなトランザクションとして扱われるべきとされる。
緊張点: 複数集約をまたぐトランザクションは誰が制御するか?
解決策:
- 単一集約の整合性 → 集約自身が保証
- 複数集約の調整 → ユースケースが結果整合性またはSagaパターンで制御
4. リポジトリ実装の配置
CAではゲートウェイはインターフェース・アダプター層に含まれる。
DDDではインターフェースはドメイン層、実装はインフラストラクチャ層に配置される。
問題: CAのどこ? = DDDのインフラストラクチャ層
DDDの視点 CAの視点
リポジトリ
├─ Interface → ドメイン層 → ユースケース層(定義)
└─ Impl → インフラストラクチャ層 → アダプター層 or ドライバ層?
解決策:
- リポジトリ実装の「変換ロジック」→ インターフェース・アダプター層
- リポジトリ実装の「DB接続詳細」→ フレームワーク&ドライバ層
緊張点から導き出された両者の補完関係のまとめ
Clean Architectureの層構造
│
├── エンティティ層 ───────────┬─── DDDの戦術的パターンが適用される領域
│ └── 全社的ビジネスルール │ ・エンティティ
│ │ ・値オブジェクト
├── ユースケース層 ───────────┤ ・集約
│ └── アプリ固有のルール │ ・ドメインサービス
│ │ ・ドメインイベント
│
├── インターフェース・アダプター層
│ └── コントローラー/プレゼンター/ゲートウェイ
│
└── フレームワーク&ドライバ層
└── DB/Web/外部サービス ←── リポジトリの実装がここに配置
END