Articoli approfonditi sulla tecnologia che plasma il futuro.

Software senza reboot: scrivere codice per lo spazio

Il software spaziale non può fallire con grazia. Come gli ingegneri scrivono codice per sistemi dove un bug costa una missione da miliardi e un riavvio richiede ore.

Veicolo spaziale solitario coperto di circuiti in orbita attorno a un pianeta rosso, lontano dalla Terra

Il tuo web server va in crash alle 3 di notte. Kubernetes lo riavvia. Gli utenti vedono una pagina di errore per qualche istante. Nessuno viene licenziato. Ora immagina che il tuo server stia orbitando attorno a Marte, il riavvio richieda 45 minuti (durante i quali non hai controllo d'assetto, né regolazione termica, né comunicazioni), il «utente» sia una sonda da 2,5 miliardi di dollari e di Kubernetes non ci sia traccia: solo il tuo codice e la CPU resistente alle radiazioni su cui gira.

Il software spaziale opera sotto vincoli che fanno sembrare l'ingegneria del software tradizionale una passeggiata. Non puoi rilasciare un hotfix. Non puoi collegarti via SSH per controllare i log. Non puoi aggiungere server quando il carico aumenta. Ogni riga di codice deve essere corretta prima del lancio, perché dopo il lancio il software è lasciato a se stesso per anni o decenni, gira su hardware che viene lentamente danneggiato dalle radiazioni e comunica attraverso un collegamento con ritardi di diversi minuti e una banda dell'ordine dei kilobit al secondo.

I vincoli che plasmano tutto

Radiazioni. Nello spazio, particelle ad alta energia bombardano continuamente l'elettronica. Una singola particella può invertire un bit in memoria (un single-event upset, o SEU), corrompere un registro o far bloccare un processore. Non è un caso raro: i satelliti in orbita bassa subiscono migliaia di inversioni di bit al giorno. L'hardware di classe spaziale usa componenti resistenti alle radiazioni, più lenti, più costosi e generazioni indietro rispetto all'hardware di consumo. Il processore del rover Mars Perseverance è un RAD750, più o meno equivalente a un PowerPC del 1998 che gira a 200 MHz.

Ritardi di comunicazione. Via radio, Marte dista da 4 a 24 minuti (a seconda della posizione orbitale). Giove ne dista da 33 a 54. Non si tratta solo di latenza: significa che la sonda deve gestire qualsiasi problema in autonomia per almeno il tempo di andata e ritorno, prima ancora che il controllo a terra possa vedere il problema, figuriamoci inviare un comando. Quando le sonde Voyager incontrano un'anomalia a oltre 22 ore-luce dalla Terra, il software prende le sue decisioni per quasi due giorni.

Nessun accesso fisico. Non puoi sostituire un componente guasto, aggiungere RAM o cambiare un disco. Se il computer principale si guasta e quello di backup non funziona, la missione è finita. Ogni modalità di guasto deve essere prevista nel software prima del lancio.

In cosa il codice spaziale è diverso

Il software spaziale usa tecniche che nello sviluppo software normale sarebbero considerate assurdamente sovradimensionate.

Triple modular redundancy (TMR). I calcoli critici vengono eseguiti tre volte su tre processori indipendenti. Un votatore confronta i tre risultati e adotta la risposta della maggioranza. Se un processore produce un risultato errato a causa di radiazioni, gli altri due lo battono ai voti. Alcuni sistemi usano cinque copie (pentuple redundancy) per una garanzia ulteriore.

Memory scrubbing. Un processo in background legge continuamente la memoria, la verifica con i codici di correzione degli errori (ECC) e corregge gli errori su singolo bit prima che si accumulino in errori multi-bit non correggibili. Gira di continuo: ogni byte di memoria viene controllato e corretto più volte al secondo.

Watchdog timer. Sono timer hardware che il software deve resettare regolarmente. Se il software si blocca (magari per un lockup causato dalle radiazioni), il timer scade e innesca un reset hardware. Il software deve essere progettato per sopravvivere a riavvii imprevisti in qualunque punto della sua esecuzione: qualsiasi calcolo potrebbe essere interrotto e rieseguito.

// Simplified space software patterns
// Watchdog — must be kicked regularly or hardware resets
void main_loop(void) {
while (1) {
kick_watchdog();  // Reset the timer — we're alive
// All operations must complete within watchdog timeout
read_sensors();
kick_watchdog();
run_attitude_control();
kick_watchdog();
check_thermal_limits();
kick_watchdog();
process_ground_commands();
kick_watchdog();
}
}
// Critical value stored with redundancy
typedef struct {
int32_t value_a;  // Primary copy
int32_t value_b;  // Redundant copy
int32_t value_c;  // Third copy for voting
} RedundantInt;
int32_t read_redundant(RedundantInt *r) {
// Majority vote — tolerates one corrupted copy
if (r->value_a == r->value_b) return r->value_a;
if (r->value_a == r->value_c) return r->value_a;
if (r->value_b == r->value_c) return r->value_b;
// All three differ — flag anomaly
raise_anomaly(MEMORY_CORRUPTION);
return r->value_a;  // Best guess
}

Il testing è il prodotto

Il Jet Propulsion Laboratory della NASA stima che il testing del software spaziale assorba tra il 60 e l'80% dello sforzo di sviluppo complessivo. Non il 60% del tempo, ma il 60% del costo totale. Il testing costa più dello sviluppo perché deve dimostrare la correttezza con un grado di rigore che il testing software normale non si sogna nemmeno.

Ogni percorso di esecuzione deve essere testato. Non nel senso di «buona copertura del codice» che intendono gli sviluppatori web, ma letteralmente ogni percorso attraverso ogni funzione, inclusi i percorsi di errore, quelli di timeout e quelli che gestiscono i guasti hardware. La copertura dei rami al 100% è il punto di partenza, non l'obiettivo.

Oltre agli unit test, il software spaziale viene sottoposto a hardware-in-the-loop testing (far girare il software reale sull'hardware di volo reale, simulando l'ambiente spaziale), stress test di lunga durata (far girare il sistema per mesi per trovare bug legati ai tempi) e fault injection testing (corrompere deliberatamente la memoria, far morire i processori e interrompere i collegamenti di comunicazione per verificare che il software si riprenda).

La verifica formale viene usata sempre più spesso per i componenti più critici. Invece di testare che il codice funzioni per input specifici, la verifica formale dimostra matematicamente che il codice funziona per tutti gli input possibili. È costosa e lenta, ma per il codice che controlla l'assetto (l'orientamento) di una sonda o ne gestisce la propulsione, il costo è giustificato.

