modulo 09 di 24 / Ore 21-40
Moduli 9-16 / Checkpoint 40 ore
Il problema: cambiare archivio senza riscrivere i casi d'uso
Capire perché un caso d'uso non deve dipendere direttamente da un archivio concreto se vogliamo cambiare persistenza senza riscrivere il progetto.
Il problema: cambiare archivio senza riscrivere i casi d’uso
Al checkpoint 20 ore abbiamo una versione essenziale del Registro del laboratorio.
Funziona con un archivio in memoria.
Questo va bene per iniziare, ma ha un limite evidente:
se ricarico la pagina, i dati spariscono.
Prima o poi vorremo passare a:
localStorage;- file JSON;
- database;
- API.
La domanda del modulo e:
Come faccio a cambiare archivio senza riscrivere i casi d'uso?
Obiettivo
Alla fine devi capire:
- perche dipendere da un archivio concreto rende il codice rigido;
- che cosa significa sostituire una infrastruttura;
- perche i casi d’uso devono chiedere operazioni, non dettagli tecnici;
- quali parti del progetto devono restare stabili quando cambia la persistenza.
Il caso fragile
Immagina un caso d’uso scritto cosi:
export function registraStrumento(comando) {
const strumenti = JSON.parse(localStorage.getItem("strumenti") ?? "[]");
const strumento = creaStrumento(comando);
strumenti.push(strumento);
localStorage.setItem("strumenti", JSON.stringify(strumenti));
return strumento;
}
Funziona.
Pero RegistraStrumento ora conosce:
localStorage;- JSON;
- la chiave
"strumenti"; - il formato di salvataggio.
Il caso d’uso non sta solo coordinando l’operazione. Sta anche decidendo un dettaglio di infrastruttura.
Che cosa succede se cambia archivio
Se vogliamo passare da localStorage a una API, dovremmo modificare il caso d’uso:
await fetch("/api/strumenti", {
method: "POST",
body: JSON.stringify(strumento),
});
Se poi passiamo a un file JSON, cambiamo di nuovo.
Se poi usiamo un database, cambiamo ancora.
Il problema non e cambiare una riga.
Il problema e che ogni scelta tecnica entra nei casi d’uso e li sporca.
Cosa deve sapere un caso d’uso
Un caso d’uso come RegistraStrumento ha bisogno di una cosa semplice:
salvare uno strumento
Non ha bisogno di sapere:
- se lo strumento finisce in un array;
- se viene serializzato in JSON;
- se viene scritto in localStorage;
- se viene mandato a una API;
- se viene salvato in database.
Questi sono dettagli.
La frase chiave
Nel nostro corso useremo questa idea:
Il caso d'uso dipende da cio che gli serve, non da come viene realizzato.
Esempio:
Mi serve un archivio strumenti.
Deve permettere di salvare, cercare per id e leggere tutti gli strumenti.
Non mi interessa se dentro usa memoria, localStorage o API.
Questa e la base del concetto di interfaccia.
Prima forma del problema
Nel Modulo 8 abbiamo scritto archivi in memoria.
Esempio:
const archivioStrumenti = creaArchivioStrumentiInMemoria();
Il caso d’uso puo usarlo cosi:
archivioStrumenti.salva(strumento);
archivioStrumenti.trovaPerId(id);
archivioStrumenti.tutti();
Queste operazioni sono piu importanti dell’implementazione.
La vera domanda diventa:
Quali operazioni deve garantire qualsiasi archivio strumenti?
Archivio come dettaglio sostituibile
Vogliamo arrivare a questa situazione:
const archivioStrumenti = creaArchivioStrumentiInMemoria();
oppure:
const archivioStrumenti = creaArchivioStrumentiLocalStorage();
oppure:
const archivioStrumenti = creaArchivioStrumentiApi();
E il caso d’uso resta uguale:
const registraStrumento = creaRegistraStrumento({
archivioStrumenti,
});
Questo e il risultato che vogliamo.
Cosa deve restare stabile
Quando cambiamo archivio, non vogliamo modificare:
- dominio;
- regole;
- casi d’uso;
- test principali del comportamento;
- UI, se i dati restituiti hanno la stessa forma.
Potremmo dover modificare:
- file di infrastructure;
- punto di composizione;
- test specifici dell’archivio;
- gestione di errori tecnici.
Questa e una buona separazione.
Esercizio
Prendi il tuo progetto e cerca:
localStorage
JSON.parse
JSON.stringify
fetch
strumenti.push
prestiti.push
Per ogni occorrenza chiediti:
Questa riga sta in un caso d'uso?
Sta nella UI?
Sta in infrastructure?
Se localStorage o JSON.parse stanno in Application o Domain, annota il problema.
Non devi correggere tutto subito.
Devi vedere dove la persistenza concreta e entrata nel codice.
Scheda di analisi
Compila:
# Cambiare archivio
Archivio attuale:
Operazioni usate dai casi d'uso:
- ...
Dettagli concreti presenti nei casi d'uso:
- ...
Dettagli concreti presenti nella UI:
- ...
File che dovrebbero stare in Infrastructure:
- ...
Primo cambio che vorrei poter fare:
Cosa produrre
Alla fine della lezione devi avere:
- una lista dei punti in cui il codice dipende da un archivio concreto;
- una lista delle operazioni che un archivio deve offrire;
- almeno un esempio di caso d’uso troppo legato alla persistenza;
- una domanda guida scritta nel README o negli appunti: “come cambio archivio senza cambiare il caso d’uso?”.
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 il problema: cambiare archivio senza riscrivere i casi d’uso, 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 perche
localStoragedentro un caso d’uso e un problema; - so distinguere operazione richiesta e dettaglio tecnico;
- ho individuato quali metodi servono all’archivio;
- so cosa dovrebbe restare stabile quando cambio persistenza;
- ho capito il problema che l’interfaccia risolve.
Nella prossima lezione distinguiamo dipendenza concreta e dipendenza da contratto.