modulo 09 di 24 / Ore 21-40
Moduli 9-16 / Checkpoint 40 ore
Usare un archivio in memoria attraverso l'interfaccia
Adattare l'archivio in memoria al contratto ArchivioStrumenti e usarlo senza legare i casi d'uso alla sua implementazione.
Usare un archivio in memoria attraverso l’interfaccia
Abbiamo definito il contratto ArchivioStrumenti.
Ora verifichiamo che l’archivio in memoria lo rispetti.
L’obiettivo non e scrivere un archivio complicato.
L’obiettivo e fare in modo che il caso d’uso non debba sapere che l’archivio e in memoria.
Obiettivo
Alla fine devi avere:
- un archivio in memoria che rispetta il contratto;
- un caso d’uso che lo usa tramite metodi minimi;
- una piccola verifica manuale o test;
- una lista di dettagli dell’archivio che il caso d’uso non conosce.
Contratto da rispettare
Ricordiamo:
ArchivioStrumenti
- salva(strumento)
- trovaPerId(id)
- tutti()
Qualsiasi archivio che offre queste operazioni puo essere usato dai casi d’uso.
Implementazione in memoria
File:
src/infrastructure/archivioStrumentiInMemoria.js
Codice:
export function creaArchivioStrumentiInMemoria(datiIniziali = []) {
const strumenti = [...datiIniziali];
return {
salva(strumento) {
const indice = strumenti.findIndex((item) => item.id === strumento.id);
if (indice === -1) {
strumenti.push(strumento);
} else {
strumenti[indice] = strumento;
}
return strumento;
},
trovaPerId(id) {
return strumenti.find((strumento) => strumento.id === id) ?? null;
},
tutti() {
return [...strumenti];
},
};
}
Questo archivio usa un array interno.
Il caso d’uso non deve saperlo.
Uso dal caso d’uso
Esempio:
export function creaRegistraStrumento({ archivioStrumenti }) {
return function registraStrumento(comando) {
const strumento = creaStrumento(comando);
archivioStrumenti.salva(strumento);
return strumento;
};
}
Qui il caso d’uso non chiama:
strumenti.push(...)
Chiama:
archivioStrumenti.salva(strumento)
Questa e la differenza importante.
Verifica manuale
Puoi scrivere:
const archivio = creaArchivioStrumentiInMemoria();
archivio.salva({
id: "s-001",
nome: "Arduino Uno",
categoria: "microcontrollori",
stato: "disponibile",
});
console.log(archivio.trovaPerId("s-001"));
console.log(archivio.tutti());
Risultato atteso:
trovaPerId restituisce Arduino Uno
tutti restituisce una lista con Arduino Uno
Poi aggiorna:
archivio.salva({
id: "s-001",
nome: "Arduino Uno",
categoria: "microcontrollori",
stato: "in_prestito",
});
Risultato atteso:
lo stesso id non crea un duplicato
lo stato diventa in_prestito
Dettagli nascosti
Il caso d’uso non sa:
- che i dati sono in un array;
- che
salvafa push o update; - che
tuttirestituisce una copia; - che i dati spariscono al refresh;
- come viene cercato l’id.
Questi dettagli stanno in Infrastructure.
Interfaccia non significa magia
In JavaScript l’interfaccia non e obbligatoriamente una parola chiave.
E un accordo:
se hai questi metodi, puoi essere usato come ArchivioStrumenti
Questo e sufficiente per il laboratorio.
Piu avanti TypeScript puo rendere l’accordo esplicito nel codice.
ArchivioPrestiti
Fai lo stesso per i prestiti:
export function creaArchivioPrestitiInMemoria(datiIniziali = []) {
const prestiti = [...datiIniziali];
return {
salva(prestito) {
const indice = prestiti.findIndex((item) => item.id === prestito.id);
if (indice === -1) {
prestiti.push(prestito);
} else {
prestiti[indice] = prestito;
}
return prestito;
},
trovaPerId(id) {
return prestiti.find((prestito) => prestito.id === id) ?? null;
},
tutti() {
return [...prestiti];
},
};
}
La forma e simile.
Non estrarre subito una fabbrica generica se rende il codice meno chiaro per la classe.
Esercizio
Compila:
# Verifica ArchivioStrumentiInMemoria
Metodo: salva
Scenario:
Risultato atteso:
Metodo: trovaPerId
Scenario:
Risultato atteso:
Metodo: tutti
Scenario:
Risultato atteso:
Dettagli nascosti al caso d'uso:
- ...
Poi verifica che RegistraStrumento usi solo il contratto.
Cosa produrre
Alla fine della lezione devi avere:
- archivio in memoria conforme al contratto;
- verifica di
salva,trovaPerId,tutti; - caso d’uso che usa l’archivio senza conoscere l’array interno;
- nota sui dettagli nascosti;
- eventuale archivio prestiti coerente.
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 usare un archivio in memoria attraverso l’interfaccia, 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:
- l’archivio in memoria rispetta il contratto;
- il caso d’uso non usa array globali;
salvainserisce o aggiorna;trovaPerIdrestituiscenullse non trova;- posso sostituire l’archivio se mantengo gli stessi metodi.
Nella prossima lezione passiamo esplicitamente le dipendenze al caso d’uso.