Cosa va storto comunque

Nonostante questo rigore, il software spaziale fallisce. Gli errori sono istruttivi perché mostrano i limiti anche dell'ingegneria più attenta.

  • Mars Climate Orbiter (1999) si schiantò perché un team usava le unità imperiali e un altro quelle metriche. Il software era corretto: sbagliati erano i requisiti. Nessuna quantità di test individua una specifica sbagliata.
  • Ariane 5 Flight 501 (1996) esplose perché un float a 64 bit fu convertito in un intero a 16 bit e andò in overflow. Il codice era stato riutilizzato dall'Ariane 4, dove quel valore non superava mai il range dei 16 bit. Il codice era corretto per l'Ariane 4 e catastroficamente sbagliato per l'Ariane 5.
  • Mars Polar Lander (1999) probabilmente si schiantò perché una vibrazione del sensore durante l'apertura delle gambe fu interpretata come contatto con il suolo, spegnendo i motori a 40 metri di altitudine. Un problema di interpretazione del sensore legato ai tempi, che il testing non individuò perché il test non riproduceva perfettamente le caratteristiche della vibrazione.
  • Il difetto iniziale dello specchio di Hubble (1990) non era un bug del software: lo specchio fu levigato con la forma sbagliata a causa di uno strumento di misura tarato male. Lo strumento di test aveva a sua volta un bug.

Il filo conduttore: il codice era corretto rispetto alla sua specifica, ma la specifica non corrispondeva alla realtà. È il tipo di bug più difficile da prevenire, perché si annida nello spazio tra il modello e il mondo.

Cosa può imparare il software terrestre

La maggior parte di noi non scrive software spaziale. Ma alcune di queste pratiche si applicano direttamente alla costruzione di sistemi affidabili sulla Terra.

Progettare per il riavvio. Il software spaziale presuppone di poter essere riavviato in qualsiasi momento e di dover tornare a uno stato noto e sano. Anche i servizi web dovrebbero avere questa proprietà: se il tuo server va in crash e si riavvia, si riprende senza intervento manuale? Riprende l'elaborazione da dove si era fermata o perde il lavoro? I pattern di ingegneria difensiva che gli ingegneri spaziali considerano obbligatori sono spesso opzionali nello sviluppo web, ma non dovrebbero esserlo.

Testare i casi di guasto, non solo quelli felici. Il testing del software spaziale inietta deliberatamente i guasti: uccidere un processo, corrompere la memoria, far cadere le connessioni di rete, restituire codici di errore da ogni system call. La maggior parte dei test delle applicazioni web verifica se le funzionalità funzionano, non se il sistema gestisce con grazia i guasti.

Ridondanza per i dati critici. Se la tua applicazione memorizza dati costosi da ricreare (registrazioni finanziarie, contenuti utente, stato di configurazione), salvali in modo ridondante e verificali regolarmente. La replica del database è l'esempio più ovvio, ma la ridondanza a livello applicativo (checksum, validazione, controlli periodici di integrità) individua corruzioni che la replica finirebbe per propagare.

Watchdog per i processi critici. Se un processo non deve bloccarsi, monitoralo. Non solo «il processo è in esecuzione», ma «il processo sta facendo progressi». Gli health check che verificano che il sistema funzioni davvero (elabora richieste, aggiorna lo stato, rispetta le scadenze) intercettano guasti che il monitoraggio a livello di processo non vede.

Il nuovo software spaziale

L'industria spaziale commerciale (SpaceX, Rocket Lab, Planet) sta mettendo in discussione alcune di queste tradizioni. SpaceX usa Linux e C++ sui computer di bordo del Falcon 9, un'eresia secondo gli standard aerospaziali tradizionali. Planet Labs gestisce centinaia di piccoli satelliti e li tratta più come un sistema distribuito che come hardware su misura: se un satellite si guasta, è la costellazione a compensare.

Questo cambiamento riflette una domanda più ampia: quanta affidabilità ti serve davvero? Un rover su Marte da 2,5 miliardi di dollari giustifica cinque anni di test. Un satellite per comunicazioni da 500.000 dollari, uno dei centinaia di una costellazione, ne giustifica molto meno. La pratica ingegneristica dovrebbe adattarsi al profilo di rischio, non seguire ciecamente tradizioni nate per un'altra epoca.

Ma la lezione fondamentale vale comunque, indipendentemente dal budget: un software a cui non si può accedere fisicamente dopo il deployment deve essere più affidabile di uno che si può riparare. Che tu stia lanciando una sonda, distribuendo su una flotta IoT o gestendo una rete di edge computing, il principio è lo stesso: se non puoi collegarti in SSH per sistemarlo, il software deve saper gestire da solo i problemi. Questa mentalità, applicata con giudizio, rende migliore tutto il software.