modulo 17 di 24 / Ore 41-60

Moduli 17-24 / Checkpoint 60 ore

Esercizio: confronto tra due infrastrutture

Confrontare concretamente l'archivio in memoria e l'archivio localStorage, analizzando differenze di implementazione, testabilità, persistenza e complessità.

30 min Architettura del software

Esercizio: confronto tra due infrastrutture

Questa lezione appartiene al Modulo 17 — Variante database o API.

Le due infrastrutture da confrontare

In questo esercizio confronti due adapter concreti per archivioStrumenti:

  1. Archivio in memoria — dati in un array JavaScript, persi al reload
  2. Archivio localStorage — dati persistenti nel browser, sopravvivono al reload

Entrambi rispettano lo stesso contratto: trovaPerId, salva, leggiTutti. Il caso d’uso registraPrestito non cambia — cambia solo quale adapter riceve.

Le due implementazioni

Archivio in memoria

// infrastructure/archivioStrumentiInMemoria.js
function creaArchivioStrumentiInMemoria(strumentiIniziali = []) {
  const lista = [...strumentiIniziali];

  function leggiTutti() {
    return [...lista]; // copia difensiva
  }

  function trovaPerId(id) {
    return lista.find(s => s.id === id) ?? null;
  }

  function salva(strumento) {
    const i = lista.findIndex(s => s.id === strumento.id);
    if (i >= 0) lista[i] = { ...strumento };
    else lista.push({ ...strumento });
  }

  return { leggiTutti, trovaPerId, salva };
}

Archivio localStorage

// infrastructure/archivioStrumentiLocalStorage.js
function creaArchivioStrumentiLocalStorage() {
  const CHIAVE = "registro:strumenti";

  function leggiTutti() {
    try {
      return JSON.parse(localStorage.getItem(CHIAVE) || "[]");
    } catch {
      return [];
    }
  }

  function trovaPerId(id) {
    return leggiTutti().find(s => s.id === id) ?? null;
  }

  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 {
      throw new Error("ARCHIVIO_NON_DISPONIBILE");
    }
  }

  return { leggiTutti, trovaPerId, salva };
}

Tabella di confronto

CaratteristicaIn memorialocalStorage
PersistenzaPersa al reloadSopravvive al reload
Velocità letturaImmediata (array in RAM)Leggermente più lenta (serializzazione)
Limite datiMemoria disponibile del browser~5 MB per dominio
TestabilitàEccellente — nessun effetto esternoRichiede mock o cleanup nei test
Errori possibiliNessuno in condizioni normaliQuotaExceededError, SyntaxError
ComplessitàMinimaGestione try/catch, serializzazione JSON
Condivisione datiSolo nella sessione correnteCondivisa tra tab dello stesso dominio

Cosa non cambia

Il caso d’uso è identico con entrambi gli adapter:

// main.js — cambia solo questa riga
const archivioStrumenti = creaArchivioStrumentiInMemoria();
// const archivioStrumenti = creaArchivioStrumentiLocalStorage();

const registraPrestito = creaRegistraPrestito({ archivioStrumenti, archivioPrestiti });

Nessuna modifica a registraPrestito, creaStrumento, o qualsiasi altra parte del progetto.

Quando usare quale

Usa l’archivio in memoria quando:

  • stai scrivendo test automatici — nessun side effect, zero cleanup
  • vuoi avviare rapidamente il progetto senza configurare persistenza
  • stai sviluppando una funzionalità nuova e non ti serve ancora la persistenza

Usa localStorage quando:

  • vuoi che i dati sopravvivano al reload del browser
  • stai facendo una demo e ti serve un dataset precaricato
  • il progetto è nella fase “funziona in produzione”

L’esercizio

Esegui questi passi in ordine:

  1. Apri main.js e verifica quale archivio viene usato attualmente.
  2. Registra due strumenti con l’archivio attuale — nota se sopravvivono al reload.
  3. Sostituisci l’archivio con l’altro tipo nel solo punto di composizione (main.js).
  4. Registra di nuovo due strumenti — nota la differenza di comportamento.
  5. Compila la scheda di confronto qui sotto.
  6. Ripristina l’archivio che preferisci per il proseguimento del corso.

Attività in classe

## Confronto tra due infrastrutture

