2016-06-06 15 views
10

In DDD, un repository carica un intero aggregato: ne carichiamo tutto o niente. Questo significa anche che dovrebbe evitare il carico pigro.DDD: ho davvero bisogno di caricare tutti gli oggetti in un aggregato? (Preoccupazioni per le prestazioni)

La mia preoccupazione è dal punto di vista delle prestazioni. Cosa succede se questo si traduce nel caricamento in memoria di migliaia di oggetti? Ad esempio, un aggregato per Customer ritorna con diecimila Orders.

In questo tipo di casi, potrebbe significare che ho bisogno di riprogettare e ripensare i miei aggregati? DDD offre suggerimenti su questo problema?

+2

Se il '' del cliente aggregato contiene diecimila 'oggetti Order', è probabile che' Order' è un aggregato per conto proprio. – theDmi

+1

[Questa mia risposta] (http://stackoverflow.com/a/31585706/219187) riepiloga i driver di progettazione primari per gli aggregati. – theDmi

+0

Puoi anche ripensare ai tuoi contesti limitati. –

risposta

12

Dai un'occhiata a questa serie Effective Aggregate Design di tre articoli da Vernon. Li ho trovati abbastanza utili per capire quando e come è possibile progettare aggregati più piccoli piuttosto che un aggregato di grandi cluster.

EDIT

vorrei dare un paio di esempi per migliorare la mia risposta precedente, sentitevi liberi di condividere i tuoi pensieri su di loro.

In primo luogo, una rapida definizione su un aggregato (preso da modelli, principi e le pratiche Domain Driven Design libro di Scott Millet)

Entità e oggetti di valore collaborano per formare relazioni complesse che soddisfano invarianti all'interno il modello di dominio. Quando si ha a che fare con grandi associazioni di oggetti interconnesse, è spesso difficile garantire coerenza e concorrenza quando si eseguono azioni contro oggetti di dominio. Il Domain-Driven Design ha il modello Aggregate per garantire la coerenza e definire i limiti di concorrenza transazionali per i grafici degli oggetti. I modelli di grandi dimensioni sono divisi per invarianti e raggruppati in aggregati di entità e oggetti di valore che sono trattati come un insieme concettuale.

Facciamo un esempio per vedere la definizione in pratica.

Semplice esempio

Il primo esempio mostra come definire un aggregato radice contribuisce a garantire la coerenza quando si eseguono azioni contro oggetti di dominio.

Data la prossima regola aziendale:

vincenti offerte d'asta devono essere sempre posizionati prima della fine dell'asta. Se l'offerta vincente viene piazzata al termine dell'asta, il dominio si trova in uno stato non valido in quanto un'invarianza è stata interrotta e il modello non è riuscito a applicare correttamente le regole del dominio.

Qui c'è un aggregato costituito da aste e offerte in cui l'asta è la radice aggregata.

Se diciamo che Bid è anche un aggregato Root separato si avrebbe hanno un , e si potrebbe facilmente fare:

var newBid = new Bid(money); 
BidsRepository->save(auctionId, newBid); 

E si stava salvando un Bid senza passare la regola di business definito. Tuttavia, avendo l'asta come l'unica radice di aggregazione si è far rispettare il vostro disegno perché è necessario fare qualcosa di simile:

var newBid = new Bid(money); 
auction.placeBid(newBid); 
auctionRepository.save(auction); 

Pertanto, è possibile controllare l'invarianti all'interno del metodo placeBid e nessuno può saltare se vogliono inserire una nuova offerta.

Qui è abbastanza chiaro che lo stato di un'offerta dipende dallo stato di un'asta.

esempio complesso

Torna al tuo esempio di ordini essere associati a un cliente, sembra che non ci sono invarianti che ci fanno definire un aggregato enorme costituito da un cliente e tutti i suoi ordini, possiamo solo continuare la relazione tra entrambe le entità attraverso un riferimento identificativo. In questo modo evitiamo di caricare tutti gli ordini durante il recupero di un cliente e attenuiamo i problemi di concorrenza.

Ma, dicono che ora attività definisce il prossimo invariante:

Vogliamo fornire ai clienti con una tasca in modo che possano pagare con i soldi per comprare i prodotti. Pertanto, se un cliente desidera acquistare un prodotto, deve disporre di denaro sufficiente per farlo.

Detto così, pocket è un VO all'interno della radice di aggregazione del cliente. Ora sembra che avere due Roots aggregati separati, uno per Cliente e un altro per Ordine non è il migliore per soddisfare la nuova invariante perché potremmo salvare un nuovo ordine senza controllare la regola. Sembra che siamo costretti a considerare il cliente come la radice. Ciò influenzerà le nostre prestazioni, la scalabilità e i problemi di concorrenza, ecc.

Soluzione? Eventuale consistenza. Cosa succede se permettiamo al cliente di acquistare il prodotto? vale a dire, avendo un aggregato radice per gli ordini in modo da creare l'ordine e salvarlo:

var newOrder = new Order(customerId, ...); 
orderRepository.save(newOrder); 

pubblichiamo un evento quando viene creato l'ordine e poi controlla in modo asincrono se il cliente ha fondi sufficienti:

class OrderWasCreatedListener: 
    var customer = customerRepository.findOfId(event.customerId); 
    var order = orderRepository.findOfId(event.orderId); 
    customer.placeOrder(order); //Check business rules 
    customerRepository.save(customer); 

Se tutto andava bene, abbiamo soddisfatto i nostri invarianti mantenendo il nostro design come volevamo all'inizio modificando solo una radice di aggregazione per richiesta. In caso contrario, invieremo una email al cliente che le dirà della mancanza di fondi.Possiamo anticiparlo aggiungendo alle opzioni di posta elettronica alternative che può acquistare con il suo budget corrente e incoraggiarla a caricare la tasca.

Prendere in considerazione che l'interfaccia utente può aiutarci ad evitare che i clienti paghino senza abbastanza denaro, ma non possiamo fidarci ciecamente dell'interfaccia utente.

Spero che troviate utile entrambi gli esempi, e fatemi sapere se trovate soluzioni migliori per gli scenari esposti :-)

+1

Grazie per il tuo impegno nel spiegarmelo. Sono stato costretto a darti la risposta. Grazie! – user11081980

10

In questo tipo di casi, potrebbe significare che ho bisogno di riprogettare e ripensare i miei aggregati?

Quasi certamente.

Il driver per la progettazione aggregata non è struttura, ma comportamento. Non ci interessa che "un utente abbia migliaia di ordini". Ciò che ci interessa sono i pezzi di stato che devono essere controllati quando si tenta di elaborare una modifica: quali dati è necessario caricare per sapere se una modifica è valida.

In genere, capirai che la modifica di un ordine non dipende (o non dovrebbe) dallo stato degli altri ordini nel sistema, il che è una buona indicazione che due diversi ordini non dovrebbero far parte di lo stesso aggregato.

Problemi correlati