Capitolo 5 — Robustezza: il codice che assume il fallimento

C'è una differenza culturale tra il codice che funziona sul tuo computer e il codice che funziona nel mondo: il secondo assume che tutto possa fallire. Le chiamate API falliscono — non spesso, ma abbastanza: il servizio è sovraccarico (errore 529), hai superato il tuo limite di richieste al minuto (errore 429, rate limit), la rete singhiozza, una risposta non arriva mai. Il codice ingenuo muore alla prima di queste; il codice professionale le mette in conto.

Il kit di sopravvivenza ha quattro pezzi. Il retry con backoff esponenziale: sugli errori transitori non riprovi subito a raffica (peggiori il sovraccarico che ti ha respinto) — aspetti un secondo, poi due, poi quattro, con un tetto ai tentativi. Il timeout: ogni chiamata ha un tempo massimo di attesa, perché una richiesta appesa per sempre blocca tutto il programma. Il rispetto dei limiti: se devi fare mille chiamate, le metti in coda a ritmo sostenibile invece di spararle insieme. E il logging: ogni chiamata lascia una riga — quando, quale modello, quanti token dentro e fuori, quanto ci ha messo, com'è finita. Oggi il log ti sembra burocrazia; al primo problema in produzione sarà l'unica lanterna, e al capitolo 6 sarà anche il tuo contatore dei costi.

Merita una menzione la Batch API: per i lavori non urgenti — elaborare diecimila documenti stanotte, non adesso — i provider offrono una modalità differita a metà prezzo. Quando il volume cresce, metà prezzo è tanta roba.

Il modo giusto di pensarla: avvolgi tutto in una tua funzione chiamata_robusta() — retry, timeout, log dentro — e da lì in poi il resto del tuo codice chiama quella e vive sereno. La scrivi una volta, la usi per sempre.

L'esperimento del giorno. Scrivi chiamata_robusta() e mettila alla prova con cattiveria: input enormi, richieste a raffica, la rete staccata a metà. Guarda il log raccontare la storia: tentativi, attese, esiti. Quel file di testo noioso è la differenza tra un esperimento e uno strumento.