Archivio A usato: in memoria / localStorage (cerchia)

Archivio B usato: in memoria / localStorage (cerchia)

Cosa cambia nel comportamento visibile (dal punto di vista dell'utente):

Cosa rimane identico (comportamento del caso d'uso):

File modificato per il cambio:

Quale archivio userò per i test e perché:

Quale archivio userò per la demo finale e perché:

Spiegazione guidata per studiare

I due adapter sono due implementazioni dello stesso contratto. Dal punto di vista del caso d’uso sono intercambiabili — entrambi hanno trovaPerId, salva, leggiTutti. La differenza è tutta nei dettagli tecnici interni.

Il punto centrale è: il contratto è il confine. Finché un adapter rispetta i metodi e le firme attesi, il resto del sistema non sa quale sta usando. Questo è il vantaggio concreto della separazione tra Application e Infrastructure.

Il rischio tipico è scegliere l’infrastruttura sbagliata per il contesto. L’archivio in memoria è perfetto per i test e per le prime fasi di sviluppo. localStorage è necessario quando serve la persistenza. Conoscere la differenza permette di scegliere consapevolmente.

Passo per passo nel progetto

  1. Verifica che entrambi gli adapter esistano nel tuo progetto (o creane uno mancante).
  2. Verifica che entrambi abbiano esattamente gli stessi metodi (leggiTutti, trovaPerId, salva).
  3. Esegui il cambio in main.js — solo quella riga.
  4. Verifica che il Registro funzioni identicamente con entrambi.
  5. Documenta la scelta nel README: quale archivio usi in produzione e quale nei test.

Esempio da leggere lentamente

// Test che funziona con entrambi gli archivi — nessuna modifica necessaria
function testRegistraStrumento(archivioStrumenti) {
  const strumento = { id: "s1", nome: "Trapano", categoria: "Utensili", stato: "disponibile" };
  archivioStrumenti.salva(strumento);
  const trovato = archivioStrumenti.trovaPerId("s1");
  console.assert(trovato !== null, "Strumento dovrebbe esistere");
  console.assert(trovato.nome === "Trapano", "Nome dovrebbe essere Trapano");
}

// Stesso test, due archivi
testRegistraStrumento(creaArchivioStrumentiInMemoria());
testRegistraStrumento(creaArchivioStrumentiLocalStorage());

Se entrambi i test passano, il contratto è rispettato e il caso d’uso può usare qualsiasi dei due.

Prova di comprensione

  • Quali metodi deve avere un adapter per essere compatibile con il caso d’uso?
  • Perché l’archivio in memoria è preferibile nei test automatici?
  • Cosa succede ai dati dell’archivio in memoria quando si ricarica la pagina?

Errori da evitare

  • modificare il caso d’uso quando si cambia archivio — non deve cambiare nulla lì;
  • usare localStorage nei test automatici senza fare cleanup — il test successivo trova dati sporchi;
  • non documentare quale archivio viene usato in quale contesto;
  • dimenticare la gestione errori nell’adapter localStorage (try/catch su JSON.parse e setItem).

Prodotto da consegnare

Può essere:

  • entrambi gli adapter implementati con gli stessi metodi;
  • la scheda di confronto compilata;
  • un test che esegue la stessa operazione su entrambi gli archivi e verifica il comportamento identico.

Checklist di chiusura

  • Entrambi gli adapter hanno leggiTutti, trovaPerId, salva
  • Il cambio avviene solo in main.js
  • Il caso d’uso non è stato modificato
  • So quale archivio usare per i test e quale per la demo
  • Il README dice quale archivio è attivo e perché

Domande per la revisione

  • Il tuo caso d’uso ha funzionato senza modifiche con entrambi gli archivi?
  • Hai trovato dipendenze nascoste che impedivano il cambio?
  • Quale archivio hai scelto per i test automatici della prossima lezione?

Risultato atteso

Alla fine lo studente deve saper dire:

Ho confrontato [archivio A] e [archivio B].
Le differenze principali sono: [lista].
Il caso d'uso non è cambiato perché [motivazione].
Per i test uso [archivio] perché [motivo].
Per la demo uso [archivio] perché [motivo].

Se questa spiegazione non è possibile, la lezione non è ancora davvero conclusa.