modulo 12 di 24 / Ore 21-40
Moduli 9-16 / Checkpoint 40 ore
Errore infrastrutturale: salvataggio o lettura fallita
Riconoscere e gestire gli errori infrastrutturali nel Registro: fallimenti di localStorage, API o file JSON che devono essere intercettati al bordo del sistema senza raggiungere il dominio.
Errore infrastrutturale: salvataggio o lettura fallita
Questa lezione appartiene al Modulo 12 — Errori, validazione e messaggi.
Cos’è un errore infrastrutturale
Un errore infrastrutturale nasce quando il sistema non riesce a leggere o scrivere dati — indipendentemente dalle regole del laboratorio e dall’input dell’utente. Il problema sta nel bordo tecnico del sistema: localStorage, un file JSON, un’API remota.
Esempi nel Registro:
localStorageè pieno (QuotaExceededError)localStoragenon è disponibile (navigazione in incognito su alcuni browser)JSON.parsefallisce perché il dato salvato è corrotto- Una chiamata API restituisce un errore HTTP (500, 503, timeout)
- Il file JSON non esiste o non è leggibile
Dove nasce e dove viene gestito
Infrastructure (adapter) → intercetta l'errore tecnico, lo traduce in errore leggibile
Application (caso d'uso) → può ricevere l'errore e decidere se propagarlo o gestirlo
Presentation (UI) → mostra un messaggio comprensibile all'utente
L’errore infrastrutturale non deve attraversare l’intera applicazione grezzo. Il messaggio QuotaExceededError: Failed to execute 'setItem' on 'Storage' non ha senso per l’utente. L’adapter lo intercetta e rilancia con un codice chiaro.
Come gestirlo nell’adapter localStorage
// infrastructure/archivioStrumentiLocalStorage.js
function salva(strumento) {
try {
const lista = leggiTutti();
const indice = lista.findIndex(s => s.id === strumento.id);
if (indice >= 0) lista[indice] = strumento;
else lista.push(strumento);
localStorage.setItem("registro:strumenti", JSON.stringify(lista));
} catch (errore) {
// localStorage pieno, non disponibile, o altro problema tecnico
throw new Error("ARCHIVIO_NON_DISPONIBILE");
}
}
function leggiTutti() {
try {
const raw = localStorage.getItem("registro:strumenti");
if (!raw) return [];
return JSON.parse(raw);
} catch (errore) {
// JSON corrotto o localStorage non disponibile
console.error("Errore lettura archivio:", errore);
return []; // fallback: restituisce lista vuota invece di propagare l'errore
}
}
Nota la differenza:
salvarilancia conARCHIVIO_NON_DISPONIBILE— il fallimento è bloccanteleggiTuttirestituisce[]— il fallimento è recuperabile (preferibile non bloccare il caricamento)
Come gestirlo in un adapter API
// infrastructure/archivioStrumentiAPI.js
async function salva(strumento) {
try {
const risposta = await fetch("/api/strumenti", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(strumento)
});
if (!risposta.ok) {
throw new Error("ARCHIVIO_NON_DISPONIBILE");
}
} catch (errore) {
if (errore.message === "ARCHIVIO_NON_DISPONIBILE") throw errore;
// Network error, timeout, ecc.
throw new Error("ARCHIVIO_NON_DISPONIBILE");
}
}
Il codice errore è lo stesso (ARCHIVIO_NON_DISPONIBILE) indipendentemente dal tipo di archivio — localStorage o API. Il caso d’uso non sa quale archivio sta usando.
Come il caso d’uso lo propaga
Il caso d’uso non cattura (di solito) gli errori infrastrutturali — li lascia salire alla Presentation:
// Application
async function registraPrestito(comando) {
const strumento = await archivioStrumenti.trovaPerId(comando.strumentoId);
if (!strumento) throw new Error("STRUMENTO_NON_TROVATO");
// Se salva() lancia ARCHIVIO_NON_DISPONIBILE, l'errore sale fino alla UI
await archivioPrestiti.salva(prestito);
await archivioStrumenti.salva({ ...strumento, stato: "in_prestito" });
}
// Presentation
try {
await registraPrestito(comando);
} catch (errore) {
const messaggi = {
STRUMENTO_NON_TROVATO: "Strumento non trovato.",
STRUMENTO_NON_DISPONIBILE: "Questo strumento non può essere prestato.",
ARCHIVIO_NON_DISPONIBILE: "Non riesco a salvare i dati. Riprova tra poco."
};
mostraMessaggio(messaggi[errore.message] ?? "Operazione non riuscita.");
console.error("Dettaglio tecnico:", errore);
}
Il console.error mantiene il dettaglio tecnico nel log senza mostrarlo all’utente.
Errori infrastrutturali tipici per tipo di archivio
| Archivio | Errore tecnico | Codice da usare |
|---|---|---|
| localStorage pieno | QuotaExceededError | ARCHIVIO_NON_DISPONIBILE |
| localStorage assente | TypeError su setItem | ARCHIVIO_NON_DISPONIBILE |
| JSON corrotto | SyntaxError su JSON.parse | restituire [] (fallback) |
| API non raggiungibile | TypeError: Failed to fetch | ARCHIVIO_NON_DISPONIBILE |
| API risponde con errore | HTTP 500, 503 | ARCHIVIO_NON_DISPONIBILE |
Procedura guidata
- Apri i tuoi adapter (
infrastructure/). - Ogni metodo
salvaeleggiTuttiha untry/catch? - Il
catchrilancia con un codice chiaro o restituisce un fallback? - La UI cattura
ARCHIVIO_NON_DISPONIBILEe mostra un messaggio comprensibile? - Il dettaglio tecnico viene loggato in
console.error(non mostrato all’utente)?
Attività in classe
## Errori infrastrutturali nel mio Registro
Adapter analizzato:
Metodo con possibile errore infrastrutturale:
Tipo di errore tecnico (QuotaExceeded, JSON corrotto, network...):
Strategia scelta (rilancia / fallback):
Codice errore usato:
Messaggio utente corrispondente:
Spiegazione guidata per studiare
Gli errori infrastrutturali sono i più “nascosti” nei progetti scolastici. localStorage quasi sempre funziona — finché non è pieno, o finché l’utente non apre una finestra in incognito. L’errore emerge in produzione o nei casi limite, non durante il test normale.
Il punto centrale è: l’adapter è l’unico responsabile degli errori dell’infrastruttura. Tutto ciò che sta sopra (Application, Domain, Presentation) non deve sapere come funziona localStorage o fetch — deve solo sapere che un’operazione è fallita, con un codice chiaro.
Il rischio tipico è non avere nessun try/catch negli adapter. In quel caso, un QuotaExceededError attraversa tutto il sistema e appare nella UI come errore JavaScript grezzo.
Passo per passo nel progetto
- Apri ogni metodo
salvaeleggiTuttinegli adapter. - Aggiungi
try/catchdove manca. - Nel
catch: rilancia conARCHIVIO_NON_DISPONIBILEper i fallimenti bloccanti; restituisce[]per le letture recuperabili. - Aggiungi
console.error(errore)nelcatchper conservare il dettaglio tecnico. - Verifica che la UI mostri un messaggio sensato quando l’archivio non è disponibile.
Esempio da leggere lentamente
// Adapter robusto con gestione errori
function creaArchivioStrumentiLocalStorage() {
const CHIAVE = "registro:strumenti";
function leggiTutti() {
try {
const raw = localStorage.getItem(CHIAVE);
if (!raw) return [];
return JSON.parse(raw);
} catch (errore) {
console.error("Impossibile leggere strumenti:", errore);
return []; // ← fallback: il Registro parte vuoto invece di bloccarsi
}
}
function salva(strumento) {
try {
const lista = leggiTutti();
const i = lista.findIndex(s => s.id === strumento.id);
if (i >= 0) lista[i] = strumento; else lista.push(strumento);
localStorage.setItem(CHIAVE, JSON.stringify(lista));
} catch (errore) {
console.error("Impossibile salvare strumento:", errore);
throw new Error("ARCHIVIO_NON_DISPONIBILE"); // ← bloccante: non possiamo procedere
}
}
return { leggiTutti, trovaPerId: (id) => leggiTutti().find(s => s.id === id) ?? null, salva };
}
Prova di comprensione
- Qual è la differenza tra un errore infrastrutturale e un errore applicativo?
- Perché
leggiTuttipuò restituire[]come fallback, mentresalvadeve rilanciare l’errore? - Dove deve stare il
console.error— nel dominio, nel caso d’uso o nell’adapter?
Errori da evitare
- non avere nessun
try/catchnegli adapter; - mostrare messaggi tecnici come
QuotaExceededErroroSyntaxErrorall’utente; - catturare l’errore infrastrutturale nel dominio (che non deve sapere di
localStorage); - non loggare il dettaglio tecnico — rende il debugging impossibile.
Prodotto da consegnare
Può essere:
- un adapter
leggiTuttiesalvacontry/catchcompleto; - un test che simula un archivio che fallisce e verifica che il codice errore corretto sia lanciato;
- una nota nel README che descrive il comportamento in caso di archivio non disponibile.
Checklist di chiusura
- Ogni metodo
salvanegli adapter ha untry/catch - Il
catchrilancia conARCHIVIO_NON_DISPONIBILE -
leggiTuttirestituisce[]in caso di errore (non blocca l’avvio) -
console.errorconserva il dettaglio tecnico - La UI mostra un messaggio comprensibile per
ARCHIVIO_NON_DISPONIBILE
Domande per la revisione
- I tuoi adapter hanno
try/catch? Se no, cosa succede quandolocalStorageè pieno? - Come distingueresti un errore di localStorage da un errore di rete in produzione?
- Il tuo progetto funziona (anche parzialmente) quando
localStoragenon è disponibile?
Risultato atteso
Alla fine lo studente deve saper dire:
Il mio adapter [X] gestisce gli errori infrastrutturali con try/catch.
In caso di fallimento lancia [ARCHIVIO_NON_DISPONIBILE] / restituisce [fallback].
La UI mostra: "Non riesco a salvare i dati. Riprova tra poco."
Il dettaglio tecnico viene loggato in console.error.
Se questa spiegazione non è possibile, la lezione non è ancora davvero conclusa.