Evans introduce nel suo libro "Domain Driven Design" nel capitolo 6 "Aggregates" il concetto di Aggregates. Definisce inoltre le regole per tradurre tale concetto in un'implementazione (Evans 2009, pp. 128-129):
The root ENTITY can hand references to the internal ENTITIES to other objects, but those objects can use them only transiently, and they may not hold on to the reference.
Dopo aver elaborato altre regole, le riassume in questo paragrafo:
Cluster the Entities and Value Objects into Aggregates and define boundaries around each. Choose one Entity to be the root of each Aggregate, and control all access to the objects inside the boundary through the root. Allow external objects to hold references to the root only. Transient references to internal members can be passed out for use within a single operation only. Because the root controls access, it cannot be blindsided by changes to the internals. This arrangement makes it practical to enforce all invariants for objects in the Aggregate and for the Aggregate as a whole in any state change.
Quindi cosa significa esattamente l'uso transitorio?
Il mio collega comprende che solo la radice aggregata espone un'interfaccia pubblica per i client. I clienti non avranno la possibilità di chiamare alcuna operazione su un'entità diversa dalla radice aggregata.
La mia comprensione delle frasi citate è diversa. Capisco che in effetti consenta esplicitamente ai client di chiamare operazioni su entità interne. Tuttavia solo dopo averli ricevuti dalla radice.
Quindi diamo un esempio concreto:
Diciamo che Cart
è composta da molti Items
. Ogni Item
ha un Quantity
. Il modello deve supportare il caso d'uso "Aumentare la quantità di un articolo specifico". Non è possibile violare alcuna invariante che influisce su qualcosa al di fuori dell'Articolo.
Un modello sta violando le regole citate sopra, quando un client può farlo chiamando cart.item(itemId).increaseQuantity()
o un client può solo chiamare un cart.increaseItemQuantity(itemId)
? Quale sarebbe il vantaggio di quest'ultimo?