Possono i gestori di eventi di dominio portare a nuovi eventi?

1

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.

    
posta Pavel Voronin 12.11.2018 - 03:02
fonte

2 risposte

3

DDD è una metodologia design e non ha nulla da dire sulla gestione delle transazioni al di fuori del dominio. In termini di DDD, il "confine transazionale" è inteso nel senso che un'entità è la sola, autorevole e non ambigua rappresentazione del suo stato. Ciò significa semplicemente che un'entità "possiede" i suoi dati e in realtà non ha nulla a che fare con le transazioni del database.

Il motivo per cui molti sostengono che cambiare solo una transazione di aggregazione per database ha a che fare con il ridimensionamento. Ovviamente, come qualsiasi altra decisione sul design, questo comporta dei compromessi. La modifica di più aggregati in una singola transazione di database significa che non si ha a che fare con la coerenza finale al costo di non essere in grado di frammentare il sistema. Il fatto che il vantaggio valga o meno il costo è una funzione dei requisiti del tuo sistema e dovrebbe essere considerato attentamente dai tuoi stakeholder. Questo non deve essere una decisione "tutto o niente".

Per quanto riguarda gli eventi di dominio, di nuovo rappresentano un compromesso. Uno degli obiettivi principali di DDD è "rendere esplicito implicito". Eventi di dominio funzionano contro questa idea introducendo l'accoppiamento implicito. Ciò può comportare un po 'di complessità aggiuntiva e ridurre la coesione di un sistema. In altre parole, vedo spesso eventi di dominio introdotti in un sistema per compensare la scarsa progettazione. Cioè, invece di prendersi la cura di modellare il dominio in base al comportamento e ai vettori di cambiamento, una complessa rete di eventi di dominio viene truccata insieme ad hoc per soddisfare i requisiti aziendali. Come sottolineo astutamente, l'intero scopo della modellazione degli aggregati è quello di riunire i dati che cambiano insieme. Se ciò non accade, possiamo dare un'occhiata a un altro principio di DDD per aiutarci a guidare: il refactoring continuo.

Gli eventi di dominio sono utilizzati al meglio per attivare processi ortogonali (asincroni) come l'invio di un messaggio di posta elettronica quando viene generato un evento CustomerRegistered , NON semplicemente mantenendo lo stato sincronizzato. In questo modo, non sono come i trigger di database. Non andrei così lontano da dire che non c'è alcuna situazione in cui gli eventi di dominio debbano essere usati per mantenere lo stato in sincrono, ma è importante capire i compromessi e stare sempre alla ricerca di un approccio alternativo.

Per quanto riguarda il tuo problema di esempio. È un po 'troppo vago e complicato per affrontare (dovevo). Si legge come un problema inventato all'indietro data una premessa difettosa. Ovviamente, partendo da un design scadente o non modificando il progetto per soddisfare i "requisiti introdotti di recente" si creano problemi lungo la strada. Nella tua spiegazione citi un numero di Servizi / Aggregati che sembrano solo creare il problema che stai delineando. Perché progettare un sistema che ha un problema? Inizia con i requisiti. ALLORA modella il sistema attorno a loro.

I sistemi non sono progettati per soddisfare i requisiti futuri. Sono progettati per soddisfare i requisiti attuali e, si spera, sono progettati in base ai principi che li rendono facili da modificare in modo che quando emergano nuovi requisiti, possono essere rapidamente integrati nel sistema. Questo è l'intero scopo di DDD!

    
risposta data 12.11.2018 - 20:55
fonte
1

Tocca su un numero di problemi diversi.

  1. Che cos'è un evento di dominio invece di un evento?

  2. Devo impegnarmi prima o dopo aver sollevato eventi di dominio?

  3. Gli eventi dovrebbero attivare altri eventi?

Prendiamo per primo quello facile. 3. Ovviamente la natura degli eventi è tale da innescarne un'altra, ma ovviamente questo può portare a loop infiniti e comportamenti difficili da tracciare.

Dobbiamo essere consapevoli di tutti gli eventi in un sistema quando cambiamo i gestori di eventi in modo da evitare problemi.

2 è un problema senza soluzione. Ancora una volta la natura di un evento è che qualsiasi cosa può potenzialmente essere innescata da esso. Questi effetti possono facilmente essere al di fuori dell'ambito di una transazione di database. ad esempio l'invio di una e-mail.

Quindi, se voglio potenzialmente riscrivere la storia eseguendo il rollback di una transazione, devo salvare la pubblicazione dell'evento fino a dopo il commit ..

OR! limita i listener di eventi a cose che verranno anche ripristinate dalla transazione.

Questo ci porta esattamente a 1. Sfortunatamente la definizione di Domain Event sembra piuttosto vaga. Le persone lo usano per significare inter AR - comunicazione non transazionale, comunicazione intra AR, nonché un trampolino di lancio verso Event Sourcing e ogni sorta di roba.

Chiaramente sarebbe bello avere una definizione tale da poter dire "Tutti gli eventi di dominio dovrebbero essere pubblicati dopo il commit dell'AR!" o "Gli eventi di dominio NON DEVONO innescare altri eventi !!" o viceversa.

Consente di limitare gli eventi di dominio alle seguenti regole.

  • Deve essere solo emmitato da AR
  • Deve essere ascoltato solo da altri domini
  • Deve essere l'unico tipo di cosa che i domini ascoltano.

Quindi possiamo iniziare a fare questo tipo di chiamate.

A. Possiamo tranquillamente rimandare la pubblicazione fino a quando le transazioni sono state commesse.

B. Dobbiamo usare eventi "normali" per fare cose all'interno della transazione.

C. Gli eventi normali possono attivare altri eventi normali ed essere sicuri all'interno della transazione / transazione

D. Gli eventi di dominio possono attivare altri eventi di dominio, ma gli effetti sono sempre al di fuori della transazione.

Questo risolve in modo preciso il problema di sostituzione degli indirizzi in quanto l'evento AddressChanged è un evento di dominio e si verifica solo quando si commette l'indirizzo modificato

La sostituzione degli indirizzi deve avvenire all'interno dell'AR prima del commit, quindi puoi eseguire in cascata normali eventi AR da esso, ma qualsiasi evento di dominio che attiva blocca la cascata fino a dopo il commit, dandoti un limite portata a cui pensare.

    
risposta data 12.11.2018 - 08:55
fonte

Leggi altre domande sui tag