modulo 10 di 24 / Ore 21-40
Moduli 9-16 / Checkpoint 40 ore
Adapter localStorage e adapter JSON
Usare adapter semplici per collegare il contratto degli archivi a localStorage o a un file JSON senza cambiare i casi d'uso.
Adapter localStorage e adapter JSON
Un adapter e un pezzo di codice che collega due forme diverse.
Nel nostro progetto:
contratto ArchivioStrumenti
<-> localStorage
oppure:
contratto ArchivioStrumenti
<-> file JSON
Non serve trasformarlo in teoria.
Un adapter serve quando vogliamo far parlare il nostro codice con un dettaglio esterno mantenendo stabile il contratto.
Obiettivo
Alla fine devi avere:
- un adapter localStorage;
- una bozza di adapter JSON;
- casi d’uso invariati;
- punto di composizione che sceglie l’adapter;
- consapevolezza dei limiti di ogni adapter.
Adapter localStorage
Il nostro ArchivioStrumentiLocalStorage e gia un adapter.
Perche espone:
salva
trovaPerId
tutti
ma dentro usa:
localStorage
JSON.stringify
JSON.parse
mapping
Il caso d’uso vede il contratto.
L’adapter nasconde il dettaglio.
Schema
RegistraPrestito
usa ArchivioStrumenti
ArchivioStrumentiLocalStorage
implementa il contratto
usa localStorage
usa mapping
Questa e la separazione che ci interessa.
Adapter JSON
In un progetto browser puro non possiamo sempre scrivere file JSON locali senza strumenti aggiuntivi.
Pero possiamo simulare o preparare un adapter JSON.
Esempio in ambiente Node o in una traccia didattica:
export function creaArchivioStrumentiJson({ leggiFile, scriviFile }) {
return {
tutti() {
const dati = leggiFile();
return dati.map(dtoToStrumento);
},
trovaPerId(id) {
return this.tutti().find((strumento) => strumento.id === id) ?? null;
},
salva(strumento) {
const strumenti = this.tutti();
const indice = strumenti.findIndex((item) => item.id === strumento.id);
if (indice === -1) {
strumenti.push(strumento);
} else {
strumenti[indice] = strumento;
}
scriviFile(strumenti.map(strumentoToDto));
return strumento;
},
};
}
Qui leggiFile e scriviFile sono funzioni passate dall’esterno.
Non introduciamo dettagli del file system nei casi d’uso.
Adapter API
Piu avanti potremmo avere:
export function creaArchivioStrumentiApi({ clientHttp }) {
return {
async tutti() {
const dtoList = await clientHttp.get("/strumenti");
return dtoList.map(dtoToStrumento);
},
async trovaPerId(id) {
const dto = await clientHttp.get(`/strumenti/${id}`);
return dto ? dtoToStrumento(dto) : null;
},
async salva(strumento) {
const dto = strumentoToDto(strumento);
await clientHttp.put(`/strumenti/${strumento.id}`, dto);
return strumento;
},
};
}
Questa versione introduce asincronia.
Non la affrontiamo ora in modo completo.
La citiamo per capire che il contratto potrebbe cambiare se l’archivio diventa remoto.
Per il percorso browser/localStorage restiamo sincroni.
Scegliere l’adapter nel punto di composizione
In main.js:
const archivioStrumenti = creaArchivioStrumentiLocalStorage();
Oppure:
const archivioStrumenti = creaArchivioStrumentiInMemoria();
La scelta sta nel punto di composizione.
Non dentro RegistraPrestito.
Limiti da dichiarare
Adapter localStorage:
- semplice;
- funziona nel browser;
- non condivide dati tra dispositivi;
- ha limiti di spazio;
- i dati possono essere modificati manualmente.
Adapter JSON:
- utile per esempi o ambiente Node;
- richiede lettura/scrittura file;
- nel browser puro non e diretto;
- puo essere comodo per esercizi.
Adapter API:
- permette dati condivisi;
- richiede backend;
- introduce rete, errori, autorizzazioni e asincronia.
Non serve usare tutti.
Serve capire che sono sostituibili se rispettano il contratto.
Esercizio
Compila una tabella:
| Adapter | Dove salva | Vantaggio | Limite | Cambia il caso d'uso? |
| --- | --- | --- | --- | --- |
| In memoria | array | semplice | perde dati | no |
| localStorage | browser | persiste dopo refresh | solo locale | no |
| JSON | file | leggibile | richiede file system | no |
| API | server | condivisibile | asincronia e rete | forse |
Poi scegli quale adapter usare nella versione completa.
Cosa produrre
Alla fine della lezione devi avere:
- adapter localStorage funzionante o descritto;
- bozza di adapter JSON;
- tabella dei limiti;
- punto di composizione aggiornato;
- nota su cosa cambierebbe con API.
Spiegazione guidata per studiare
Questa lezione va studiata su due piani. Il primo è il comportamento visibile del Registro del laboratorio: che cosa vede o fa l’utente quando registra uno strumento, cerca un dispositivo, apre un prestito o segnala un guasto. Il secondo è il confine architetturale: dove deve stare il codice che rende possibile quel comportamento.
Per adapter localStorage e adapter JSON, il punto centrale è questo: L’infrastruttura è il bordo tecnico: salva, legge, chiama API, usa localStorage o file JSON. È importante, ma deve restare sostituibile.
Il rischio tipico è far entrare il formato salvato dentro il dominio. Un oggetto comodo per localStorage non è automaticamente il modello con cui ragiona il progetto. Per evitarlo, non partire dal file che hai già aperto nell’editor. Parti dalla domanda: “quale responsabilità sto modificando?”. Se la risposta riguarda una regola del laboratorio, guarda il dominio. Se riguarda una sequenza di operazioni, guarda i casi d’uso. Se riguarda salvataggio, file, localStorage, API o database, guarda l’infrastruttura. Se riguarda input, pulsanti, form e messaggi, guarda la Presentation.
Il tempo è sufficiente per alternare spiegazione, modifica guidata e revisione. Alla fine della lezione lo studente non deve ricordare una definizione a memoria: deve saper indicare un punto del progetto, spiegare perché quel codice sta lì e mostrare una verifica del comportamento.
Passo per passo nel progetto
- Rileggi il titolo della lezione e riscrivilo come domanda pratica. Per esempio: “dove deve stare questa regola?”, “chi deve salvare questo dato?”, “come verifico questo errore?”.
- Apri solo i file necessari. Se devi toccare più di tre file, fermati e scrivi prima una mini-mappa.
- Distingui modello di dominio e formato salvato.
- Crea una funzione di mapping leggibile.
- Gestisci dati mancanti o non validi.
- Verifica che i casi d’uso non cambino quando cambi archivio.
- Aggiorna una nota breve nel README o negli appunti se hai cambiato un confine del progetto.
Esempio da leggere lentamente
Questo esempio serve a ragionare, non a incollare codice senza capire:
function strumentoToDTO(strumento) {
return {
id: strumento.id,
name: strumento.nome,
category: strumento.categoria,
status: strumento.stato
};
}
Leggilo chiedendoti che cosa cambierebbe se domani sostituissimo la pagina web con una CLI, oppure localStorage con un’API. Se l’esempio continua ad avere senso senza riscrivere tutto, il confine è probabilmente buono. Se invece un dettaglio tecnico si propaga in molti file, il progetto sta tornando fragile.
Prova di comprensione
Prima di chiudere la lezione, rispondi per iscritto a queste domande:
- Qual è la responsabilità principale trattata in questa lezione?
- In quale livello del progetto dovrebbe stare?
- Quale errore faresti se cercassi la soluzione più veloce?
- Quale piccolo test, controllo manuale o esempio dimostra che hai capito?
- Che cosa deve restare facile da cambiare dopo questa lezione?
Una risposta accettabile non deve essere lunga. Deve però usare parole concrete del Registro: strumento, prestito, stato, archivio, caso d’uso, messaggio, test.
Controllo finale
La lezione e completata quando puoi rispondere si:
- so spiegare cosa fa un adapter;
- localStorage e nascosto dietro il contratto;
- il caso d’uso non conosce JSON;
- so dove scegliere l’adapter;
- so quali limiti ha localStorage;
- so perche una API richiederebbe nuove attenzioni.
Nella prossima lezione chiudiamo con una micro-sfida: cambiare archivio senza modificare il caso d’uso.