modulo 03 di 24 / Ore 0-20

Moduli 1-8 / Checkpoint 20 ore

Esempio guidato: cosa succede quando cambia la persistenza

Usare il cambio di persistenza come esempio guidato per capire perché UI, casi d'uso, dominio e infrastruttura devono avere confini chiari.

20 minArchitettura del software

Esempio guidato: cosa succede quando cambia la persistenza

Una delle domande più utili per capire l’architettura è:

cosa succede se cambio il modo in cui salvo i dati?

Nel Registro fragile il salvataggio può essere dentro gli event listener:

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

Funziona.

Ma cosa succede se domani vogliamo usare un file JSON, una piccola API o un database?

Questa lezione serve a vedere il costo reale del cambiamento.

Obiettivo della lezione

Alla fine devi avere:

  • una lista dei punti in cui il codice usa localStorage;
  • una distinzione tra persistenza, dominio, UI e caso d’uso;
  • una tabella di ciò che cambierebbe passando a JSON o API;
  • una prima idea di archivio sostituibile;
  • una frase che spiega perché il problema non è localStorage, ma la dipendenza diffusa.

Non devi ancora implementare un adapter completo. Devi capire perché servirà.

Scenario iniziale

Oggi il Registro salva nel browser.

Quando registri un prestito, il codice fragile può fare così:

strumento.stato = "in_prestito";
prestiti.push(nuovoPrestito);

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

Questo blocco sembra innocuo.

Però, se sta dentro il click del bottone, la UI conosce troppe cose:

  • conosce l’array strumenti;
  • conosce l’array prestiti;
  • conosce il formato JSON;
  • conosce le chiavi "strumenti" e "prestiti";
  • conosce il momento in cui salvare;
  • conosce anche parte delle regole di modifica dello stato.

La UI non sta solo mostrando una pagina.

Sta partecipando alla persistenza.

Il cambio richiesto

Immagina una richiesta del docente:

Vorrei esportare i dati in un file JSON, così posso consegnarli o importarli
in un altro browser.

Oppure:

Vorrei usare una piccola API locale, così più postazioni vedono gli stessi dati.

Nel codice fragile la prima reazione è cercare ogni punto in cui appare:

localStorage
JSON.stringify
JSON.parse

Probabilmente li trovi:

  • al caricamento iniziale;
  • dopo la registrazione di uno strumento;
  • dopo un prestito;
  • dopo la chiusura di un prestito;
  • dopo un cambio stato;
  • dopo una segnalazione di guasto;
  • in eventuali funzioni di reset;
  • in eventuali test manuali.

Più punti trovi, più il cambio è costoso.

Il problema non è localStorage

localStorage non è sbagliato.

È adatto a un laboratorio iniziale:

  • è disponibile nel browser;
  • non richiede server;
  • permette di vedere subito la persistenza;
  • è semplice da ispezionare con gli strumenti sviluppatore.

Il problema nasce quando il resto del progetto dipende direttamente da localStorage.

Questo è fragile:

function puoEsserePrestato(idStrumento) {
  const dati = localStorage.getItem("strumenti");
  const strumenti = JSON.parse(dati);
  const strumento = strumenti.find((item) => item.id === idStrumento);

  return strumento.stato === "disponibile";
}

La funzione sembra controllare una regola, ma in realtà:

  • legge dal browser;
  • conosce la chiave "strumenti";
  • conosce il formato salvato;
  • cerca lo strumento;
  • applica la regola.

Sono troppe responsabilità.

Una regola più pulita ragiona su uno strumento già disponibile:

function puoEsserePrestato(strumento) {
  return strumento.stato === "disponibile";
}

Questa funzione non sa nulla di browser, file, database o API.

Per questo è più facile da testare.

Che cosa dovrebbe restare stabile

Se cambio persistenza, alcune cose non dovrebbero cambiare:

Parte Perché dovrebbe restare stabile
Strumento il concetto di strumento non dipende da dove salvo
Prestito il ciclo del prestito non dipende da localStorage
Regola sul guasto uno strumento guasto non diventa prestabile perché cambio archivio
Regola sul già in prestito vale in memoria, JSON, API o database
RegistraPrestito il flusso dovrebbe restare simile
Test del dominio devono continuare a verificare le regole

Altre cose possono cambiare:

