ddd-anti-patterns について
ddd-anti-patterns は、ドメインモデルのレビューやリファクタリングに使う DDD のリファレンススキルです。よくある設計上の問題、その症状と理由をまとめ、修正の参考となる関連パターンスキルを示します。
主な機能
- 01一般的な DDD アンチパターン集
- 02各問題の症状と理由
- 03関連パターンスキルへのリンク
- 04リファクタリング対象の判断基準
- 05DDD の過剰適用を避ける指針
活用シーン
- 01コードレビューでのドメインモデルの問題発見
- 02見つかった問題をもとにした修正方針の選定
- 03チームメンバーへの DDD の注意点の説明
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ yonatankarp/ software-design-skills --skill ddd-anti-patternsインストール後、Claude Code で/ddd-anti-patternsを入力して読み込まれたか確認します。
詳細
1 行での概要
よく見られる DDD のアンチパターンをまとめたリファレンスカタログです。それぞれに症状と、解決方法を説明するパターンスキルへのリンクが含まれています。
このスキルを使う場面
- コードレビューのウォークスルー(
ddd-reviewは指摘ごとにこのカタログを参照します)。 - リファクタリング中にコードの臭いを見つけるとき(
ddd-refactorはこのカタログを、コードの臭いから目指す形を調べるために使います)。 - 「これは本当に DDD なのか、それともパターン名を使った CRUD にすぎないのか」を議論するとき。
- チームメイトのオンボーディング — 避けるべきものをまとめた単一のページです。
このスキルを使わない場面
- どのパターンを適用すべきかすでに分かっている場合 — そのパターンに直接進んでください。
- 問いが「何を」構築するかであり、「何を構築しないか」ではない場合 →
ddd-designを使ってください。
主な内容
カタログです。各項目には、名前、症状、問題である理由、解決方法が記載されています。
貧血ドメインモデル。 エンティティがデータの入れ物になっており、フィールドとゲッター、セッターはあるものの、振る舞いがありません。ロジックはすべて *Service クラスにあります。モデルにドメイン知識がなく、サービスが DTO に対するトランザクションスクリプトになってしまうため、問題です。解決方法:振る舞いをエンティティに持たせます。ddd-entity、ddd-domain-service を参照してください。
プリミティブ型への執着。 ドメインの概念を、String、Long、BigDecimal などのプリミティブ型で表現しています — String customerId、Long amount、String currency。不変条件が保証されず、同じプリミティブ型を共有する異なる概念が相互に置き換え可能になり、処理が静的ヘルパーに散在するため、問題です。解決方法:値オブジェクトを抽出します。ddd-value-object を参照してください。
巨大なアグリゲート。 モデルの半分を所有するアグリゲートが 1 つあります。症状:読み込み時に数百行が取得され、ロック競合が急増し、トランザクションが扱いにくくなります。アグリゲートの境界はトランザクションの境界であるべきなので、問題です。解決方法:一緒に変更する必要があるものを基準に分割します。ddd-aggregate を参照してください。
永続化層が漏れ出すリポジトリ。 リポジトリが永続化関連の型(Query、Predicate、EntityManager、フレームワークの JpaRepository)を公開しています。ドメイン層が永続化の関心事に依存し、単独でテストできなくなるため、問題です。解決方法:ドメイン層のインターフェースにはドメインの言葉でメソッドを定義し、インフラストラクチャ層で実装します。ddd-repository を参照してください。
DDD を装ったトランザクションスクリプト。 データ DTO に対する手続き型ロジックでいっぱいのサービスがあり、クラス名は *Manager、*Helper、*Processor です。実際のドメイン層がなく、名前が DDD であるかのような錯覚を生むため、問題です。解決方法:振る舞いをエンティティに持たせます。*Service は、本当にステートレスで、複数のアグリゲートにまたがる場合にのみ使います。ddd-domain-service を参照してください。
スマート UI。 ビジネスルールがコントローラー、ビュー、またはフロントエンドのコードに埋め込まれています。「ドメイン」とは、たまたまデータベースにあるものです。ルールにアクセスできるのが UI に限られるため、問題です。解決方法:実際のドメイン層を抽出します。ddd-design を参照してください。
泥団子。 境界がまったくありません。あらゆるものが、あらゆるものにアクセスします。変更箇所を局所化できなくなるため、問題です。解決方法:まずコンテキストマップを描きます。腐敗防止層を介して泥団子と連携し、それを拡張しないでください。ddd-bounded-context、ddd-context-mapping を参照してください。
アグリゲート間のオブジェクト参照。 Order が Customer の オブジェクト 参照を保持しています(ID のみではありません)。これによって遅延読み込みが強制され、2 つのアグリゲートのライフサイクルが結び付けられ、トランザクション境界が崩れるため、問題です。解決方法:ID を保持し、必要なときにリポジトリ経由で検索します。ddd-aggregate を参照してください。
Manager / Service / Helper の接尾辞症候群。 OrderManager、PaymentHelper、AccountProcessor のような名前は、ドメインの動詞を技術的なノイズの背後に隠してしまいます。コードにはユビキタス言語が反映されているべきなので、問題です。解決方法:ビジネスで使われる動詞に基づいて名前を付けます。ddd-ubiquitous-language、ddd-domain-service を参照してください。
判断のヒューリスティクス
- 臭いを特定できても、目指すパターンを挙げられない場合、問題は実在しますが、解決策は明確ではありません。チームで話し合い、まず目指す形を決めてからリファクタリングしてください。
- 深刻度は影響範囲に比例します。10 個の呼び出し元に影響する漏れのある抽象化は、同じ漏れが 1 か所にある場合よりも問題です。
- 一部のアンチパターンは、汎用サブドメインでは許容されます(設定テーブルに対する CRUD に豊かなモデルは必要ありません)。DDD の手続きを一律に適用しないでください。
ddd-subdomain-classificationを参照してください。
アンチパターンに関するアンチパターン
- 長いクラスをすべて貧血モデルと見なすこと。貧血モデルは長さではなく、振る舞いに関するものです。
- 目的への適合性ではなく、パターンを使うこと自体を目的としてパターンを追い求めること。
- 教科書どおりの構成と一致しないという理由で、正常に動作し、十分にテストされたコードを「誤り」と呼ぶこと。
ManagerをServiceに改名して、リファクタリングと呼ぶこと。
関連項目
ddd-coreのすべてのパターンスキル。それぞれの臭いは、そのうち 1 つ以上に関連付けられています。ddd-review— このカタログをチェックリストとして使用します。ddd-refactor— このカタログを、臭いから目標への参照表として使用します。
参考文献
- Evans、『Domain-Driven Design』(2003 年)、第 II 部および第 III 部。
- Fowler、『Anemic Domain Model』(2003 年のエッセイ)— このアンチパターンを定義した代表的な文献です。