modulo 02 di 24 / Ore 0-20

Moduli 1-8 / Checkpoint 20 ore

Dati, eventi, regole e salvataggio mescolati

Analizzare una versione volutamente fragile del registro in cui dati, eventi della UI, regole di dominio e salvataggio sono concentrati nello stesso punto.

20 minArchitettura del software

Dati, eventi, regole e salvataggio mescolati

Nella lezione precedente abbiamo costruito una versione fragile del Registro. Ora la guardiamo con calma.

Il punto non è dire “questo codice fa schifo”. Il punto è capire perché un codice che funziona può diventare difficile da modificare.

Quando dati, eventi, regole e salvataggio si mescolano, il programma diventa fragile perché ogni modifica tocca più responsabilità insieme.

Obiettivo della lezione

Alla fine devi saper:

  • distinguere dati, eventi, regole, messaggi e salvataggio;
  • indicare dove queste responsabilità compaiono in main.js;
  • spiegare perché il codice funziona ma resta fragile;
  • aggiungere un salvataggio volutamente diretto in localStorage;
  • osservare perché salvare non basta se non esiste anche una fase di caricamento;
  • annotare i punti che più avanti dovranno essere separati.

Non stiamo ancora facendo refactoring. Stiamo imparando a vedere.

Le responsabilità mescolate

Nel nostro main.js stanno insieme almeno quattro tipi di codice:

  1. dati;
  2. eventi della UI;
  3. regole;
  4. aggiornamento della pagina.

Se aggiungiamo localStorage, entra una quinta responsabilità:

  1. salvataggio dati.

Vediamole una per una.

Dati

Questi sono dati:

let strumenti = [
  {
    id: "str-001",
    nome: "Notebook Lenovo 01",
    categoria: "notebook",
    stato: "disponibile",
  },
];

let prestiti = [];

I dati descrivono lo stato corrente del sistema.

Per ora sono in memoria. Quando ricarichi la pagina, tornano al valore iniziale. Questo è un limite accettabile nella primissima versione, ma diventerà un problema quando vorremo conservare prestiti e stati.

Domanda utile:

questo codice descrive che cosa esiste nel registro?

Se sì, probabilmente stai guardando dati.

Eventi della UI

Questo è codice di interfaccia:

bottonePresta.addEventListener("click", () => {
  const id = inputStrumentoId.value;
  const studente = inputStudente.value;
  // ...
});

La UI legge input e reagisce a un click.

Questa responsabilità è legittima: qualcuno deve ascoltare il click del bottone. Il problema nasce quando dentro lo stesso evento finiscono anche regole importanti, salvataggio e modifiche al modello.

Domanda utile:

questo codice dipende da un bottone, da un input o dal DOM?

Se sì, sei nella Presentation, cioè nel bordo visibile del sistema.

Regole

Questa è una regola:

if (strumento.stato === "guasto") {
  messaggioElement.textContent = "Uno strumento guasto non può essere prestato";
  return;
}

La regola dice qualcosa che deve valere sempre:

uno strumento guasto non può essere prestato

Non è una preferenza grafica. Non è un dettaglio del bottone. È una regola del dominio.

Se resta nell’event listener, sarà più difficile:

  • riusarla;
  • testarla;
  • applicarla da una UI diversa;
  • proteggerla quando cambiamo il salvataggio.

Domanda utile:

questa cosa deve valere anche se cambio interfaccia?

Se sì, probabilmente è una regola di dominio.

Messaggi e aggiornamento della pagina

Questo è codice di presentazione:

messaggioElement.textContent = "Prestito registrato";
mostraStrumenti();

Serve a comunicare con l’utente e aggiornare ciò che vede.

Va bene che la UI mostri messaggi. Il problema è quando la UI decide anche le regole. Un messaggio può stare vicino all’interfaccia; la regola che produce l’errore dovrebbe diventare indipendente dalla pagina.

Domanda utile:

questo codice serve a mostrare qualcosa all'utente?

Se sì, è presentazione.

Aggiungere salvataggio nel modo più diretto

Ora aggiungiamo intenzionalmente un salvataggio fragile.

Dentro l’event listener del prestito, dopo aver modificato strumenti e prestiti, scrivi:

localStorage.setItem("strumenti", JSON.stringify(strumenti));
localStorage.setItem("prestiti", JSON.stringify(prestiti));

Il codice diventa:

strumento.stato = "in_prestito";
prestiti.push({
  id: `pre-${Date.now()}`,
  strumentoId: strumento.id,
  studente,
  aperto: true,
});

localStorage.setItem("strumenti", JSON.stringify(strumenti));
localStorage.setItem("prestiti", JSON.stringify(prestiti));

