So one aggregate is a ChatAggregate which allows people to add comments. However a user can only add one comment per hour or one comment for the entire life time. My domain object cannot keep all comments in memory but I still need my ChatAggregate to apply this business logic. Because of the eventually consistent nature of my view store, I cannot let my aggregates query it for business logic. How does DDD handle when an aggregate needs access to a lot of data?
Esamina nuovamente il design per vedere se il requisito reale viene espresso correttamente. Una buona parte del valore aggiunto del DDD è che quando i programmatori incontrano problemi nell'adattare i requisiti aziendali al progetto, è spesso
significa che i programmatori non comprendono i requisiti reali.
Per estendere il tuo esempio; potresti scoprire che CommentSubmitted e CommentPublished sono in realtà due diversi eventi e che esiste un processo aziendale responsabile di capire se un evento conduce necessariamente all'altro.
Il modello di scrittura potrebbe essere simile a:
User.submitComment(comment) ->
[ CommentSubmitted
, UserMuted
] ;
Chat.publishComment(comment) ->
[ CommentPublished
] ;
Dove submitComment genera un'eccezione se lo stato disattivato dell'utente non supporta i commenti e la chat rifiuta di pubblicare commenti in cui l'utente lo ha già fatto.
La colla che rende questo lavoro è una macchina a stati che sta ascoltando il flusso di eventi (avviso: pseudo-codice in anticipo).
IDLE {
onCommentSubmitted(event) {
asyncDispatch(publishComment(event));
asyncDispatch(scheduleTimer(event));
transitionTo(PUBLISHING)
}
onTimer(event) {
asyncDispatch(unmuteUser(event));
}
}
PUBLISHING {
onCommentPublished(event) {
transitionTo(IDLE)
}
}
Questo è un gestore di processi; interagisce con il dominio esclusivamente attraverso l'api (ascolto di eventi e comandi di invio). Sta anche programmando i messaggi al suo sé futuro (tramite il timer).
Si noti che, come mostrato qui, in genere non è possibile richiamare direttamente i comandi sul modello di dominio. Il problema è che si suppone che si debba aggiornare una cronologia per transazione e che il manager di processo debba mantenere le proprie transizioni di stato.
Vale la pena notare anche lo spazio che si è aperto, per soddisfare i requisiti: disattiviamo l'utente quando inviano un commento (e poi proviamo a recuperare se il commento non è pubblicato) o disattiviamo solo l'audio utente se un commento è pubblicato. Forse disattiviamo l'utente solo per pochi minuti quando inviano, ma per l'intero giorno una volta che abbiamo ricevuto la conferma che il commento è stato pubblicato e così via.
The second issue I have is when a domain command is being processed, I want to query other aggregates before processing the command with the target aggregate.
Vai avanti - questa è una cosa assolutamente ragionevole per l'applicazione da fare. Devi tenere a mente che la query qualsiasi che esegui restituisce risultati obsoleti - non puoi mai sapere cosa è "adesso" tranne all'interno del dominio aggregato stesso, ma "non troppo tempo fa" è quasi sempre sarà abbastanza buono.
Un modello comune per la convalida è che l'operatore umano (seduto di fronte al cliente), proverà a verbo, e l'app dirà "no - le ultime informazioni che abbiamo detto che non possiamo farlo". Ma se tutto si verifica, il comando viene inviato al server, che può eseguire la propria convalida prima di inviare il comando all'aggregato per l'elaborazione.
Ma una volta che siete in aggregato, le uniche cose che dovreste considerare sono lo stato corrente dell'aggregato e lo stato catturato nel comando.