🩺
貧血ドメインモデルを診断・修正するスキル
コードを見て「業務ロジックがドメインに収まっているか」を判断し、漏れているロジックをドメインオブジェクトに戻す手順
目的
コードを見て「業務ロジックがドメインに収まっているか」を素早く診断し、漏れているものをドメインオブジェクトに戻す。
診断手順
1. サービス層のif文を探す
// 🚨 サービス層にif文がある → 業務ロジックが漏れているサイン
func (s *OrderService) PlaceOrder(...) error {
if len(order.Items()) == 0 { // ← ドメインルール
return errors.New("商品がない")
}
if order.Status() != "DRAFT" { // ← ドメインルール
return errors.New("確定済み")
}
}
2. ドメインオブジェクトのgetterだけが呼ばれていないかを確認する
// 🚨 getterで値を取り出して外で判断している
if order.GetStatus() == "DRAFT" && order.GetTotalAmount() > 0 {
order.SetStatus("PLACED") // setterで状態を直接書き換えている
}
getter/setterだけのオブジェクトは「データ置き場」。業務ロジックが外に漏れている。
3. 同じ判断が複数のサービスに重複していないかを確認する
// 🚨 PlaceOrderServiceにも
if order.Status() != "DRAFT" { return err }
// 🚨 UpdateOrderServiceにも
if order.Status() != "DRAFT" { return err }
重複は「ドメインルールがドメインに収まっていない」証拠。
修正手順
Step 1: 漏れているルールを特定する
サービス層のif文を読んで「これは業務のルールか?」を問う。
「商品がない注文は確定できない」→ YES、業務のルール → Orderへ
「cmd.OrderID == ""」 → NO、入力検証 → コマンドオブジェクトへ
「HasPermission(ctx, ...)」 → NO、認証 → ミドルウェアへ
Step 2: ドメインオブジェクトにメソッドを追加する
// Before: サービス層にロジックがある
func (s *OrderService) PlaceOrder(...) error {
if len(order.Items()) == 0 {
return errors.New("商品がない")
}
if order.status != "DRAFT" {
return errors.New("確定済み")
}
order.status = "PLACED"
}
// After: ロジックをOrderに移す
func (o *Order) Place() error {
if len(o.items) == 0 {
return ErrNoItems
}
if o.status != Draft {
return ErrAlreadyPlaced
}
o.status = Placed
return nil
}
Step 3: サービス層を薄くする
// After: サービス層はオーケストレーションだけ
func (s *OrderService) PlaceOrder(...) error {
order, _ := s.repo.FindByID(cmd.OrderID)
if err := order.Place(); err != nil {
return err
}
return s.repo.Save(order)
}
診断チェックリスト
コードレビュー時に使う
- サービス層に
if entity.GetXxx() == "..."が書かれていないか - ドメインオブジェクトに getter/setter しかなく、メソッドがないか
- 同じ業務判断が複数のサービスに重複していないか
-
entity.SetStatus("PLACED")のように状態を外から直接書き換えていないか - ドメインオブジェクトのメソッドを呼んだだけでルールが保証されるか
関連概念
- 1. 🔍集約の境界を見つけるスキル
- 2. 🩺貧血ドメインモデルを診断・修正するスキル
- 3. 🗺️コンテキストマップを描くスキル
- 4. 🔲境界づけられたコンテキスト
- 5. 🗺️サブドメイン(コア・サポート・汎用)
- 6. 🗾コンテキストマップ
- 7. ⬡六角形アーキテクチャ(ポートとアダプター)
- 8. 🪪エンティティ(Entity)
- 9. ⚙️ドメインサービス(Domain Service)
- 10. 💎値オブジェクト(Value Object)- IDDD
- 11. 📣ドメインイベント(Domain Event)
- 12. 🫧集約(Aggregate)
- 13. 📐集約の設計原則(Vernon の4ルール)
- 14. 🗄️リポジトリ(Repository)
- 15. 🏭ファクトリ(Factory)
- 16. 📦モジュール(Module)
- 17. 🎛️アプリケーションサービス(Application Service)
- 18. 🔌境界づけられたコンテキストの統合
- 19. ⚡CQRS(コマンドクエリ責任分離)
- 20. 📜イベントソーシング(Event Sourcing)
- 21. 🩸貧血ドメインモデル(Anemic Domain Model)
- 22. 🪶アプリケーションサービスを薄く保つ
出典: 実践ドメイン駆動設計(Vaughn Vernon)第1章