Come creare una nuova radice aggregata in CQRS?

11

Come dovremmo creare nuove radici aggregate nell'architettura cqrs? In questo esempio voglio creare una nuova radice aggregata AR2 che contenga il riferimento al primo AR1.

Sto creando AR2 usando il metodo AR1 come punto di partenza. Finora vedo poche opzioni:

  1. Metodo interno in AR1 createAr2RootOpt1 Potrei chiamare new AR2() e salvare questo oggetto in db imediatelly utilizzando il servizio di dominio che ha accesso al repository.
  2. Potrei emettere un evento nella prima radice aggregata es. SholdCreateAR2Event e poi avere saga senza stato che reagisce su questo ed emette il comando CreateAR2Command che viene poi gestito e in realtà crea AR2 ed emette AR2CreatedEvent . In caso di utilizzo dell'output di eventi SholdCreateAR2Event non verrebbe mantenuto nell'archivio eventi, poiché non influisce sullo stato della prima radice aggregata. (O dovremmo ancora salvarlo nell'archivio degli eventi?)

    class AR1{
        Integer id;
        DomainService ds;
    
        //OPTION 1
        void createAr2RootOpt1(){
            AR2 ar2 = new AR2();
            ds.saveToRepo(ar2);
        }
    
        //OPTION 2
        void createAr2RootOpt2(){
            publishEvent(new SholdCreateAR2Event());    //we don't need this event. Shoud it still be preserved in event store?
        }
    }
    
    class AR2{
        Integer id;
        Integer ar1Id;
    
        void handle(CreateAR2Command command){
            //init this AR with values and save
            publishEvent(AR2CreatedEvent());    //used for projections afterwards and saved inside AR2 event store
        }
    }
    
    class Saga{
        void handle(SholdCreateAR2Event ev){
            emitCommand(new CreateAR2Command());
        }
    }
    

Quale è il modo più corretto per farlo?

    
posta bojanv55 21.02.2017 - 13:20
fonte

2 risposte

2

Penso che l'opzione no. 2 è la soluzione, con una modifica piccola ma importante: AR1 non dovrebbe emettere un evento il cui scopo è creare AR2 , invece dovrebbe emettere un evento AR1WasCreated . Questo evento deve essere persistente nell'archivio eventi, in quanto è un evento importante che segna la nascita di AR1 . Quindi, un Saga che dovrebbe listent per AR1WasCreated event e generare un comando per creare AR2 : CreateAR2Command .

L'opzione numero 1 è molto errata. Non dovresti mai iniettare quel tipo di servizio di dominio in Aggregate . Aggregates dovrebbe essere puro, senza effetti collaterali diversi dalla generazione di eventi.

P.S. Non emetto mai eventi dal costruttore di Aggregate in quanto vi è una distinzione tra la creazione di un'istanza di un oggetto (nel senso del linguaggio di programmazione) e la creazione (la nascita se si desidera) di un Aggregate . Emetto eventi solo da un metodo handle (quando si gestisce un command ).

    
risposta data 21.02.2017 - 17:08
fonte
2

How should we create new aggregate roots in cqrs architecture?

I pattern di creazione sono bizzarri .

Udi Dahan ha alcune cose utili da dire sul problema generale: Do not Create Aggregate radici . Il punto di base è che gli aggregati non saltano fuori dal nulla e che esiste un linguaggio di dominio che descrive come appaiono, che dovrebbe essere catturato nel tuo modello di dominio.

Dove tende a essere distorto è che l'entità nel modello di dominio che sta elaborando il comando è non l'entità che viene modificata dalla transazione. Non è sbagliato; è solo strano (rispetto ai casi in cui chiedi a un'entità di modificarsi.

Anche il tuo secondo approccio è OK. "Gli eventi che generiamo senza salvare effettivamente nel database" vengono a volte definiti "eventi del dominio"

L'idea di base è che, all'interno della stessa transazione, il gestore comandi solleva l'evento, che viaggia lungo il bus verso un gestore di eventi che consente al secondo aggregato di creare se stesso. Puoi ottenere una coesione del codice un po 'migliore, forse.

Nota: nei sistemi basati su eventi, di solito non usi gli eventi in questo modo.

In case of using event sourcing ShouldCreateAR2Event would not be preserved in event store, since it does not affect the state of first aggregate root.

Nota: i nomi degli eventi sono di solito al passato - ShouldCrateAR2 ha l'ortografia sbagliata.

Sì, se stai solo lanciando un evento sul bus sincrono per eseguire il codice remoto, non dovresti salvare quell'evento nel libro dei record. È solo un dettaglio di implementazione a questa scala.

Or should we still save this in event store?

Evita di modificare due diversi flussi di eventi nella stessa transazione. Se questa creazione rappresenta anche una modifica ad AR1, la solita risposta sarebbe quella di modificare AR1 in questa transazione, con un sottoscrittore asincrono a quegli eventi che è responsabile per l'attivazione del comando per creare AR2.

La gestione dei comandi idempotent aiuta molto qui.

    
risposta data 24.02.2017 - 16:51
fonte