私はドメイン駆動設計を約8年間適応してきましたが、これらすべての年が経過した後でも、まだ1つ問題があります。それは、ドメインオブジェクトに対してデータストレージ内の一意のレコードをチェックしています。
2013年9月、Martin Fowlerは、可能であればすべてのドメインオブジェクトに適用する必要があるTellDon'tAsk原則について言及し、操作がどのように行われたかをメッセージで返します(オブジェクト指向の設計では、これはほとんど例外によって行われます)。操作は失敗しました)。
私のプロジェクトは通常多くの部分に分かれており、そのうちの2つはドメイン(ビジネスルールのみを含み、ドメインは完全に永続性を無視する)とサービスです。データをCRUDするために使用されるリポジトリレイヤーを認識するサービス。
オブジェクトに属している属性の一意性はドメイン/ビジネスルールであるため、ドメインモジュールにとっては長くなければならないため、ルールは本来あるべき場所にあります。
レコードの一意性を確認できるようにするには、現在のデータセット(通常はデータベース)にクエリを実行して、別のレコードName
が存在するかどうかを確認する必要があります。
ドメインレイヤーは永続性を無視しており、データを取得する方法がわからないだけでなく、データを操作する方法しか考慮していないため、リポジトリ自体に直接触れることはできません。
私が適応させたデザインは次のようになります。
class ProductRepository
{
// throws Repository.RecordNotFoundException
public Product GetBySKU(string sku);
}
class ProductCrudService
{
private ProductRepository pr;
public ProductCrudService(ProductRepository repository)
{
pr = repository;
}
public void SaveProduct(Domain.Product product)
{
try {
pr.GetBySKU(product.SKU);
throw Service.ProductWithSKUAlreadyExistsException("msg");
} catch (Repository.RecordNotFoundException e) {
// suppress/log exception
}
pr.MarkFresh(product);
pr.ProcessChanges();
}
}
これにより、ドメインレイヤー自体ではなくサービスがドメインルールを定義し、コードの複数のセクションにルールが分散されます。
明確にわかるように、サービスはアクションを提供するので(それはを保存するProduct
か、例外をスローします)、TellDon'tAskの原則について述べましたが、メソッド内では、手続き型のアプローチを使用してオブジェクトを操作しています。
明白な解決策は、をスローDomain.ProductCollection
するAdd(Domain.Product)
メソッドを使用してクラスを作成するProductWithSKUAlreadyExistsException
ことですが、コード内で製品がすでに同じSKUを持っているかどうかを確認するには、データストレージからすべての製品を取得する必要があるため、パフォーマンスが大幅に不足しています追加しようとしている製品として。
この特定の問題をどのように解決しますか?これ自体は問題ではありません。何年もの間、特定のドメインルールを表すサービスレイヤーを用意してきました。サービス層は通常、より複雑なドメイン操作にも対応します。キャリアの中で、より優れた、より集中化されたソリューションに出くわしたのではないかと思います。