Sto adattando il design guidato dal dominio da circa 8 anni e anche dopo tutti questi anni, c'è ancora una cosa che mi ha infastidito. Ciò sta verificando la presenza di un record univoco nella memorizzazione dei dati su un oggetto dominio.
Nel settembre 2013 Martin Fowler ha menzionato il principio TellDon'tAsk , che, se possibile, dovrebbe essere applicato a tutti gli oggetti di dominio, che dovrebbe quindi restituire un messaggio, come è andata l'operazione (nella progettazione orientata agli oggetti questo è fatto principalmente attraverso eccezioni, quando l'operazione non è andata a buon fine).
I miei progetti sono generalmente divisi in molte parti, in cui due sono Dominio (contenente regole aziendali e nient'altro, il dominio è completamente ignaro della persistenza) e Servizi. Servizi a conoscenza del livello di repository utilizzato per i dati CRUD.
Poiché l'unicità di un attributo appartenente a un oggetto è una regola di dominio / business, dovrebbe essere lungo il modulo di dominio, quindi la regola è esattamente dove dovrebbe essere.
Per poter verificare l'unicità di un record, è necessario eseguire una query sul set di dati corrente, in genere un database, per scoprire se Name
esiste già un altro record con un diciamo .
Considerando che il livello di dominio ignora la persistenza e non ha idea di come recuperare i dati ma solo come eseguire operazioni su di essi, non può davvero toccare i repository stessi.
Il design che ho adattato appare in questo modo:
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();
}
}
Questo porta ad avere servizi che definiscono le regole di dominio anziché il livello di dominio stesso e che le regole sono distribuite su più sezioni del codice.
Ho citato il principio TellDon'tAsk, perché come puoi vedere chiaramente, il servizio offre un'azione (salva Product
o genera un'eccezione), ma all'interno del metodo stai operando sugli oggetti attraverso l'approccio procedurale.
La soluzione ovvia è quella di creare una Domain.ProductCollection
classe con un Add(Domain.Product)
metodo che lancia ProductWithSKUAlreadyExistsException
, ma è molto carente in termini di prestazioni, perché sarebbe necessario ottenere tutti i prodotti dall'archiviazione dei dati per scoprire nel codice, se un prodotto ha già lo stesso SKU come prodotto che stai tentando di aggiungere.
Come risolvete questo problema specifico? Questo non è davvero un problema di per sé, ho avuto livello di servizio che rappresentano alcune regole di dominio per anni. Il livello di servizio di solito serve anche operazioni di dominio più complesse, mi chiedo semplicemente se ti sei imbattuto in una soluzione migliore, più centralizzata, durante la tua carriera.