modulo 17 di 24 / Ore 41-60

Moduli 17-24 / Checkpoint 60 ore

Gestire latenza, errori e dati mancanti

Come gestire la latenza delle operazioni asincrone nel Registro (stato di caricamento nella UI), errori infrastrutturali e dati mancanti o corrotti in localStorage.

30 min Architettura del software

Gestire latenza, errori e dati mancanti

Questa lezione appartiene al Modulo 17 — Robustezza e gestione degli errori.

Obiettivo della lezione

Rendere il Registro robusto di fronte a tre problemi concreti: operazioni lente (con stato di caricamento visibile), errori infrastrutturali (localStorage pieno o non disponibile), e dati corrotti o mancanti (JSON malformato o chiavi assenti).

Alla fine il Registro non si blocca silenziosamente davanti a questi problemi — mostra un messaggio utile e continua a funzionare.

Perché serve nel percorso

localStorage è sincrono ma può fallire (modalità privata del browser, storage pieno, permessi). I dati salvati possono essere corrotti da un bug precedente. Trattare questi casi come impossibili porta a errori silenziosi che l’utente vede come “il Registro non funziona” senza capire perché.

Nel Registro del laboratorio

Problema 1 — Dati mancanti in localStorage:

// src/infrastructure/archivioStrumentiLocalStorage.js
function trovaTutti() {
  try {
    const raw = localStorage.getItem("registro_strumenti");
    if (!raw) return []; // localStorage vuoto: ok, lista vuota
    const parsed = JSON.parse(raw);
    if (!Array.isArray(parsed)) {
      console.error("[ERROR] registro_strumenti non è un array, resetto");
      return [];
    }
    return parsed.map(dtoToStrumento).filter(Boolean); // filtra DTO malformati
  } catch (err) {
    console.error("[ERROR] lettura_strumenti_fallita", err.message);
    return []; // fallback sicuro: lista vuota invece di crash
  }
}

Problema 2 — localStorage non disponibile:

// src/infrastructure/localStorageDisponibile.js
export function localStorageDisponibile() {
  try {
    const chiave = "__test__";
    localStorage.setItem(chiave, "1");
    localStorage.removeItem(chiave);
    return true;
  } catch {
    return false;
  }
}

Usalo all’avvio dell’applicazione:

// src/main.js
import { localStorageDisponibile } from "./infrastructure/localStorageDisponibile.js";

if (!localStorageDisponibile()) {
  document.getElementById("messaggio-globale").textContent =
    "Il browser non supporta il salvataggio locale. I dati non verranno conservati.";
}

Problema 3 — Stato di caricamento nella UI:

Se in futuro si passa a un’API (o anche solo si aggiunge un timeout simulato per testare), la UI deve mostrare uno stato intermedio:

// src/presentation/listaStrumenti.js
async function aggiornaListaStrumenti(archivio) {
  const contenitore = document.getElementById("lista-strumenti");
  contenitore.textContent = "Caricamento...";

  try {
    const strumenti = await archivio.trovaTutti(); // async anche se localStorage è sync
    if (strumenti.length === 0) {
      contenitore.textContent = "Nessuno strumento registrato.";
      return;
    }
    mostraStrumenti(strumenti, contenitore);
  } catch (err) {
    contenitore.textContent = "Impossibile caricare gli strumenti. Riprova.";
    console.error("[ERROR] caricamento_strumenti", err.message);
  }
}

Procedura guidata

  1. Apri archivioStrumentiLocalStorage.js e aggiungi il blocco try/catch intorno a JSON.parse.
  2. Aggiungi la verifica che il risultato del parse sia un array.
  3. Crea localStorageDisponibile.js e chiamalo in main.js all’avvio.
  4. Apri la UI della lista strumenti e aggiungi un messaggio di stato vuoto (“Nessuno strumento registrato.”).
  5. Testa il caso di dati corrotti: apri localStorage nel browser, cambia il valore di registro_strumenti in "corrotto" e ricarica la pagina.

Attività in classe

