modulo 09 di 24 / Ore 21-40
Moduli 9-16 / Checkpoint 40 ore
Dipendenza concreta e dipendenza da contratto
Distinguere una dipendenza da una implementazione specifica da una dipendenza da un contratto minimo condiviso.
Dipendenza concreta e dipendenza da contratto
Quando un pezzo di codice usa un altro pezzo di codice, crea una dipendenza.
La dipendenza non e sempre un problema.
Un programma senza dipendenze non fa nulla.
Il punto e capire da che cosa dipende.
Nel Registro del laboratorio vogliamo che i casi d’uso dipendano da operazioni stabili, non da dettagli tecnici troppo concreti.
Obiettivo
Alla fine devi saper distinguere:
- dipendenza concreta;
- dipendenza da contratto;
- quando una dipendenza concreta va bene;
- quando una dipendenza concreta rende difficile cambiare il progetto.
Dipendenza concreta
Questa e una dipendenza concreta:
import { creaArchivioStrumentiLocalStorage } from "../infrastructure/archivioStrumentiLocalStorage.js";
export function registraStrumento(comando) {
const archivio = creaArchivioStrumentiLocalStorage();
archivio.salva(comando);
}
Il caso d’uso conosce direttamente:
- quale archivio usare;
- dove si trova;
- come viene creato.
Se domani vogliamo usare un archivio in memoria nei test, dobbiamo cambiare il caso d’uso.
Dipendenza da contratto
Questa e una dipendenza piu flessibile:
export function creaRegistraStrumento({ archivioStrumenti }) {
return function registraStrumento(comando) {
archivioStrumenti.salva(comando);
};
}
Il caso d’uso non sa quale archivio riceve.
Sa solo che quell’oggetto deve avere un metodo:
salva(strumento)
Questo e un contratto.
Che cosa e un contratto
Un contratto e un accordo minimo.
Nel nostro caso:
Un ArchivioStrumenti deve offrire:
- salva(strumento)
- trovaPerId(id)
- tutti()
Se un oggetto offre questi metodi con il comportamento atteso, il caso d’uso puo usarlo.
Non importa se dentro usa:
- array;
- localStorage;
- file;
- API;
- database.
Contratto non significa per forza interfaccia formale
In TypeScript potremmo scrivere:
export type ArchivioStrumenti = {
salva(strumento: Strumento): void;
trovaPerId(id: string): Strumento | null;
tutti(): Strumento[];
};
In JavaScript possiamo documentarlo:
/**
* ArchivioStrumenti:
* - salva(strumento)
* - trovaPerId(id)
* - tutti()
*/
Il concetto didattico e lo stesso:
il caso d'uso lavora contro un contratto
Non contro una implementazione specifica.
Esempio nel Registro
Archivio in memoria:
const archivioStrumenti = {
salva(strumento) {
// salva in array
},
trovaPerId(id) {
// cerca in array
},
tutti() {
// restituisce array
},
};
Archivio localStorage:
const archivioStrumenti = {
salva(strumento) {
// salva in localStorage
},
trovaPerId(id) {
// legge da localStorage e cerca
},
tutti() {
// legge da localStorage
},
};
Il caso d’uso vede lo stesso contratto.
Quando la dipendenza concreta va bene
Non tutte le dipendenze concrete sono sbagliate.
Nel punto di avvio dell’applicazione e normale scrivere:
const archivioStrumenti = creaArchivioStrumentiInMemoria();
Qualcuno deve decidere quale implementazione usare.
Il problema nasce quando questa decisione entra ovunque.
Buon posto per scegliere implementazioni concrete:
main.js;- file di composizione;
- setup dei test;
- configurazione dell’app.
Cattivo posto:
- dominio;
- funzione di regola;
- caso d’uso che dovrebbe restare indipendente.
Segnale pratico
Se dentro un caso d’uso trovi:
new Qualcosa()
creaArchivioQualcosa()
localStorage
fetch
JSON.parse
chiediti:
Il caso d'uso sta scegliendo un dettaglio concreto?
Se si, valuta di passare quella dipendenza dall’esterno.
Esercizio
Classifica:
1. RegistraPrestito riceve archivioStrumenti come parametro.
2. RegistraPrestito importa archivioStrumentiLocalStorage.
3. main.js crea archivioStrumentiInMemoria.
4. Dominio usa localStorage per controllare lo stato.
5. Test passa un archivio finto al caso d'uso.
Scrivi:
dipendenza concreta accettabile
dipendenza concreta problematica
dipendenza da contratto
Possibile soluzione:
1. dipendenza da contratto
2. dipendenza concreta problematica
3. dipendenza concreta accettabile
4. dipendenza concreta problematica
5. dipendenza da contratto
Cosa produrre
Alla fine della lezione devi avere:
- una definizione di dipendenza concreta;
- una definizione di dipendenza da contratto;
- almeno tre esempi dal progetto;
- una lista di dipendenze concrete accettabili;
- una lista di dipendenze concrete da spostare.
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 dipendenza concreta e dipendenza da contratto, il punto centrale è questo: Un caso d’uso coordina un’operazione completa: riceve un comando, legge ciò che serve, applica regole, salva il risultato e restituisce un esito.
Il rischio tipico è far diventare il caso d’uso una seconda UI o un secondo database. Deve coordinare, non mostrare HTML e non conoscere dettagli tecnici di salvataggio. 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.
- Definisci input e output del caso d’uso.
- Leggi i dati attraverso un archivio o una dipendenza esplicita.
- Chiama le regole del dominio.
- Salva il risultato senza sapere come funziona la persistenza concreta.
- 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 registraPrestito(comando, archivioStrumenti, archivioPrestiti) {
const strumento = archivioStrumenti.trovaPerId(comando.strumentoId);
verificaStrumentoPrestabile(strumento);
const prestito = apriPrestito(strumento.id, comando.nomePersona);
archivioPrestiti.salva(prestito);
archivioStrumenti.salva({ ...strumento, stato: "in_prestito" });
return prestito;
}
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 cosa significa dipendere da una implementazione;
- so cosa significa dipendere da un contratto;
- so dove scegliere implementazioni concrete;
- so perche un caso d’uso dovrebbe ricevere archivi dall’esterno;
- so spiegare questa idea senza usare framework.
Nella prossima lezione definiamo il contratto ArchivioStrumenti.