2015-04-18 10 views
6

Attualmente sto studiando il progetto guidato da dominio di Eric Evans. L'idea degli aggregati è chiara per me e la trovo molto interessante. Ora sto pensando ad un esempio di aggregato come:DDD (Domain-Driven-Design) - aggregati di grandi dimensioni

BankAccount (1) ----> (*) Transazione.

BankAccount 
BigDecimal calculateTurnover(); 

BankAccount è un aggregato. Per calcolare il fatturato dovrei attraversare tutte le transazioni e sommare tutti gli importi. Evans presume che dovrei usare i repository per caricare solo aggreagates. Nel caso precedente potrebbero esserci alcune migliaia di transazioni che non voglio caricare contemporaneamente in memoria.

Nel contesto del modello di repository, le radici aggregate sono gli unici oggetti> il codice del client viene caricato dal repository.

Il repository incapsula l'accesso agli oggetti figlio: dal punto di vista del chiamante li carica automaticamente, sia allo stesso tempo in cui viene caricato il root, sia quando è effettivamente necessario (come nel caso di caricamento lento).

Quale sarebbe il tuo suggerimento per implementare calulcateTurnover in un aggregato DDD?

risposta

2

Come è stato sottolineato, caricare migliaia di entità in un aggregato non è una soluzione scalabile. Non solo ti imbatterai in problemi di prestazioni, ma probabilmente incontrerai anche problemi di concorrenza, come sottolineato da Vaughn Vernon nella sua serie Effective Aggregate Design.

Vuoi che ogni transazione sia disponibile nel gruppo BankAccount o sei interessato solo al fatturato?

Se è solo il fatturato necessario, è necessario stabilire questo valore durante l'istanziazione dell'aggregato BankAccount. Questo potrebbe essere calcolato in modo efficace dalla tecnologia del data store (JOIN indicizzati, ad esempio, se si utilizza SQL). Forse devi anche considerare di averlo come valore precalcolato nel tuo archivio dati (cosa succede quando inizi a trattare milioni di transazioni per conto bancario)?

Ma forse hai ancora bisogno delle transazioni disponibili nel tuo dominio? Quindi dovresti considerare di avere un repository separato Transaction.

Consiglio vivamente di leggere la serie di Vaughn Vernon sul design aggregato, come sopra collegato.

+0

Prima di tutto, grazie per aver risposto così rapidamente. Ho recentemente ordinato il libro di Vernon, quindi lo leggerò presto e tornerò su questo thread. –

+0

Piacere. A condizione che tu conosca le basi e la terminologia DDD, potresti iniziare leggendo quella serie di PDF in 3 parti collegata nella mia risposta. – davenewza

1

Siete riusciti a prendere un esempio molto interessante :)

Io in realtà uso Account 1 -> * Transaction quando spiega di sourcing evento (ES) a tutti coloro che non hanno familiarità con esso.

Come sviluppatore mi è stato insegnato (via di ritorno) per utilizzare ciò che ora possiamo fare riferimento come interazione entità. Quindi abbiamo un record Customer e ha uno stato corrente. Modifichiamo in qualche modo lo stato del record (indirizzo, dettagli fiscali, sconti, ecc.) E memorizziamo il risultato. Non sappiamo mai cosa sia successo, ma abbiamo lo stato più recente e, poiché questo è lo stato attuale della nostra attività, va bene. Naturalmente uno dei primi problemi che dovevamo affrontare era la concorrenza, ma avevamo dei modi per gestirlo e, anche se non fantastico, "funzionava".

Per qualche motivo, la disciplina contabile non si è concentrata in questo.Perché non abbiamo semplicemente lo stato più recente di Account. Caricheremo il relativo record, cambieremo il bilancio e salveremo lo stato. Stranamente, la maggior parte delle persone probabilmente rabbrividire al pensiero, ma sembra essere OK per il resto dei nostri dati.

Il dominio di contabilità ha aggirato questo registrando gli eventi di modifica come una serie di voci Transaction. Quindi, se dovessi perdere il tuo account e il saldo più recente, puoi sempre eseguire tutte le transazioni per ottenere il saldo più recente. Questo è il sourcing di eventi.

In ES si carica in genere un intero elenco di eventi per una radice aggregata (AR) per ottenere il suo stato più recente. C'è anche, in genere, un meccanismo per gestire un numero enorme di eventi quando il caricamento di tutti causerebbe problemi di prestazioni: istantanee. Solitamente viene memorizzata solo l'ultima istantanea. L'istantanea contiene l'ultimo stato completo dell'aggregato e l'unico evento dopo l'applicazione della versione di istantanea.

Uno degli enormi vantaggi di ES è che si potrebbero creare nuove query e quindi applicare semplicemente tutti gli eventi al gestore query e determinare il risultato. Forse qualcosa del tipo: "Quanti clienti ho trasferito due volte nell'ultimo anno". Abbastanza arbitrario, ma utilizzando l'approccio "tradizionale", la risposta sarebbe molto probabile che inizieremo a raccogliere le informazioni da oggi e renderle disponibili l'anno prossimo poiché non abbiamo salvato gli eventi CustomerMoved. Con ES possiamo cercare gli eventi CustomerMoved e ottenere un risultato in qualsiasi momento.

Quindi questo mi riporta al tuo esempio. Probabilmente non vuoi caricare tutte le transazioni. Invece memorizza il "Fatturato" e calcola in movimento. Se il "Fatturato" dovesse essere un nuovo requisito, allora un'elaborazione una tantum di tutte le RA dovrebbe aggiornarla. Puoi sempre avere un metodo calculateTurnover() da qualche parte ma sarebbe qualcosa che non verrebbe eseguito troppo spesso. E in quei casi dovresti caricare tutte le transazioni per un AR.

Problemi correlati