C#中級

中級 C#で学ぶクリーンアーキテクチャ|アンチパターン編

導入

クリーンアーキテクチャは、ソフトウェア設計において高い柔軟性と保守性を実現するための原則を提供します。しかし、実際の開発現場では、これらの原則を正しく適用できないケースが多々あります。本記事では、C#を用いてクリーンアーキテクチャのアンチパターンに焦点を当て、具体的なシナリオを通じてその落とし穴と改善策を探ります。

教科書レベルの解説(クリーンアーキテクチャ)

重要な概念の整理

クリーンアーキテクチャは、アプリケーションの構造を層に分け、依存関係を逆転させることを重視します。具体的には、ビジネスロジックが外部の影響を受けないように設計されており、テストの容易さや再利用性を高めることが目的です。層は通常、エンティティ、ユースケース、インターフェースアダプタ、フレームワークといった形で構成されます。

コード例(C#)


public interface IProductRepository
{
    Product GetProductById(int id);
    void AddProduct(Product product);
}

public class ProductService
{
    private readonly IProductRepository _productRepository;

    public ProductService(IProductRepository productRepository)
    {
        _productRepository = productRepository;
    }

    public void CreateProduct(string name)
    {
        var product = new Product { Name = name };
        _productRepository.AddProduct(product);
    }
}

コードの行ごとの解説

  1. IProductRepositoryインターフェースは、製品データの取得と追加に関するメソッドを定義しています。
  2. ProductServiceクラスは、IProductRepositoryを依存性注入で受け取り、ビジネスロジックを実装しています。
  3. CreateProductメソッドは、新しい製品を作成し、リポジトリを通じて保存します。

アンチパターン編

実務においてよく見られるアンチパターンの一つは、リポジトリの実装がビジネスロジックを持つケースです。以下のコードは、その典型的な例です。


public class ProductRepository : IProductRepository
{
    public Product GetProductById(int id)
    {
        // データベースから製品を取得
    }

    public void AddProduct(Product product)
    {
        // データベースに製品を追加
        if (product.Name == null)
        {
            throw new ArgumentException("Product name cannot be null");
        }
    }
}

この実装の問題点は、AddProductメソッド内でビジネスルール(製品名がnullでないこと)をチェックしている点です。リポジトリはデータアクセスの責任を持つべきであり、ビジネスロジックを含むべきではありません。これにより、リポジトリが変更されるたびに、ビジネスロジックのテストも影響を受けてしまいます。

改善策として、ビジネスロジックをProductServiceに移動させることが考えられます。これにより、リポジトリは純粋なデータ操作に専念し、ビジネスロジックはサービス層で管理されることになります。


public class ProductService
{
    private readonly IProductRepository _productRepository;

    public ProductService(IProductRepository productRepository)
    {
        _productRepository = productRepository;
    }

    public void CreateProduct(string name)
    {
        if (string.IsNullOrEmpty(name))
        {
            throw new ArgumentException("Product name cannot be null or empty");
        }

        var product = new Product { Name = name };
        _productRepository.AddProduct(product);
    }
}

まとめ

  • リポジトリはデータアクセスに特化し、ビジネスロジックを含めないように設計することが重要です。
  • ビジネスロジックはサービス層で管理し、各層の責任を明確に分けることがクリーンアーキテクチャの基本です。