Progettare per il caso di guasto, non per il percorso felice
Quasi tutto il software viene mostrato sul suo percorso felice — l’esecuzione in cui ogni servizio risponde, ogni input è ben formato e niente va in timeout. Quel percorso è il facile 80% del lavoro. L’altro 20%, la parte che decide se una piattaforma è davvero affidabile, è tutto ciò che accade quando una di quelle assunzioni si rompe.
Lavorare su una piattaforma ad alta scala e regolamentata lo insegna in fretta: la domanda interessante non è mai “funziona quando va tutto bene”. È “cosa succede quando qualcosa non va”.
Il percorso felice è la parte che puoi dare per scontata
Quando un sistema è piccolo e poco usato, i guasti sono abbastanza rari da trattarli come eccezioni — li risolvi quando capitano. Su larga scala questa matematica si rovescia. Un evento su un milione capita molte volte al giorno. Una dipendenza attiva al 99,9% del tempo, da qualche parte, per te è giù di continuo. Il guasto smette di essere un caso limite e diventa una condizione di regime dentro cui operi sempre.
Una volta interiorizzato questo, smetti di progettare per l’esecuzione in cui tutto funziona e inizi a progettare per quella in cui qualcosa non funziona.
Il guasto è un input di progettazione, non un ripensamento
Il passaggio è da “come faccio a farlo funzionare” a “come si comporta questo quando le sue dipendenze non funzionano”. È una domanda diversa, e porla presto cambia il progetto invece di attaccare la sicurezza alla fine.
In pratica si traduce in un pugno di abitudini:
- Dai per scontato che ogni chiamata possa fallire o bloccarsi. Timeout, retry con backoff e circuit breaker non sono decorazioni — sono la differenza tra una dipendenza lenta e un’interruzione a cascata.
- Degrada con grazia. Decidi in anticipo cosa fa il sistema senza ciascun pezzo. Una funzione che ripiega in silenzio batte una pagina che non si carica.
- Rendi le operazioni idempotenti. Su larga scala le cose vengono ritentate. Se una ripetizione non addebita o invia due volte, intere classi di bug semplicemente non possono accadere.
- Contieni il raggio dell’esplosione. Quando qualcosa si rompe, quanto si rompe con esso? Buoni confini fanno sì che un guasto resti un piccolo guasto.
- Rendilo osservabile. Non puoi reagire a ciò che non vedi. Il caso di guasto ha bisogno di log, metriche e alert con la stessa cura della funzione.
Niente di tutto questo è affascinante, e niente compare in una demo. Compare alle 3 di notte, o sotto un picco di carico, o quando un fornitore terzo ha una brutta giornata — il che, con abbastanza traffico, per qualcuno è ogni giorno.
L’affidabilità è una funzione di prodotto
È tentante trattare tutto questo come igiene ingegneristica, separata dal prodotto. Non lo è. Per chi usa la piattaforma, “funziona quando mi serve” è il prodotto. La funzione più ingegnosa non vale nulla il giorno in cui non si carica.
Preferisco quindi che un team spenda il tempo in più a progettare per il caso di guasto piuttosto che rilasciare un percorso felice più ampio che crolla la prima volta che la realtà non collabora. Il percorso felice ti dà la demo. Il percorso di guasto ti rende affidabile — e su larga scala, in un contesto regolamentato, la fiducia è tutto il gioco.