Dipende da ciò che sei disposto a fare in termini di profitti architettonici / prestazionali. Sembra che tu stia facendo una sorta di event sourcing , che in effetti ha molto senso quando inizi parlare di domini in cui è importante avere audit-trail per esattamente quello che è successo.
Penso che un punto chiave per evitare il "code rot" sia quello di assicurarsi che il percorso del codice per gli eventi di "replaying" sia lo stesso di fare modifiche la prima volta. Esempio approssimativo:
// Don't do this
assert(account.getBalance() == 0);
transactionEvent = account.add(123);
recordInDatabase(transactionEvent);
assert(account.getBalance() == 123);
// Instead try this
transactionEvent = new TransactionEvent(123, account.getId());
assert(account.getBalance() == 0);
account.apply(transactionEvent);
assert(account.getBalance() == 123);
recordInDatabase(transactionEvent);
Con il secondo metodo, stai sempre utilizzando apply()
per trasformare il tuo oggetto, se gli eventi sono "freschi" o se vengono "riprodotti" dal database. (Avrai ovviamente bisogno di un trattamento speciale per prevenire effetti collaterali esterni come le chiamate al servizio web che si verificano durante i replay, comunque.)
I'm going to calculate this every time a page is requested?
Un'ottimizzazione delle prestazioni da considerare è "istantanee", dove ancora mantieni l'intera sequenza di eventi (es. transazioni) ma registri anche periodicamente cose come "Dopo la transazione # 4155, il saldo era di $ 255,43 ".
Quindi, quando stai cercando di capire il "saldo corrente" dopo la transazione n. 4203, salti direttamente a $ 255,43 e inizia ad aggiungere i valori da tutte le transazioni 4156-4203. Ogni volta che il processo di riassunzione diventa troppo lento, registra una nuova istantanea.
Ancora una volta, le istantanee sono semplicemente ottimizzazioni delle prestazioni: se non ne sono disponibili, il codice dovrebbe comunque essere in grado di ricostruire tutto dalla Transazione n. 1 e ottenere sempre la stessa risposta. È possibile impostare un processo in background offline per ricalcolare la verifica dell'integrità delle istantanee.
On the other hand if I create some kind of cache or another table called something like balances
Questo potrebbe essere considerato un "Modello di lettura" per un'architettura CQRS . Una specie di visualizzazione materializzata SQL , tranne per il fatto che puoi riutilizzare il tuo "reale" "codice / linguaggio dell'applicazione per farlo. Se le tue balances
righe contengono informazioni sulla versione (come, ad esempio, l'ultimo ID della transazione che faceva parte del calcolo), puoi anche rilevare quando qualcosa è andato storto e diventa obsoleto.