Simula un dato corrotto in localStorage:

  1. Apri il browser e vai agli strumenti di sviluppo → Application → Local Storage.
  2. Cambia il valore di registro_strumenti in "non-json".
  3. Ricarica la pagina e osserva cosa succede.
  4. Se il Registro crasha: aggiungi il try/catch nell’adapter.
  5. Se mostra lista vuota senza errori: il Registro è già robusto su questo punto.

Compila la scheda:

## Robustezza del Registro

Scenario testato: dati corrotti in localStorage
Comportamento prima della correzione:
Comportamento dopo la correzione:
File modificato:
Messaggio mostrato all'utente:

Spiegazione guidata per studiare

Ci sono tre strati di difesa per i dati mancanti o corrotti:

Strato 1 — Parse sicuro: JSON.parse può lanciare un errore se il valore non è JSON valido. Il try/catch nell’adapter trasforma questo errore tecnico in un fallback controllato (lista vuota).

Strato 2 — Validazione del DTO: anche se il JSON è valido, la struttura potrebbe essere sbagliata (un campo rinominato in una versione precedente, un valore undefined dove si aspetta una stringa). La funzione di mapping può gestire questo:

function dtoToStrumento(dto) {
  if (!dto || !dto.id || !dto.name) return null; // DTO malformato
  return {
    id: dto.id,
    nome: dto.name ?? "Senza nome",
    categoria: dto.category ?? "Senza categoria",
    stato: dto.status ?? "disponibile"
  };
}

Il .filter(Boolean) nell’adapter rimuove i null restituiti da mapping falliti.

Strato 3 — Messaggio all’utente: l’utente non deve vedere né un crash né un silenzio. Se la lista è vuota per un errore, il messaggio “Impossibile caricare gli strumenti” è più utile di una pagina bianca.

Passo per passo nel progetto

  1. Aggiungi try/catch intorno a JSON.parse in tutti gli adapter di localStorage.
  2. Verifica che il tipo del dato parsato sia corretto (array per le liste, oggetto per i singoli).
  3. Crea localStorageDisponibile.js e aggiungilo al controllo all’avvio.
  4. Aggiungi un messaggio di stato vuoto in ogni lista della UI.
  5. Aggiungi un messaggio di errore generico in ogni sezione della UI.
  6. Testa i tre scenari: localStorage vuoto, JSON corrotto, struttura dati sbagliata.

Prova di comprensione

  • Cosa succede se JSON.parse riceve la stringa "undefined"?
  • Come si gestisce un DTO in cui manca il campo id?
  • Dove deve stare la logica di fallback — nell’adapter o nel caso d’uso?
  • Come si distingue “lista vuota perché non ci sono dati” da “lista vuota perché c’è stato un errore”?

Errori da evitare

  • non mettere il try/catch intorno a JSON.parse — un valore corrotto crasha tutta l’applicazione;
  • restituire undefined invece di un array vuoto in caso di errore — il codice che chiama l’adapter si aspetta sempre un array;
  • mostrare err.message direttamente in UI — contiene dettagli tecnici incomprensibili per l’utente;
  • ignorare il caso in cui localStorage non è disponibile (modalità privata del browser).

Prodotto da consegnare

Gli adapter di localStorage con try/catch intorno al parse, il file localStorageDisponibile.js, e un messaggio di stato vuoto nella UI per ogni lista. Documentazione del comportamento in caso di dato corrotto.

Checklist di chiusura

  • JSON.parse è sempre dentro un try/catch negli adapter
  • il fallback in caso di errore è un array vuoto, non undefined
  • l’adapter valida che il risultato del parse sia del tipo atteso
  • la UI mostra un messaggio quando la lista è vuota
  • il check localStorageDisponibile() è eseguito all’avvio
  • il test con dato corrotto non crasha la pagina

Risultato atteso

Ho aggiunto try/catch intorno a JSON.parse in tutti gli adapter del Registro.
Ho creato localStorageDisponibile.js per il check all'avvio.
Ho aggiunto messaggi di stato vuoto e di errore nella UI.
Il test con dato corrotto mostra lista vuota senza crash.
Il prossimo passo sarebbe aggiungere migrazione automatica dei DTO vecchi.