C#中級

中級 C#で学ぶドメイン駆動設計|アンチパターン編

導入

ドメイン駆動設計(DDD)は、ソフトウェア開発においてビジネスの複雑さを管理するための強力な手法です。しかし、実際のプロジェクトでは、設計の意図を誤解したり、実装時に不適切な選択をすることがよくあります。特に中級者以上のエンジニアが直面する「アンチパターン」は、プロジェクトの成功を脅かす要因となり得ます。本記事では、C#を用いた具体的なシナリオを通じて、ドメイン駆動設計におけるアンチパターンを探ります。

教科書レベルの解説(ドメイン駆動設計)

重要な概念の整理

ドメイン駆動設計は、ビジネスドメインの複雑さを解消するために、ドメインモデルを中心に据えたアプローチです。ドメインモデルは、ビジネスのルールやプロセスを反映したオブジェクトの集合であり、開発者とビジネス側が共通の理解を持つための基盤となります。DDDの目的は、システムの設計と実装がビジネスの要件に密接に結びつくようにすることです。

コード例(C#)


public class Order
{
    public Guid Id { get; private set; }
    public List Items { get; private set; }

    public Order(Guid id)
    {
        Id = id;
        Items = new List();
    }

    public void AddItem(OrderItem item)
    {
        Items.Add(item);
    }

    public decimal CalculateTotal()
    {
        return Items.Sum(item => item.Price);
    }
}

public class OrderItem
{
    public string ProductName { get; }
    public decimal Price { get; }

    public OrderItem(string productName, decimal price)
    {
        ProductName = productName;
        Price = price;
    }
}

コードの行ごとの解説

  1. Orderクラス: 注文を表すエンティティ。注文IDとアイテムのリストを持つ。
  2. AddItemメソッド: 注文にアイテムを追加するためのメソッド。
  3. CalculateTotalメソッド: 注文の合計金額を計算する。
  4. OrderItemクラス: 注文内のアイテムを表す値オブジェクト。商品名と価格を持つ。

アンチパターン編

ドメイン駆動設計において、しばしば見られるアンチパターンの一つが「アナemicドメインモデル」です。これは、ドメインモデルがデータを保持するだけで、ビジネスロジックを持たない状態を指します。たとえば、以下のような実装が考えられます。


public class Order
{
    public Guid Id { get; set; }
    public List Items { get; set; }

    public decimal CalculateTotal()
    {
        return Items.Sum(item => item.Price);
    }
}

このコードは一見正しく見えますが、Orderクラスが持つべき責任を分散させています。特に、データの保持とビジネスロジックが混在しているため、メンテナンス性が低下します。理想的な設計では、ロジックはエンティティ内にカプセル化され、外部からの直接アクセスを制限すべきです。

改善策として、Orderクラスのコンストラクタでアイテムを初期化し、アイテムを追加するメソッドを持たせることが有効です。また、CalculateTotalメソッドはエンティティの一部として保持することで、責任の一貫性を保つことができます。

まとめ

  • アナemicドメインモデルは、データとロジックの分離によるメンテナンス性の低下を招く。
  • ビジネスロジックはドメインモデル内にカプセル化し、外部からのアクセスを制限することが重要。
  • ドメイン駆動設計の原則に従い、エンティティの責任を明確にすることで、より堅牢な設計が実現できる。