J'adapte la conception basée sur le domaine depuis environ 8 ans maintenant et même après toutes ces années, il y a encore une chose qui me dérange. Cela vérifie un enregistrement unique dans le stockage de données par rapport à un objet de domaine.
En septembre 2013, Martin Fowler a mentionné le principe TellDon'tAsk , qui, si possible, devrait être appliqué à tous les objets de domaine, qui devrait ensuite renvoyer un message, comment l'opération s'est déroulée (dans la conception orientée objet, cela se fait principalement par le biais d'exceptions, lorsque l'opération a échoué).
Mes projets sont généralement divisés en plusieurs parties, dont deux sont le domaine (contenant des règles métier et rien d'autre, le domaine est complètement ignorant de la persistance) et les services. Services connaissant la couche de référentiel utilisée pour les données CRUD.
Étant donné que l'unicité d'un attribut appartenant à un objet est une règle de domaine / métier, le module de domaine doit être long, de sorte que la règle est exactement là où elle est censée se trouver.
Afin de pouvoir vérifier l'unicité d'un enregistrement, vous devez interroger l'ensemble de données actuel, généralement une base de données, pour savoir si un autre enregistrement avec un disons Name
existe déjà.
Considérant que la couche de domaine est ignorante de la persistance et n'a aucune idée de comment récupérer les données mais seulement comment effectuer des opérations sur elles, elle ne peut pas vraiment toucher les référentiels eux-mêmes.
Le design que j'ai ensuite adapté ressemble à ceci:
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();
}
}
Cela conduit à avoir des services définissant les règles de domaine plutôt que la couche de domaine elle-même et vous avez les règles dispersées sur plusieurs sections de votre code.
J'ai mentionné le principe TellDon'tAsk, car comme vous pouvez le voir clairement, le service propose une action (il enregistre Product
ou lève une exception), mais à l'intérieur de la méthode, vous opérez sur des objets en utilisant une approche procédurale.
La solution évidente est de créer une Domain.ProductCollection
classe avec une Add(Domain.Product)
méthode lançant le ProductWithSKUAlreadyExistsException
, mais cela manque beaucoup de performances, car vous auriez besoin d'obtenir tous les produits du stockage de données afin de savoir dans le code, si un produit a déjà le même SKU comme le produit que vous essayez d'ajouter.
Comment résolvez-vous ce problème spécifique? Ce n'est pas vraiment un problème en soi, la couche de service représente certaines règles de domaine depuis des années. La couche de service sert généralement également des opérations de domaine plus complexes, je me demande simplement si vous êtes tombé sur une solution meilleure et plus centralisée au cours de votre carrière.