But, what if one of the events should cause an external system not in your control to "ship an item" to the customer if you just replay the events the item would be shipped twice.
Per scegliere un esempio specifico, consideriamo come potrebbe funzionare un approccio "almeno una volta" agli effetti collaterali.
State currentState = State.InitialState
for(Event e : events) {
currentState = currentState.apply(e)
}
for(SideEffect s : currentState.querySideEffects()) {
performSideEffect(s)
Quindi il modello di dominio tiene traccia di ciò che deve essere fatto; ma lascia il fare effettivo all'applicazione
Nel contesto dell'esecuzione di un comando, l'idea di base è la stessa. Gli effetti collaterali effettivi si verificano fuori della transazione che aggiorna il modello.
Quindi l'unit test per il tuo modello potrebbe sembrare qualcosa di simile
{
// Given
State currentState = State.InitialState
// When
Events events = List.of(OrderPlaced)
// Then
List.of(SendEmail) === currentState.applyAll(events).querySideEffects()
}
{
// Given
State currentState = State.InitialState
// When
Events events = List.of(OrderPlaced, EmailSent)
// Then
List.EMPTY === currentState.applyAll(events).querySideEffects()
}
I punti principali qui sono
- L'aggiornamento del modello è privo di effetti collaterali; gli effetti collaterali effettivi si verificano al di fuori della transazione che aggiorna il modello.
- Un evento che descrive il risultato dell'effetto collaterale deve tornare.