Mi sto immergendo nei concetti di Domain-Driven Design (DDD) e ho trovato alcuni principi strani, soprattutto per quanto riguarda l'isolamento del modello di dominio e persistenza. Ecco la mia comprensione di base:
- Un servizio sul livello applicazione (che fornisce un set di funzionalità) richiede gli oggetti del dominio da un repository di cui ha bisogno per svolgere la sua funzione.
- L'implementazione concreta di questo repository recupera i dati dall'archiviazione implementata per
- Il servizio indica all'oggetto dominio, che incapsula la logica aziendale, di eseguire determinati compiti che ne modificano lo stato.
- Il servizio indica al repository di mantenere l'oggetto dominio modificato.
- Il repository deve mappare l'oggetto dominio alla corrispondente rappresentazione in archivio.
Ora,dateleipotesidicuisopra,ilseguentesembrastrano:
Annuncio2.:
Ilmodellodidominiosembracaricarel'interooggettodeldominio(compresituttiicampieiriferimenti),anchesenonsononecessariperlafunzionecheloharichiesto.Ilcaricamentocompletopotrebbenonesserenemmenopossibilesesifariferimentoadaltrioggettididominio,amenochenonsicarichianchequestioggettidominioetuttiglioggettiacuifannoriferimentoaturno,ecosìviaecosìvia.Vieneinmenteuncaricamentolento,ilchesignificatuttaviacheiniziaeseguirequerysuglioggettideltuodominiochedovrebberoesserelaresponsabilitàdelrepositoryinprimoluogo.
Datoquestoproblema,ilmodo"corretto" di caricare oggetti di dominio sembra avere una funzione di caricamento dedicata per ogni caso d'uso. Queste funzioni dedicate caricheranno quindi solo i dati richiesti dal caso d'uso per il quale sono stati progettati. Qui è dove entra in gioco l'imbarazzo: in primo luogo, dovrei mantenere una notevole quantità di funzioni di caricamento per ogni implementazione del repository, e gli oggetti di dominio finirebbero in stati incompleti che trasportano null
nei loro campi. Quest'ultimo dovrebbe tecnicamente non essere un problema perché se un valore non è stato caricato, non dovrebbe essere richiesto dalla funzionalità che lo richiedeva comunque. Eppure è imbarazzante e potenzialmente pericoloso.
Annuncio 3.:
In che modo un oggetto di dominio verifica i vincoli di unicità alla costruzione se non ha alcuna nozione del repository? Ad esempio, se volessi creare un nuovo User
con un numero di previdenza sociale univoco (che è dato), il conflitto più antico si verificherebbe chiedendo al repository di salvare l'oggetto, solo se è stato definito un vincolo di univocità sul database . Altrimenti, potrei cercare un User
con la sicurezza sociale fornita e segnalare un errore nel caso esista, prima di crearne uno nuovo. Ma poi i controlli dei vincoli sarebbero presenti nel servizio e non nell'oggetto di dominio a cui appartengono. Mi sono appena reso conto che gli oggetti di dominio sono molto ben autorizzati a utilizzare repository (iniettati) per la convalida.
Annuncio 5.:
Percepisco la mappatura degli oggetti di dominio su un back-end di storage come un processo ad alta intensità di lavoro rispetto a quando gli oggetti di dominio modificano direttamente i dati di underlaying. È, ovviamente, un prerequisito essenziale per disaccoppiare l'implementazione dello storage concreto dal codice di dominio. Tuttavia, ha davvero un costo così alto?
A quanto pare hai la possibilità di usare gli strumenti ORM per fare la mappatura per te. Ciò richiederebbe spesso di progettare il modello di dominio in base alle restrizioni dell'ORM, tuttavia, o addirittura di introdurre una dipendenza dal dominio al livello infrastruttura (utilizzando, ad esempio, le annotazioni ORM negli oggetti dominio). Inoltre ho letto che gli ORM introducono un considerevole overhead computazionale.
Nel caso di database NoSQL, per i quali non esistono praticamente concetti simili a ORM, come tenere traccia delle proprietà modificate nei modelli di dominio su save()
?
Modifica : Inoltre, affinché un repository possa accedere allo stato dell'oggetto dominio (cioè il valore di ogni campo), l'oggetto dominio deve rivelare il suo stato interno che interrompe l'incapsulamento.
In generale:
- Dove andrebbe la logica transazionale? Questa è certamente persistenza specifico. Alcune infrastrutture di storage potrebbero non supportare nemmeno transazioni (come i depositi fittizi in memoria).
- Per le operazioni di massa che modificano più oggetti, dovrei caricare, modificare e archiviare ogni oggetto singolarmente per passare attraverso la logica di validazione incapsulata dell'oggetto? Questo è contrario all'esecuzione di una singola query direttamente sul database.
Gradirei qualche chiarimento su questo argomento. Le mie supposizioni sono corrette? In caso contrario, qual è il modo corretto di affrontare questi problemi?