貧血ドメインモデル

ドメインオブジェクトがデータのみを持ち、ビジネスロジックが外部のサービスに散在するアンチパターン

DDD品質

貧血ドメインモデルとは

貧血ドメインモデル (Anemic Domain Model) は、Martin Fowler が指摘したアンチパターンで、ドメインオブジェクトがデータ (プロパティ) のみを持ち、ビジネスロジックが外部のサービスクラスに散在する設計である。

貧血 vs リッチドメインモデル

// ❌ 貧血ドメインモデル: Order はデータだけ
class Order {
  id: string;
  items: OrderItem[];
  status: string;
  totalAmount: number;
}

// ロジックが外部サービスに散在
class OrderService {
  cancel(order: Order) {
    if (order.status !== 'pending') throw new Error('Cannot cancel');
    order.status = 'cancelled';
    order.totalAmount = 0;
  }
  addItem(order: Order, item: OrderItem) {
    order.items.push(item);
    order.totalAmount = order.items.reduce((sum, i) => sum + i.price, 0);
  }
}
// ✅ リッチドメインモデル: Order がロジックを持つ
class Order {
  private constructor(
    readonly id: string,
    private items: OrderItem[],
    private status: OrderStatus,
  ) {}

  cancel() {
    if (this.status !== 'pending') throw new Error('Cannot cancel');
    this.status = 'cancelled';
  }

  addItem(item: OrderItem) {
    if (this.status !== 'pending') throw new Error('Cannot modify');
    this.items.push(item);
  }

  get totalAmount(): number {
    return this.items.reduce((sum, i) => sum + i.price, 0);
  }
}

なぜ問題か

問題 説明
ロジックの散在 同じドメインのルールが複数のサービスに分散
不変条件の破壊 外部から直接プロパティを変更でき、不正な状態になる
重複 同じバリデーションが複数箇所に書かれる
テストの困難さ サービスの依存関係が複雑

なぜ発生するか

  • データベースのテーブル構造をそのままクラスにマッピング (ORM の影響)
  • 手続き型プログラミングの習慣
  • 「モデルはデータ、サービスはロジック」という誤った分離

Lambda での現実的な判断

Lambda の単純な CRUD 関数では、リッチドメインモデルが過剰な場合がある。

ケース 推奨
複雑なビジネスルール リッチドメインモデル
単純な CRUD 貧血でも問題ない
バリデーションが多い リッチドメインモデル
1 関数で完結 貧血でも問題ない

基礎から学ぶなら関連書籍が手がかりになる。

関連用語