Domain Driven Design: progettazione di root aggregati

5

Immagina di progettare un'applicazione per organizzare seminari. Lo stesso workshop è piuttosto complicato: agisce come una macchina a stati con più stati possibili e transizioni tra di essi.

Utilizziamo DDD, CQRS e Event Sourcing.

E ora, i casi d'uso:

1) si dovrebbe essere in grado di assegnare TodoItem ad un Workshop ed eseguire su di essi operazioni CRUD

2) si dovrebbe essere in grado di inviare risorse aggiuntive per un determinato workshop (diapositive, foto, archivi zip / tar.gz ecc.) ed eseguire anche operazioni CRUD su di esse

3) si dovrebbe essere in grado di aggiungere un PossibleTerm (con un Docente, una Data e una Stanza specificati) ad un Workshop. Inoltre, dovrebbe esserci un modo per modificarli / eliminarli.

Più tardi c'è una votazione su questi termini, il sistema cerca di prenotare una stanza per pochi termini (diciamo, per due termini) che ha vinto Voto e utenti dovrebbero essere divisi tra questi Termini.

Ecco le seguenti soluzioni:

1) Modello TodoItems, Resources e PossibleTerms come parte di un Workshop.

Pro:

  • tutto è dove concettualmente appartiene a
  • nessuna consistenza finale (probabilmente non un grosso problema ...)

Contro:

  • Gli aggregati di workshop sono ingombri di tutti quei metodi CRUD per tutte le cose.
  • Secondo Implementing Domain Driven Design di Vaughn Vernon, la creazione di enormi radici aggregate è un antipattern

2) Crea radici aggregate per contenere tutti quegli "articoli" (ad esempio TodoItemList, PossibleTermList, Resources o qualsiasi altra cosa li chiamerai).

Pro:

  • L'aggregato del seminario è più piccolo, non è correlato a tali elenchi (l'unica connessione sarebbe che ad esempio PossibleTermList abbia un riferimento a WorkshopId)

Contro:

  • quando arriva CreateWorkshopCommand, sei costretto a creare non solo un workshop, ma anche aggregati aggiuntivi che devono esistere dopo la creazione del workshop. Per evitare questo, potrebbe esserci qualche tipo di CreationSaga, ascoltare WorkshopCreatedEvent e produrre comandi appropriati per creare parenti, ma non penso che sia una buona idea.

3) Model PossibleTerms, Resource, TodoItem as aggregate roots stesso

Pro:

  • nessuna necessità di creare 'aggregati wrappers' (come in 2))

Contro:

  • di nuovo, stai ingombrando Workshop con almeno i metodi di fabbrica
  • è difficile per me implementare funzionalità di scelta del termine - per il conteggio dei voti e in seguito assegnando l'utente a un determinato termine è necessario interrogare il repository per tutti i termini che corrispondono all'ID del workshop e così via - questo porta a operazioni su più aggregati all'interno di una transazione.

Domanda: quale soluzione suona meglio per te? Forse hai idee diverse?

(domanda bonus: ho bisogno di eseguire operazioni CRUD su singole risorse / TodoItem, preferisco modellare come oggetti valore, ma come vengono identificati?)

    
posta slnowak 28.03.2015 - 10:19
fonte

2 risposte

2

Penso che manchi l'analisi transazionale. Quali entità saranno modificate da ciascuno dei tuoi casi d'uso? Alcuni di essi avranno impatto su più di un'entità?

Quali sono i tuoi invarianti? Alcuni di essi si estendono su più entità (ad esempio, due Term s non può utilizzare lo stesso Room alla stessa data / ora)? Sono veri invarianti o potrebbe essere sufficiente la coerenza finale?

Vaughn Vernon ha un buon approccio graduale alla modellazione aggregata qui: link

    
risposta data 01.04.2015 - 15:14
fonte
0

Mi sembra che la scelta peggiore sia cercare di modellare le liste. Il punto di un aggregato è garantire un'invarianza di business. Quale invariante fa rispettare una collezione? Se viene invocato il comando addItem, l'elenco può pronunciare no?

Rendere tutte le entità parte dell'aggregato del Workshop è una scelta naturale - specialmente se le altre entità non "hanno senso" al di fuori del contesto di un workshop. Se hai un'invarianza di business che vincola più entità, allora hai bisogno che quelle entità facciano parte dello stesso aggregato.

Ma vuol dire che sei contesa: Alice, lavorando su ToDoItem: 1, e Bob, lavorando su ToDoItem: 2, non può salvare le loro modifiche "nello stesso tempo" a causa del conflitto di scrittura.

L'opzione n. 3, in cui ogni entità è il proprio aggregato, si prende cura del problema della contesa. Alice e Bob possono commettere le loro modifiche senza conflitti, i ToDoItems possono imporre il loro invariante.

È vero che le entità hanno cicli di vita diversi e devi essere d'accordo. Devi anche lavorare un po 'più duramente per applicare un invariante che si estende su più aggregati.

Il linguaggio onnipresente dovrebbe suggerire se i componenti di un workshop devono essere parte della stessa transazione del workshop stesso (se esiste già un processo aziendale per mitigare gli imprevisti, allora probabilmente non si ha una coerenza delle transazioni requisito.

Detto questo, se il tuo dominio è CRUD (se il modello non è autorizzato a porre il veto al giudizio degli operatori umani), provare a inventare "aggregati" dal nulla potrebbe non essere la migliore.

    
risposta data 12.01.2016 - 06:27
fonte

Leggi altre domande sui tag