Design basato sul dominio con coerenza finale

2

Il mio aggregato di domini è alle prese con una semplice logica di business, quindi mi sembra di averlo modellato in modo errato.

L'architettura che ho ora utilizza la progettazione basata su domini con l'event sourcing. L'aggregato del dominio produce eventi che vengono digeriti dagli abbonati. Alla fine la coda degli eventi sarà vuota e la vista verrà completamente aggiornata.

Dove si trova a lottare è con ampie raccolte di oggetti sull'aggregato e la necessità di coordinare tra domini.

Quindi un aggregato è un ChatAggregate che consente alle persone di aggiungere commenti. Tuttavia, un utente può aggiungere solo un commento all'ora o un commento per l'intera durata della vita. Il mio oggetto dominio non può conservare tutti i commenti in memoria, ma ho ancora bisogno del mio ChatAggregate per applicare questa logica aziendale. A causa della natura alla fine coerente del mio negozio di visualizzazione, non posso permettere che i miei aggregati lo interrogino per la logica aziendale. Come gestisce DDD quando un aggregato ha bisogno di accedere a molti dati?

Il secondo problema che ho è quando si elabora un comando di dominio, voglio interrogare altri aggregati prima di elaborare il comando con l'aggregato di destinazione. Un esempio è prima di creare una nuova istanza ChatCommentAggregate , vorrei interrogare ChatAggregate per vedere se la chat è ancora aperta.

    
posta LivingOnACloud 27.07.2015 - 16:16
fonte

2 risposte

1

Se la consistenza finale non verrà eseguita, avrai bisogno di un modo per archiviare dati coerenti al 100% sul lato transazione / scrittura / dominio delle cose.

Detto questo, a volte è possibile implementare una regola aziendale in modo leggermente diverso ma ottenere lo stesso risultato. Ad esempio, potresti aggiungere un elenco di oggetti di valore ChatAggregateComment al tuo ChatAggregate che memorizza, ad esempio, UserId , CommentId e DateCommented . Questo elenco sarebbe cresciuto solo come il numero di persone coinvolte nella chat. Tuttavia, anche se fosse troppo grande, potresti denormalizzare i dati e archiviare lo stesso elenco come immediatamente coerente sul tuo lato di scrittura e quindi eseguire query sulla tabella tramite un'interfaccia di query sul lato dominio.

Per quanto riguarda la creazione di un nuovo ChatCommentAggregate , potresti utilizzare ChatAggregate come fabbrica per ChatCommentAggregate . La tua regola potrebbe essere applicata all'interno del metodo ChatAggregate.CreateComment .

    
risposta data 28.07.2015 - 06:18
fonte
0

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.

    
risposta data 15.01.2016 - 22:51
fonte