La progettazione di un aggregato e la scelta di una radice di aggregazione diventano sempre difficili per me soprattutto quando si tratta di garantire giusti contesti transazionali e vincoli di coerenza, quindi mi chiedo se ci siano pratiche che possano renderlo più semplice.
Per esempio
Esiste un sistema di tracciamento delle presenze degli studenti che tiene traccia delle presenze degli studenti nei gruppi.
- Ilcorsoèuncomponentedilivellosuperiore,descriveun'informazionegenericasulcorsodiapprendimento(nome,descrizione)
- Ognicorsocontienegruppichedescrivonoigruppiacuiunutentedeveiscriversisedesideraparteciparealgruppo.
- Ognigruppocontieneunelencodiriunionichedescrivonoleoccorrenzedelgruppoacuiunutentepuòpartecipare.Èdefinitoda(datetimeBegins,datetimeEndseunsetdioggettiPresenza).
- Lafrequenzaèunrecordcontieneinformazionisuunostudentechepartecipa.Contieneunriferimentoall'Utenteealcunidatistatistici.
Iterazionen.1
Sembravaunabuonaideaprogettareiconfiniaggregatiinmodochecorrispondesseroesattamenteallatassonomia,incuiilpilastroprincipaleeralaradicediaggregazionedeipercorsi:
Èbelloperché:
- Corrispondeesattamenteallatassonomiadeldominio
- Assicuravincolididominiocome"I gruppi non possono essere creati al di fuori del corso" o "Le riunioni devono essere definite all'interno di un gruppo".
Ma allo stesso tempo, è molto grasso, difficile da mantenere e progettato pensando a invarianti finti che hanno causato fallimenti alle transazioni: nulla sulla creazione di un nuovo elemento Meeting dovrebbe interferire logicamente con la modifica / creazione di un corso, ad esempio. Semplicemente non scala. Inoltre, di solito, potresti voler aggiornare il gruppo aggiungendo alcune sessioni con GroupId e non dovrebbe richiedere di recuperare l'intero corso.
Iterazione n. 2
Poi mi è venuta l'idea di separare tutti i concetti principali in diverse AR:
Dopotutto,nonhoproblemiconletransazioni,ma,sfortunatamente,hoaggiuntopiùdomandecheproblemirisolti:
- PoichéGroupeMeetingsonoseparatidaARora,comegarantirenessunocreerà"Deattached" dal Course Group o Meeting al di fuori del Raggruppa tramite i propri repository?
- Avendo il metodo
Meeting#attend(UserId userId)
, come garantire che l'utente sia idoneo (iscritto al gruppo) per partecipare a questo incontro?
Idee per l'iterazione n. 3
Sto pensando di spostare Meeting all'interno del gruppo AR, dove posso inserire il metodo Group#attend(UserId userId)
. Ma c'è ancora un problema nel garantire che il Gruppo venga creato solo all'interno del Corso.
Stavo pensando di nascondere (pacchetto private'ing / protected'ing) Costruttore di gruppo e aggiungere Course#createGroup(GroupParams p): Group
, ma non sono sicuro che sia valido confondere due concetti diversi (Raggruppamento e aggregazione delle radici) l'uno nell'altro.
Inoltre, non risolve il problema che gli utenti possono ancora rimuovere Group tramite il suo repository (una percentuale di Spring Repository#delete(Group)
nel mio caso). Posso risolvere questo problema:
- con l'individuazione di eventi di dominio, ad esempio, il repository di gruppo emetterà
GroupRemovedEvent
in modo che il corso possa iscriversi e modificare il suoList<GroupId> groupIds
. - avendo un riferimento inverso da Group a Course, ma può diventare scomodo perché use case
get all groups of the course by CourseId given
è un'operazione giornaliera.
Apprezzerei qualsiasi idea in merito. Grazie.