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à.
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:
- Archivio in memoria — dati in un array JavaScript, persi al reload
- 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
| Caratteristica | In memoria | localStorage |
|---|---|---|
| Persistenza | Persa al reload | Sopravvive al reload |
| Velocità lettura | Immediata (array in RAM) | Leggermente più lenta (serializzazione) |
| Limite dati | Memoria disponibile del browser | ~5 MB per dominio |
| Testabilità | Eccellente — nessun effetto esterno | Richiede mock o cleanup nei test |
| Errori possibili | Nessuno in condizioni normali | QuotaExceededError, SyntaxError |
| Complessità | Minima | Gestione try/catch, serializzazione JSON |
| Condivisione dati | Solo nella sessione corrente | Condivisa 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:
- Apri
main.jse verifica quale archivio viene usato attualmente. - Registra due strumenti con l’archivio attuale — nota se sopravvivono al reload.
- Sostituisci l’archivio con l’altro tipo nel solo punto di composizione (
main.js). - Registra di nuovo due strumenti — nota la differenza di comportamento.
- Compila la scheda di confronto qui sotto.
- 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
- Verifica che entrambi gli adapter esistano nel tuo progetto (o creane uno mancante).
- Verifica che entrambi abbiano esattamente gli stessi metodi (
leggiTutti,trovaPerId,salva). - Esegui il cambio in
main.js— solo quella riga. - Verifica che il Registro funzioni identicamente con entrambi.
- 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/catchsuJSON.parseesetItem).
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.