Come devono essere gestiti i comandi Aggiungi / Crea * nell'architettura CQRS + Event Sourcing


11

Voglio implementare la mia prima applicazione usando il modello CQRS insieme a Event Sourcing. Mi chiedo come gestire correttamente la creazione di radici aggregate. Diciamo che qualcuno invia il comando CreateItem. Come dovrebbe essere gestito? Dove deve essere archiviato l'evento ItemCreated? Come primo evento di un nuovo oggetto? O dovrei avere una sorta di entità ItemList che aggrega tutti gli elementi e il suo elenco di eventi è costituito solo da eventi ItemCreated?

Udi Dahan suggerisce di non creare radici aggregate e di utilizzare sempre una sorta di metodo di recupero. Ma come posso recuperare qualcosa di nuovo e che sicuramente non ha alcun ID assegnato. Capisco l'idea alla base ed è abbastanza ragionevole pensare che un nuovo oggetto sia un oggetto il cui stato è composto da zero eventi replicati su di esso. Ma come dovrei usarlo? Dovrei avere un metodo distinto nel mio repository come getNewItem()o far get(id)accettare Optional<ItemId>invece il mio metodo ?

Modifica: dopo un po 'di scavo ho trovato l' implementazione davvero interessante dei modelli di cui sopra usando gli attori. L'autore invece di creare l'aggregato, lo recupera da una sorta di repository con l'UUID appena creato. Lo svantaggio di questo approccio è che consente uno stato di incoerenza temporanea. Mi chiedo anche come posso implementare il deletemetodo con tale approccio. È sufficiente aggiungere un evento eliminato all'elenco eventi dell'aggregato?


1
Sospetto che il post-titolo di Udi sia fuorviante. Secondo me, il suo vero obiettivo è che gli AR appena fatti dovrebbero essere sempre raggiungibili da qualche altra parte, in un modo che catturi il contesto sul perché / come / chi ha deciso che il nuovo AR doveva essere creato. Tutto il resto riguarda il modo in cui una particolare implementazione (NHibernate?) Potrebbe semplificarne la gestione.
Darien,

2
Si noti che l'articolo di Udi Dahan a cui si fa riferimento in particolare afferma che il suo consiglio potrebbe non essere applicabile all'acquisizione di eventi: udidahan.com/2009/06/29/dont-create-aggregate-roots/…
EZ Hart

Risposte:


13

L'idea nel post di Udi, come ho capito, è che nessun tipo di oggetto appare dal nulla. C'è (quasi) sempre qualcosa, o più specificamente, qualche operazione di dominio, che ha causato la creazione dell'elemento. Proprio come nell'esempio di Udi di un utente nato da un visitatore che si registra al sito. A quel punto e in quel contesto limitato, il Visitatore è la radice aggregata, che viene recuperata dal suo indirizzo IP. Questo Visitatore crea quindi il nuovo "elemento", un utente a questo punto, tramite un'operazione di dominio chiamata Register . Lo stesso vale per il passaggio precedente, che è un altro contesto limitato: Referrer è l'AR, che viene recuperato dall'URL e che ha un'operazione di dominio chiamata BroughtVisitorWithIp , dove nasce il visitatore.

Udi scrive molto bene anche sulla cancellazione: http://www.udidahan.com/2009/09/01/dont-delete-just-dont/ . L'idea principale è che non si elimina mai nulla. C'è sempre un'operazione di dominio dietro, che vogliamo catturare. Come se un ordine venisse cancellato, piuttosto che cancellato. Leggi, è un ottimo post.

Il punto principale qui su entrambi gli account, facendo DDD e soprattutto Event Sourcing, è che non dovresti mai fare operazioni CRUD diritte. Se ti trovi in ​​una situazione in cui devi semplicemente inserire, aggiornare o eliminare alcuni dati e non c'è davvero alcuna operazione di dominio dietro di esso, allora forse DDD ed Event Sourcing non sono adatti per quel contesto limitato . Sei libero di combinare questi due come desideri finché un singolo contesto limitato aderisce a un principio. In questo modo il contesto limitato in stile CRUD potrebbe creare una riga nel database, che diventa un'entità e una radice aggregata in un altro contesto limitato, dove ora è possibile recuperare l'AR e non è necessario crearlo.


2
"forse DDD e Event Sourcing non sono adatti per quel contesto limitato." Hai capito bene il punto di DDD. Non dovrebbe essere implementato in ogni caso solo per la gloria di Satana, ma solo quando si ha a che fare con un dominio complesso pieno di regole incerte. Personalmente l'ho fatto per software legale in cui i requisiti non sono guidati dalla logica.
Yegor Chumakov,

2
+1 solo per questa frase "per quel contesto limitato". :)
Songo,

2
+1 l'uso dei verbi 'Aggiungi' e 'Crea' è fortemente indicativo del fatto che stai ancora pensando al tuo dominio in termini di interazione con un buon vecchio database tabulare. Senza conoscere il tuo dominio / contesto limitato non posso dire se sia appropriato o meno. Ignora la persistenza, concentrati prima sui COMANDI e sugli EVENTI (ovvero le INTENZIONI e i RISULTATI) che sono unici per il tuo dominio, quindi preoccupati di come mantenere lo stato, che è un problema che è stato risolto centinaia di migliaia di volte in precedenza.
Matt

"l'uso dei verbi 'Aggiungi' e 'Crea' è fortemente indicativo del fatto che stai ancora pensando al tuo dominio in termini di interazione con un buon vecchio database tabulare" Hmmm. Quando hai un design dell'interfaccia utente che ha un grande pulsante 'Aggiungi qualcosa', allora, purtroppo, questa è l'intenzione; letteralmente per aggiungere qualcosa di nuovo. Sono generalmente d'accordo con te, ma non stiamo parlando a livello di database qui, a volte Aggiungi o Crea sono in realtà le parole giuste da usare.
designermonkey,

1
@designermonkey Quando hai questi pulsanti nell'interfaccia utente, hai davvero un'operazione di dominio dietro di loro? Forse, ma 9 volte su 10 non è davvero necessaria un'operazione di dominio complessa in quel contesto limitato. E la pura operazione CRUD è proprio questa, una pura operazione CRUD, e dovrebbe essere gestita come tale. Solo quando è necessaria la complessità del modello di dominio, dovrebbe essere utilizzato. Quindi i diversi contesti limitati con diversi principi di progettazione.
Tuukka Haapaniemi,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.