Estou adaptando o design orientado a domínio há cerca de 8 anos e, mesmo depois de todos esses anos, ainda há uma coisa que me incomoda. Isso está verificando um registro exclusivo no armazenamento de dados em um objeto de domínio.
Em setembro de 2013, Martin Fowler mencionou o princípio TellDon'tAsk , que, se possível, deve ser aplicado a todos os objetos de domínio, que devem retornar uma mensagem, como foi a operação (no design orientado a objetos, isso é feito principalmente por meio de exceções, quando a operação não teve êxito).
Meus projetos geralmente são divididos em várias partes, onde dois deles são Domínio (contendo regras de negócios e nada mais, o domínio ignora completamente a persistência) e Serviços. Serviços que conhecem a camada de repositório usada para dados CRUD.
Como a exclusividade de um atributo pertencente a um objeto é uma regra de domínio / negócio, ele deve demorar muito para o módulo de domínio, portanto, a regra está exatamente onde deveria estar.
Para poder verificar a exclusividade de um registro, você precisa consultar o conjunto de dados atual, geralmente um banco de dados, para descobrir se outro registro com digamos que Name
já existe.
Considerando que a camada de domínio é persistente e ignorante e não tem idéia de como recuperar os dados, mas apenas como executar operações neles, ela não pode realmente tocar os próprios repositórios.
O design que eu tenho adaptado fica assim:
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();
}
}
Isso faz com que os serviços definam as regras de domínio em vez da própria camada de domínio e você tenha as regras espalhadas por várias seções do seu código.
Mencionei o princípio TellDon'tAsk, porque, como você pode ver claramente, o serviço oferece uma ação (ele salva Product
ou lança uma exceção), mas dentro do método você está operando objetos usando a abordagem procedural.
A solução óbvia é criar uma Domain.ProductCollection
classe com um Add(Domain.Product)
método lançando o ProductWithSKUAlreadyExistsException
, mas está com um desempenho muito baixo, porque você precisaria obter todos os produtos do armazenamento de dados para descobrir no código se um produto já tem o mesmo SKU como o produto que você está tentando adicionar.
Como vocês resolvem esse problema específico? Isso não é realmente um problema em si, tive a camada de serviço que representa certas regras de domínio há anos. A camada de serviço geralmente também serve operações de domínio mais complexas. Estou simplesmente me perguntando se você encontrou uma solução melhor e mais centralizada durante sua carreira.