Event Sourcing e cross Aggregate validation

1

Sto cercando Event Sourcing (ES) e gioco con il codice Greg Young messo insieme ( Greg Young Git Repo ).

Mi piace ciò che ES offre in termini di funzionalità, ma sto cercando di applicarlo alla mia conoscenza di un dominio problematico specifico. La maggior parte delle applicazioni su cui ho lavorato si basano sulla memorizzazione di tutti i dati come stato. Tipicamente applicazioni CRUD e un sacco di DDD di ritardo - praticamente in un back-end di SQL Server.

Vedo molti esempi di ordini d'acquisto e articoli d'ordine per ES, che sono esempi piuttosto semplicistici - sebbene nel mio mondo degli ordini d'acquisto abbiamo domini molto più complessi - dove ci sono tutti i tipi di regole. Mentre questi sono un ottimo punto di partenza, vorrei ampliare il mio orizzonte su scenari di dominio leggermente più complessi.

Quindi per testare ES nel mio ipotetico problema, supponiamo di avere il seguente scenario semplificato in cui:

Aggregato 1 - Configurazione aziendale

L'aggregato 1 è configurato come una relazione gruppo / oggetto, ad esempio:

Group 1 (Aggregate1Group)
    Item 1 (Aggregate1Item)
    Item 2 (Aggregate1Item)
Group 2 (Aggregate1Group)
    Item 3 (Aggregate1Item)
    Item 4 (Aggregate1Item)

Questo è in genere uno dei compiti che l'utente potrebbe eseguire, ma nulla rimane mai in questo modo!

Aggregato 2 - Set di regole aziendali

Aggregate2 è praticamente un insieme di regole indipendenti. Gli intervalli di regole aziendali configurati dall'utente vengono utilizzati all'interno di Aggregate3, ma richiedono un "riferimento" al gruppo Aggregato1.

BusinessRule1 (BusinessRule)
    Min: 0
    Max: 100
    Aggregate1Group: Group 1

BusinessRule2 (BusinessRule)
    Min: 200
    Max: 300
    Aggregate1Group: Group 2

Aggregato 3 - Enforcing Rules

Aggregazione3 richiede all'utente di selezionare un elemento e selezionare un valore, che sarebbe implementato con il seguente metodo:

void Aggregate3.BookThisIn(int value, Aggregate1Item item, string someIrrevantInfo)
{ 
    bool allowed = BusinessRules.Any(b => value >= b.Min && value <= b.Max && b.Aggregate1Group.Contains(item));

    if (allowed)
    {
        IrrelevantInfo.Add(someIrrevantInfo);

        // raise events
        Events.Add(new IrrelevantInfoAddedEvent(...));
    }
}

Quindi in pratica, se il valore è compreso tra la regola aziendale Min e Max e l'elemento specificato si trova all'interno del gruppo di regole aziendali, è possibile registrare le informazioni irrilevanti.

Scenari ipotetici e domande

Quindi supponiamo che siano accaduti i seguenti eventi:

  1. Gruppi e articoli creati dall'utente secondo Aggregazione 1 - Configurazione aziendale
  2. Regole aziendali create dall'utente secondo Aggregate 2 - Set di regole aziendali
  3. User BookThisIn per il valore di 50 e Aggregate1Item dell'elemento 1 con alcuniIrrevantInfo di "Some Test"

Tutti i dati del dominio sono in uno stato valido finora ... O è?

Ora l'utente decide di aver sbagliato la configurazione. Aggregate1Item "Item 1" appartiene effettivamente a Aggregate1Group "Group 2". Dato che, i dati inseriti nel passaggio 3 sono ora di fatto errati.

Potenzialmente, i dati potrebbero essere storicamente corretti in altri casi, in cui tutti i dati attuali sono ritenuti corretti al momento in cui si verificano gli eventi.

Quindi, nel caso di un database SQL basato sullo stato, è possibile esaminare qualsiasi entità memorizzata nell'elenco IrrelevantInfo (che si assocerebbe a una tabella, ad esempio IrrelevantInfos) e si potrebbe consentire all'utente di risolvere i problemi all'interno di un'interfaccia utente.

Ma in un sistema basato su eventi, come giocherebbe questo scenario di invalidazione e come potresti fornire le informazioni all'utente per la risoluzione? Quali modelli ES offre per superare questi ostacoli?

    
posta Andez 10.01.2018 - 23:58
fonte

1 risposta

2

Quello che hai qui è la convalida interglobale, possibilmente anche il contesto interlacciato. Questo non è un tipo di convalida eseguita all'interno di un singolo Aggregate, quindi questo codice && b.Aggregate1Group.Contains(item) all'interno di Aggregate3 non è consentito e deve essere spostato all'interno di un servizio di dominio, ovvero DS1 (il nome è molto importante in DDD quindi dargli un nome appropriato).

Puoi chiamare DS1 nella tua Application service , prima della chiamata a Aggregate3 se vuoi ridurre al minimo il tempo in cui il sistema come una buca entrerà in uno stato non valido. Tieni presente che la chiamata di DS1 non rientra in Aggregate3 , quindi non è strongmente coerente con Aggregate3 .

Tuttavia, come già notato, gli utenti cambieranno idea sullo stato del gruppo Aggregate1 in modo che il sistema inserisca uno stato non valido (un aggregato mai immette uno stato non valido, per definizione).

La risposta a questo problema è stata risolta da un gestore di Saga / Process . Quindi devi creare una Saga che chiama DS1 . Se rileva uno stato non valido, la Saga esegue le azioni richieste. Che azione è che dipende dal tuo sistema. Potrebbe inviare un'email a qualcuno, mostrando una notifica sull'interfaccia utente, inviando un comando a un altro aggregato o a quanto sopra. La Saga può avere servizi iniettati in modo che possano avere effetti collaterali.

L'individuazione degli eventi facilita l'invocazione della Saga: la Saga si iscrive agli eventi di dominio pertinenti. Inoltre, ES rende il rilevamento dello stato non valido il prima possibile (in genere millisecondi, a seconda dell'infrastruttura).

Quindi, la risposta è data da DDD, l'individuazione degli eventi semplifica l'implementazione.

    
risposta data 11.01.2018 - 07:59
fonte

Leggi altre domande sui tag