Parte Perché può cambiare
chiavi di localStorage sono dettagli tecnici
formato JSON salvato è formato esterno
endpoint API riguarda comunicazione esterna
mapping dei dati traduce tra esterno e dominio
gestione di dati mancanti dipende dal tipo di archivio

Questa distinzione è architettura pratica.

Primo schizzo di archivio

Più avanti useremo un’idea semplice:

ArchivioStrumenti
  trovaPerId(id)
  salva(strumento)
  cerca(filtri)
  elenco()

All’inizio può essere un oggetto in memoria.

Poi può diventare localStorage.

Poi può diventare JSON o API.

Il punto è che un caso d’uso dovrebbe ragionare così:

1. chiedo all'archivio lo strumento
2. applico le regole
3. chiedo all'archivio di salvare lo strumento aggiornato
4. chiedo all'archivio prestiti di salvare il nuovo prestito

Non così:

1. leggo localStorage
2. faccio JSON.parse
3. cerco nello stesso array
4. modifico l'array
5. faccio JSON.stringify
6. riscrivo localStorage

Il secondo elenco è infrastruttura travestita da caso d’uso.

Esempio di separazione minima

Prima:

function salvaDopoPrestito(strumenti, prestiti) {
  localStorage.setItem("strumenti", JSON.stringify(strumenti));
  localStorage.setItem("prestiti", JSON.stringify(prestiti));
}

Questo è ancora legato a localStorage, ma almeno il dettaglio è concentrato.

Meglio ancora, più avanti:

const archivioStrumenti = {
  salva(strumento) {
    // dettaglio tecnico qui dentro
  },
  trovaPerId(id) {
    // dettaglio tecnico qui dentro
  },
};

Per ora non serve arrivare subito alla versione completa.

Serve vedere la direzione: il dettaglio tecnico deve avere un posto.

Attività guidata

Cerca nel tuo progetto fragile tutte le occorrenze di:

localStorage
JSON.stringify
JSON.parse

Puoi usare la ricerca dell’editor oppure, se sei nel terminale:

rg "localStorage|JSON\\.stringify|JSON\\.parse" .

Per ogni occorrenza compila una tabella:

| Punto del codice | Cosa fa | Responsabilità reale | Se cambio persistenza lo tocco? |
| --- | --- | --- | --- |
| caricamento iniziale | legge strumenti | infrastruttura | sì |
| event listener prestito | salva strumenti e prestiti | UI + infrastruttura mescolate | sì |
| regola prestito | legge localStorage | dominio contaminato | sì, grave |

Se trovi localStorage dentro una funzione di dominio, segnalo nel tuo documento come priorità alta.

Micro-sfida

Immagina di sostituire localStorage con un file JSON.

Scrivi due liste:

Dovrebbe cambiare:
- il modo in cui leggo strumenti;
- il modo in cui salvo prestiti;
- il formato esterno dei dati;
- la gestione di dati mancanti o corrotti.

Non dovrebbe cambiare:
- la regola sullo strumento guasto;
- la regola sullo strumento già in prestito;
- il significato di Strumento;
- il flusso generale di RegistraPrestito;
- i test sulle regole di dominio.

Vincolo: ogni elemento deve essere collegato al Registro, non scritto in modo generico.

Prodotto da ottenere

Alla fine della lezione devi avere:

  • elenco delle occorrenze di localStorage, JSON.stringify, JSON.parse;
  • tabella con responsabilità e costo del cambio;
  • lista di cose che cambierebbero passando a JSON;
  • lista di cose che non dovrebbero cambiare;
  • primo schizzo testuale di ArchivioStrumenti;
  • una priorità di refactoring legata alla persistenza.

Domande di comprensione

Rispondi per iscritto:

  • Perché localStorage non è il problema in sé?
  • Perché una regola di dominio non dovrebbe leggere dal browser?
  • Quale parte del progetto dovrebbe conoscere JSON.stringify?
  • Che cosa significa rendere la persistenza sostituibile?
  • Quale punto del tuo codice sarebbe più costoso da cambiare se passassi a una API?

Controllo finale

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

  • ho trovato i punti che usano localStorage;
  • so spiegare perché il problema è la dipendenza diffusa, non localStorage;
  • ho distinto ciò che dovrebbe cambiare da ciò che dovrebbe restare stabile;
  • ho capito perché il dominio non deve conoscere il browser;
  • so spiegare a parole cosa sarà un archivio sostituibile.

Nel prossimo passo torneremo sul programma fragile e coloreremo i confini direttamente nel codice.