CQRS / ES in haskell, usando l'architettura di carta "Out of the tar pit"

2

Trovo difficile alleare CQRS / ES con l'architettura della carta "Out of tar pit".

Questa architettura implica 4 livelli:

  • Stato (stato dell'applicazione)
  • Dominio aziendale (puramente funzionale)
  • I / O
  • Controllo (tutte le cose sporche per far lavorare gli strati)

Nel mio caso, lo stato dipende in gran parte da un database.

Tenendo presente il CQRS / ES, ho un motore decisionale. Il motore decisionale per la produzione di un evento da un comando è Business Domain, che deve essere puramente funzionale.

Quando un comando richiede la creazione di un elemento, il motore decisionale sceglie di accettare o meno di creare un evento CreateItem solo se l'elemento non è già esistente (semplificato per l'esempio).

In teoria, dovrei passare lo stato dell'applicazione come argomento al dominio aziendale, in modo da decidere di conseguenza.

Ma nel caso di un database, non posso passare il database come parametro libero da effetti collaterali. Mi sento come se dovessi eseguire la query controllando in anticipo l'esistenza dell'elemento all'interno del livello di controllo e quindi passare il risultato della query sul database al dominio aziendale, che restituirà un evento o meno.

La conseguenza è che ho un codice aziendale (quello relativo alla query e la logica di business per eseguire i controlli) che si troverà nel livello di controllo.

Questo mi sembra sbagliato per quanto ho capito sul documento "Out of the tar pit" e anche su CQRS / ES.

Il problema principale mi sembra che lo stato sia enorme: è l'intero database.

Cosa c'è di sbagliato nel mio ragionamento?

    
posta Stephane Rolland 11.01.2017 - 15:27
fonte

1 risposta

7

With the CQRS/ES in mind, I have a decision engine. The decision engine for producing an event from a command, is the Business Domain, which has to be purely functional.

Bene.

When a command asks for an Item to be created, the decision engine chooses to accept or not to create an event CreateItem only if the Item is not already existing (simplified for the example).

Buono anche.

In theory, I should pass the state of the application as a argument to the Business Domain, so as to decide accordingly.

Sì, perfetto. (Nota: più "stato del dominio" che "stato dell'applicazione". ci ha insegnato che non abbiamo bisogno dello stato dell'intero dominio, basta indicare il cambiamento locale che stiamo considerando.

But in the case of a database, I cannot pass the database as a side-effect free parameter.

Esatto - tutte le interazioni con il database dovrebbero avvenire al di fuori del dominio aziendale (che si preoccupa solo dello stato).

I feel like I have to perform the query checking the existence of the item beforehand inside the Control layer, and then pass the result of the query on the database to the Business Domain, which will then return an event or not.

Ah. Non proprio - non è necessario controllare l'esistenza dell'oggetto, è necessario controllare il suo stato , che non è esattamente la stessa cosa.

Fortunatamente, stai usando ES; che rende le cose più semplici da spiegare: questa storia di un'entità che non esiste è vuota .

Quindi in questo caso: ricevi un comando da IO. Control recupera la cronologia appropriata dallo stato dell'applicazione. Il modello viene invocato passando la cronologia e il comando come argomenti. Il modello restituisce gli eventi che sono le conseguenze del comando eseguito a questo punto della cronologia. Control aggiorna la copia della cronologia nello stato dell'applicazione.

Percorso felice: arriva il comando CreateItem(x) . Comando recupera History(x) , che in questo caso è una sequenza vuota di eventi. Il modello invocato, vede dalla cronologia che l'elemento non esiste ancora e che l'invariante di business è altrimenti soddisfatto, restituisce una rappresentazione dell'evento ItemCreated(x) .

Percorso alternativo: arriva il comando CreateItem(x) . Il comando recupera History(x) , che in questo caso è una sequenza di eventi che include CreatedItem(x) . Il modello invocato, vede dalla cronologia che l'elemento è stato precedentemente creato e rifiuta il comando (genera un'eccezione, restituisce un Error , restituisce una raccolta vuota di eventi).

    
risposta data 11.01.2017 - 18:44
fonte

Leggi altre domande sui tag