Iniziamo con una breve discussione su Entità, Aggregate Root, Value Objects e identità in quanto una certa confusione qui sembra essere un grande contributo al tuo problema.
Le entità sono oggetti che hanno un concettuale ciclo di vita (da non confondere con un ciclo di vita dell'oggetto). A causa del suddetto comportamento concettuale , ci deve essere un modo per distinguere l'uno dall'altro. Come è fatto è puramente un dettaglio di implementazione del sistema. Spesso, poiché un RDBMS viene scelto come backing store per il sistema, Entities conterrà un attributo arbitrario Id
che consente al sistema di distinguere l'uno dall'altro. In altri casi, può esistere una chiave naturale (attraverso uno o più attributi in combinazione). Ma ancora, in che modo due entità sono distinte è un dettaglio di implementazione.
I Roots aggregati sono semplicemente Entità che richiedono ad altre Entity di far valere i loro invarianti. Per questo motivo, devono incapsulare l'accesso / la modifica a quelle altre Entità per coerenza transazionale. Dal "fuori" non vi è alcuna differenza (e spesso nessuna caratteristica distintiva) tra un'entità e una radice aggregata. Un cliente di un sistema non deve sapere se sta lavorando con un'entità o una radice di aggregazione.
Questo ci porta a Value Objects. Un oggetto valore non ha un'identità concettuale , nessun ciclo di vita e può, pertanto, essere creato e distrutto con facilità. Quanto sopra non significa un Oggetto Valore non ha un'identità fisica (una chiave primaria nei termini RDBMS), piuttosto che questa identità è nascosta dal tuo dominio. Dopo tutto, potrebbe comunque essere necessario memorizzare / correlare i dati per scopi di normalizzazione.
Da quanto sopra ora possiamo vedere che è il comportamento di un oggetto che lo classifica come Entity o Value Object, non alcune analisi dei dati che l'oggetto contiene (dettagli di implementazione). Ad esempio, Address
è l'esempio per eccellenza di un oggetto dominio che confonde spesso gli sviluppatori sul fatto che debba essere trattato come oggetto valore o entità. Dopo tutto, l'intero punto di un Address
deve essere unico, giusto? Per questo motivo, Address
verrà spesso considerato come oggetto (tabella) dal backing store e semplicemente correlato a Persons
(o qualsiasi altra cosa) secondo necessità (più Persons
può condividere il stesso Address
giusto?). Questa decisione di implementazione è dove inizia la confusione. Sebbene esista un identificatore univoco per ogni Address
, ancora deve essere trattato come un oggetto valore. Quando Person
cambia il loro Address
, non modifichiamo nessun campo, noi li assegniamo semplicemente uno nuovo (dal nostro elenco di Addresses
).
Ora che qui abbiamo trattato alcuni aspetti di ciò che costituisce ciascuno di questi elementi costitutivi, vediamo come si applicano al tuo oggetto Race
. Il tuo concetto di Race
ha un ciclo di vita? Probabilmente no. Dovrebbe essere un oggetto valore. Indipendentemente dal fatto che si possa o meno distinguere da altri Races
è irrilevante.
La vera domanda qui è perché più domini devono conoscere queste informazioni? Cercando di unire insieme alcuni sistemi di Domain Events (ad esempio ProviderChangedRace
) per mantenere le informazioni coerenti in più contesti, si crea un bel po 'di complessità aggiuntiva e punti di errore.
La pietra miliare del DDD è che i sistemi sono progettati attorno al comportamento (non ai dati), e spesso è un modello carente che crea questo tipo di imbarazzo, non una regola tecnica mancante /dettaglio. C'è un modo per organizzare il tuo sistema in modo tale che ogni oggetto che ha bisogno di usare Race
possa essere refactored in una singola Entity / Aggregate? Modificando il tuo sistema in modo che l'oggetto che usa Race
sia lo stesso oggetto che modifica Races
disponibile, puoi evitare completamente molti dei problemi sollevati nella tua domanda. Ad esempio, il tuo Provider
potrebbe essere caricato con Races
disponibile e Race
scelto. Ora aggiungendo nuove opzioni e facendo nuove scelte sono accoppiati in un unico confine transazionale dove l'applicazione di invarianti è banale. In una nota simile, non si "fa" la convalida su Provider
, a Provider
dovrebbe essere valida se stessa.
Capisco che ci possono essere più pezzi per questo puzzle, ma il refactoring per una comprensione più profonda è qualcosa che dovrebbe essere considerato qui. Prova a trovare un modo per "affettare" i tuoi dati verticalmente in modo da riunire comportamento .