messaggioElement.textContent = "Prestito registrato";
mostraStrumenti();

Funziona. Ma ora lo stesso blocco:

  • modifica lo stato del sistema;
  • crea un prestito;
  • salva dati nel browser;
  • mostra un messaggio;
  • aggiorna la lista.

È una zona a rischio.

Perché è un problema

Il problema non è localStorage in sé. Il problema è il punto in cui lo stiamo usando.

Se domani cambi il modo di salvare i dati, devi toccare l’event listener.

Se domani cambi la UI, rischi di toccare anche il salvataggio.

Se domani vuoi testare la regola sullo strumento guasto, devi passare da input, bottone, DOM e messaggi.

Questa è la fragilità: il codice non è rotto, ma è costoso da cambiare.

Salvare non significa caricare

Dopo aver aggiunto localStorage.setItem, fai una prova:

  1. presta uno strumento;
  2. controlla in DevTools che i dati siano stati salvati;
  3. ricarica la pagina.

Probabilmente la pagina tornerà ai dati iniziali.

Perché?

Perché hai scritto dati in localStorage, ma non li hai ancora letti all’avvio.

Per caricarli nel modo più diretto potresti scrivere:

const strumentiSalvati = localStorage.getItem("strumenti");
const prestitiSalvati = localStorage.getItem("prestiti");

if (strumentiSalvati) {
  strumenti = JSON.parse(strumentiSalvati);
}

if (prestitiSalvati) {
  prestiti = JSON.parse(prestitiSalvati);
}

Anche questo funziona. Ma main.js cresce ancora: ora contiene dati iniziali, DOM, eventi, regole, salvataggio e caricamento.

Non correggerlo ancora. Annotalo.

Mappa delle responsabilità

Prendi un pezzo del codice e annotalo così:

Lettura input:
  const id = inputStrumentoId.value

Ricerca dati:
  strumenti.find(...)

Regola:
  if (strumento.stato === "guasto")

Modifica stato:
  strumento.stato = "in_prestito"

Salvataggio:
  localStorage.setItem(...)

Messaggio:
  messaggioElement.textContent = ...

Render:
  mostraStrumenti()

Questa mappa è più utile di un giudizio generico. Ti fa vedere dove il codice è mescolato.

Attività guidata

Aggiungi localStorage nel modo fragile:

  1. salva strumenti dopo un prestito;
  2. salva prestiti dopo un prestito;
  3. salva strumenti dopo aver segnato uno strumento guasto;
  4. ricarica la pagina;
  5. osserva se i dati vengono caricati oppure no;
  6. aggiungi il caricamento iniziale nel modo più diretto;
  7. annota quali nuove responsabilità sono entrate in main.js.

Questo ultimo punto è il più importante: salvare non basta. Bisogna anche leggere, gestire dati mancanti e gestire dati non validi. Se tutto resta nella UI, il file cresce in fretta.

Micro-sfida

Evidenzia il tuo main.js con commenti temporanei.

Prima di ogni blocco scrivi una di queste etichette:

// DATI
// UI
// REGOLA
// MODIFICA STATO
// SALVATAGGIO
// MESSAGGIO
// RENDER

Vincolo: non spostare ancora il codice.

Risultato atteso: il file resta fragile, ma ora sai leggere quali responsabilità contiene.

Prodotto da ottenere

Alla fine della lezione devi avere:

  • salvataggio diretto in localStorage;
  • eventuale caricamento iniziale diretto da localStorage;
  • una mappa delle responsabilità presenti in main.js;
  • almeno cinque righe o blocchi etichettati;
  • una nota su quali parti saranno difficili da testare.

Domande di comprensione

Rispondi per iscritto:

  • Qual è la differenza tra dati, regole e UI?
  • Perché localStorage è infrastruttura e non dominio?
  • Perché salvare i dati dentro l’event listener crea accoppiamento?
  • Che cosa succede se salvi i dati ma non li carichi all’avvio?
  • Quale blocco del tuo main.js contiene più responsabilità?

Controllo finale

La lezione è completata quando puoi dire sì a queste domande:

  • so distinguere dati, UI, regole, messaggi e salvataggio;
  • ho visto un esempio di salvataggio mescolato alla UI;
  • so perché questo codice può funzionare ma restare fragile;
  • ho annotato almeno cinque responsabilità dentro main.js;
  • ho capito che localStorage è infrastruttura, non dominio.

Nel prossimo passo aggiungeremo ricerca e cambio stato nel modo più diretto possibile. Il programma diventerà più utile, ma anche più difficile da tenere sotto controllo.