Da qualche parte, nella maggior parte dei sistemi aziendali, c'è un numero di cui non si fida nessuno. Lo stock in magazzino. Il saldo di un conto. I punti accumulati. I posti occupati. Di solito è una colonna in cui scrive il codice, e verso il secondo anno è sbagliata da qualche parte e nessuno sa dire quando è andata storta o perché.
La soluzione non è una validazione migliore. È smettere di conservarlo.
Conservato contro derivato
Un totale conservato è un'affermazione. Qualcosa l'ha calcolato una volta e l'ha scritto, e da quell'istante può allontanarsi dagli eventi che l'hanno prodotto - un retry applicato due volte, una transazione fallita a metà, una correzione manuale in buona fede, una race condition tra due richieste.
Un totale derivato è una domanda posta agli eventi stessi. Non ha modo di allontanarsi, perché non esiste niente di separato da cui allontanarsi. Chiedi di nuovo e ricevi la risposta di oggi dai fatti di oggi.
Come si presenta nella pratica
Invece di una colonna quantity, tieni una tabella di movimenti:
ciascuno con segno, immutabile, con chi l'ha fatto, quando e su quale
riferimento. Lo stock di un magazzino è la somma dei movimenti che lo toccano.
Una correzione è un movimento nuovo in senso inverso, mai una modifica.
Tre cose ne seguono immediatamente, e sono il guadagno vero:
- La riconciliazione smette di essere un compito. Il saldo e la sua spiegazione sono lo stesso oggetto, quindi non possono contraddirsi. Non esiste più l'esercizio mensile di trovare dove il numero è andato storto.
- "Perché ne abbiamo undici?" ha sempre una risposta. Non di solito. Sempre. Lo storico completo è il numero.
- L'undo diventa sicuro. Aggiungere l'inverso lascia intatta la traccia di audit, mentre cancellare l'originale distrugge la prova di quello che è successo.
C'è una piccola versione funzionante dell'idea nel caso studio delle cliniche - registra un movimento e guarda i totali ricalcolarsi dal log, senza che niente, da nessuna parte, conservi una quantità.
L'obiezione, e la risposta onesta
"Sommare ogni movimento a ogni lettura sarà lento."
Di solito non lo è. Qualche migliaio di movimenti non significa niente per un database con l'indice giusto, e la maggior parte dei sistemi che se ne preoccupano ha molte meno righe di quante ne immaginino i loro autori.
Quando diventa davvero lento, la risposta è uno snapshot periodico - una riga di checkpoint che dice "a questa data il saldo era X" - e derivi in avanti dal più recente. Quella è una cache, ed è sicura proprio perché si può ricostruire: cancella tutti gli snapshot e il sistema sa ancora tutte le risposte giuste. Nel momento in cui non lo puoi più ricostruire dagli eventi, si torna a conservare, e ti ritrovi con il problema iniziale, più un po' di meccanica in più.
Dove non usarlo
È per le cose che si contano e che devono poter essere spiegate. È inutile per una preferenza di visualizzazione, per una bozza o per qualsiasi cosa in cui il valore corrente è l'unica cosa a cui qualcuno terrà mai. L'event sourcing per il tema scelto da un utente non è rigore, è cerimonia.
Decidere quale delle due categorie sia un certo numero avviene durante la discovery, non durante la costruzione - ed è in parte per questo che il primo prezzo che ti danno è di solito sbagliato. È l'argomento della nota su quanto costa davvero una piattaforma.