Ho adattato il design basato sul dominio per circa 8 anni e anche dopo tutti questi anni, c'è ancora una cosa che mi ha infastidito. Questo è il controllo di un record univoco nell'archiviazione dei dati rispetto a un oggetto dominio.
Nel settembre 2013 Martin Fowler ha citato il principio TellDon't Ask , che, se possibile, dovrebbe essere applicato a tutti i domini oggetti, che dovrebbero quindi restituire un messaggio, come è andata l'operazione (nella progettazione orientata agli oggetti questo avviene principalmente attraverso eccezioni, quando l'operazione non ha avuto successo).
I miei progetti sono solitamente divisi in molte parti, in cui due sono Dominio (contenente regole aziendali e nient'altro, il dominio è completamente persistente-ignorante) e Servizi. Servizi che conoscono il livello del repository utilizzato per i dati CRUD.
Poiché l'unicità di un attributo appartenente a un oggetto è una regola dominio / aziendale, dovrebbe essere lunga per il modulo dominio, quindi la regola è esattamente dove dovrebbe essere.
Per essere in grado di verificare l'unicità di un record, è necessario interrogare il set di dati corrente, di solito un database, per scoprire se esiste già un altro record con diciamo Name
.
Considerare il livello del dominio è la persistenza ignorante e non ha idea di come recuperare i dati, ma solo come fare operazioni su di essi, non può davvero toccare i repository stessi.
Il design che ho adattato si presenta così:
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 piuttosto che lo stesso livello del dominio e hai le regole sparse su più sezioni del tuo codice.
Ho menzionato il principio TellDon'tAsk, perché come puoi vedere chiaramente, il servizio offre un'azione (salva il Product
o genera un'eccezione), ma all'interno del metodo sei operativo sugli oggetti usando l'approccio procedurale .
La soluzione ovvia è creare una classe Domain.ProductCollection
con un metodo Add(Domain.Product)
che lancia il ProductWithSKUAlreadyExistsException
, ma è carente in termini di prestazioni, perché è necessario ottenere tutti i prodotti dall'archiviazione dei dati per trovare nel codice, se un prodotto ha già la stessa SKU del prodotto che si sta tentando di aggiungere.
Come risolvete questo problema specifico? Questo non è davvero un problema in sé, ho avuto il livello di servizio che rappresenta alcune regole di dominio per anni. Il livello di servizio di solito serve anche operazioni di dominio più complesse, mi sto semplicemente chiedendo se ti sei imbattuto in una soluzione migliore, più centralizzata, durante la tua carriera.