Voglio capire le conseguenze di consentire ai gestori di essere fonte diretta o indiretta di nuovi eventi di dominio.
In tutti gli esempi che vedo in letteratura, gli eventi di dominio sono generalmente pubblicati da Aggregate Roots. In realtà, gli eventi possono essere appena restituiti e successivamente pubblicati prima o / e dopo l'impegno della transazione.
Consideriamo il flusso:
AR returns event
- > event is published
- > handler modifies another AR which belongs to same Bounded Context
- > modified AR produces another event
- > event is published/persisted
- > ...
- > commit (all or nothing)
.
L'invio e l'elaborazione degli eventi continuano fino a quando non si verificano nuovi eventi. (In qualche modo mi ricorda il comportamento dei trigger di database e i trigger sono odiati per cambiamenti a cascata di stato, ma per essere onesti, ritengo che la coerenza finale con tutti questi flussi di eventi e messaggi non sia più facile da ragionare.)
Ok, si può dire:
"La modifica di più AR nella stessa transazione è un'indicazione del design AR danneggiato in quanto il suo compito principale è quello di essere un limite di transazione."
Posso concordare e suggerire un altro scenario:
Immagina due requisiti:
- L'indirizzo del cliente deve essere univoco.
- (richiesto di recente). Alcuni indirizzi (non solo quelli del cliente) devono essere automaticamente sostituiti con un altro indirizzo.
Abbiamo più AR e quindi più flussi di lavoro in cui è impostato l'indirizzo. L'indirizzo è modellato come oggetto valore, è convalidato e creato da Address IAddressService.New(string address)
.
La logica della sostituzione dipende parzialmente dallo stato di AR e da uno stato esterno.
Option1.
Crea una serie di servizi di indirizzi che funzionano con un particolare tipo di AR e con la restituzione di un indirizzo coercitivo. Sfortunatamente, alcune AR richiedono che un indirizzo sia fornito come processo per la loro creazione. Significa che il servizio deve funzionare con dati "grezzi". Questa sarebbe una possibile soluzione, a meno che non avessimo bisogno di creare un evento sulla sostituzione degli indirizzi e sulla referenza AR in questo evento. È impossibile, se AR% Id
è generato dal negozio.
Opzione 2.
Adottare la coerenza finale. Salva AR così com'è, esegui la sostituzione degli indirizzi dopo il commit, forse fallisce se il vincolo univoco è rotto.
Personalmente, non ho idea di come notificare Downstream Bounded Context sull'errore quando questo BC appartiene a terze parti: fanno semplicemente una chiamata all'endpoint HTTP e si aspettano il successo o l'insuccesso.
Opzione 3.
Consenti al gestore di modificare l'indirizzo in AR. L'intero flusso è:
AR is created
- > event is handled by the handler which checks for uniqueness of address
, poi same event is handled by new handler, and it changes AR's address
+ emits new event AddressSubstituted about performed substitution
- > AR emits a regular AddressChanged event
- > check for uniqueness is done once again
, but no need for substitution this time
- > no new events are emitted
- > commit
- > Id is assigned to AR
- > publish/persist AddressSubstituted event
(questo evento ha un riferimento ad AR, quindi quando si pubblica / persistente, Id ha già un valore valido).
Si noti che tutte le parti critiche vengono eseguite nella stessa transazione. Handler produce un evento stesso AddressSubstituted
e conduce indirettamente a un altro evento - AddressChanged
.
AddressSubstituted
è pubblicato fuori dalla transazione, tuttavia è ancora possibile salvare tutto nella stessa transazione. Il nucleo EF è una vera bestia intelligente. In caso di relazioni configurate determinerà l'ordine di persistenza e salverà innanzitutto AR, quindi utilizzerà Id
per il salvataggio. EF può anche generare automaticamente Guid
quando AR viene aggiunto a DbContext (ma ancora dopo che AR è stato creato).
Vale la pena ricordare che l'ordine di esecuzione dei gestori di eventi può o non può essere importante, ma è un argomento separato per la discussione.
Professionisti di questa soluzione: - Il vecchio codice non viene quasi toccato, basta sviluppare nuovi gestori. - Atomicita. Il chiamante viene immediatamente informato sullo stato dell'operazione. - L'intenzione del cambiamento viene catturata.
Contro:
- Estremamente difficile ragionare sul flusso (presumo).
- La generazione di eventi potrebbe non finire mai a causa di qualche strano loop non rivoluzionario creato dal gestore.
- <your items here>
Trovo che questo approccio sia legittimo, ma potrei mancare qualcosa di molto importante qui. Poiché non l'ho mai incontrato, chiamiamolo - exhaustive event dispatching
prima, sono in dubbio.