modulo 03 di 24 / Ore 0-20
Moduli 1-8 / Checkpoint 20 ore
Esercizio: evidenziare i confini nel programma fragile
Esercizio guidato per evidenziare nel programma fragile le parti che appartengono a UI, casi d'uso, dominio e infrastruttura.
Esercizio: evidenziare i confini nel programma fragile
In questa lezione non aggiungeremo funzionalità.
Faremo un esercizio di lettura: evidenziare i confini nel programma fragile.
L’obiettivo è allenare lo sguardo. Prima di separare il codice in file, devi saper riconoscere quali parti appartengono a responsabilità diverse.
Questa è una lezione di passaggio: chiude il modulo sull’architettura come responsabilità, confini e decisioni costose.
Obiettivo della lezione
Alla fine devi avere:
- tre blocchi del programma fragile annotati con etichette;
- una lista delle responsabilità trovate;
- almeno una riga ambigua discussa;
- un punto candidato per il primo refactoring;
- una nota finale che spiega cosa hai capito del programma fragile.
Non devi ancora pulire tutto. Devi vedere con precisione cosa è mescolato.
Prepara una legenda
Usa quattro etichette:
[UI]
[APPLICATION]
[DOMAIN]
[INFRASTRUCTURE]
Significato:
| Etichetta | Domanda pratica | Esempi |
|---|---|---|
[UI] |
riguarda l’interazione con l’utente? | input, bottoni, render, messaggi |
[APPLICATION] |
coordina un’operazione completa? | registrare prestito, cercare strumento, chiudere prestito |
[DOMAIN] |
decide una regola del laboratorio? | guasto non prestabile, stato valido, prestito già chiuso |
[INFRASTRUCTURE] |
parla con strumenti tecnici esterni? | localStorage, JSON, file, API, database |
Per l’esercizio puoi scrivere queste etichette come commenti temporanei nel codice o copiarle in un file di note.
Non devono restare per sempre nel progetto. Sono evidenziatori didattici.
Esempio non annotato
Partiamo da un event listener fragile:
bottonePresta.addEventListener("click", () => {
const id = inputStrumentoId.value;
const studente = inputStudente.value;
const strumento = strumenti.find((item) => item.id === id);
if (!strumento) {
messaggioElement.textContent = "Strumento non trovato";
return;
}
if (strumento.stato === "guasto") {
messaggioElement.textContent = "Uno strumento guasto non può essere prestato";
return;
}
strumento.stato = "in_prestito";
prestiti.push({
id: `pre-${Date.now()}`,
strumentoId: strumento.id,
studente,
aperto: true,
});
localStorage.setItem("strumenti", JSON.stringify(strumenti));
localStorage.setItem("prestiti", JSON.stringify(prestiti));
messaggioElement.textContent = "Prestito registrato";
mostraStrumenti(strumenti);
});
Il blocco funziona, ma contiene livelli diversi.
Esempio annotato
Ora evidenziamolo:
// [UI] evento generato da un click nella pagina
bottonePresta.addEventListener("click", () => {
// [UI] lettura dei campi del form
const id = inputStrumentoId.value;
const studente = inputStudente.value;
// [APPLICATION] cerca il dato necessario per completare l'operazione
const strumento = strumenti.find((item) => item.id === id);
// [APPLICATION] gestisce il caso in cui l'operazione non può proseguire
if (!strumento) {
// [UI] messaggio mostrato all'utente
messaggioElement.textContent = "Strumento non trovato";
return;
}
// [DOMAIN] regola: uno strumento guasto non può essere prestato
if (strumento.stato === "guasto") {
// [UI] messaggio collegato all'esito della regola
messaggioElement.textContent = "Uno strumento guasto non può essere prestato";
return;
}
// [DOMAIN] cambio di stato dello strumento
strumento.stato = "in_prestito";
// [APPLICATION] creazione del prestito come parte dell'operazione
prestiti.push({
id: `pre-${Date.now()}`,
strumentoId: strumento.id,
studente,
aperto: true,
});
// [INFRASTRUCTURE] salvataggio nel browser
localStorage.setItem("strumenti", JSON.stringify(strumenti));
localStorage.setItem("prestiti", JSON.stringify(prestiti));
// [UI] comunicazione e aggiornamento visivo
messaggioElement.textContent = "Prestito registrato";
mostraStrumenti(strumenti);
});
Questa annotazione non è perfetta.
Va bene così.
Serve a vedere il problema: dentro un solo click ci sono UI, coordinamento, regole e persistenza.
Righe ambigue
Alcune righe non sono facili da etichettare.
Esempio:
const strumento = strumenti.find((item) => item.id === id);
Potresti dire:
- è dominio, perché parla di strumenti;
- è applicazione, perché serve al caso d’uso;
- è infrastruttura, perché sta cercando dati in un archivio in memoria.
In questa fase la cosa importante non è scegliere l’etichetta perfetta.
La cosa importante è discutere il motivo.
Una scelta ragionevole è [APPLICATION], perché la riga serve a coordinare l’operazione RegistraPrestito: prima devo trovare lo strumento, poi posso applicare le regole.
Più avanti, quando avremo un archivio, questa responsabilità potrà spostarsi dietro un metodo come:
archivioStrumenti.trovaPerId(id);
Sequenza dei livelli
Dopo l’annotazione potresti vedere una sequenza come questa:
[UI]
[APPLICATION]
[UI]
[DOMAIN]
[UI]
[DOMAIN]
[APPLICATION]
[INFRASTRUCTURE]
[UI]
Questa sequenza è il motivo per cui il blocco è fragile.
Il problema non è che esista la UI.
Il problema non è che esista localStorage.
Il problema è che tutti i livelli sono agganciati nello stesso punto.
Cosa annotare nel file di note
Nel file note-architettura.md aggiungi una sezione così:
## Confini individuati nel codice fragile
### Event listener Registra prestito
- UI: legge input e mostra messaggi.
- Application: cerca lo strumento e coordina la creazione del prestito.
- Domain: controlla lo stato dello strumento e decide se il prestito è permesso.
- Infrastructure: salva strumenti e prestiti in localStorage.
Problema:
tutti questi livelli sono nello stesso blocco.
Possibile evoluzione:
estrarre prima una regola di dominio, poi un caso d'uso, poi un archivio.
Questa nota prepara il lavoro dei moduli successivi.
Non è documentazione decorativa: è una lista di interventi futuri.
Attività guidata
Scegli tre blocchi del tuo programma fragile:
- registrazione prestito;
- cambio stato;
- ricerca strumenti.
Per ciascuno:
- aggiungi etichette temporanee
[UI],[APPLICATION],[DOMAIN],[INFRASTRUCTURE]; - scrivi quali responsabilità compaiono;
- segnala almeno una riga ambigua;
- indica la responsabilità che separeresti per prima.
Non modificare ancora il comportamento.
Questa è lettura architetturale, non refactoring.
Micro-sfida
Trova un blocco che contiene almeno tre etichette diverse.
Poi rispondi:
Blocco:
Etichette presenti:
Responsabilità più urgente da separare:
Perché proprio quella:
Comportamento da proteggere prima di modificare:
Esempio:
Responsabilità più urgente da separare:
la regola "uno strumento guasto non può essere prestato".
Perché proprio quella:
deve valere anche fuori dalla UI ed è facile da testare.
Comportamento da proteggere:
quando provo a prestare uno strumento guasto, il prestito non viene creato.
Prodotto da ottenere
Alla fine della lezione devi avere:
- tre blocchi annotati;
- una tabella o lista delle responsabilità trovate;
- almeno una riga ambigua spiegata;
- una nota
Confini individuati nel codice fragile; - un primo refactoring candidato;
- una frase che spiega perché non conviene riscrivere tutto subito.
Esempio:
Non riscrivo tutto subito perché prima devo proteggere i comportamenti già
funzionanti e separare una responsabilità alla volta.
Domande di comprensione
Rispondi per iscritto:
- Perché annotare i livelli prima di spostare codice?
- Quale blocco contiene più responsabilità nel tuo progetto?
- Quale riga ti è sembrata più ambigua?
- Quale responsabilità separeresti per prima?
- Quale comportamento devi verificare prima di fare refactoring?
Controllo finale
La lezione è completata quando puoi dire sì a queste domande:
- ho etichettato almeno tre blocchi di codice fragile;
- so riconoscere UI, Application, Domain e Infrastructure;
- ho capito che alcune righe possono essere ambigue;
- ho scritto una nota sui confini individuati;
- ho trovato un punto candidato per il primo refactoring;
- so spiegare perché non serve riscrivere tutto subito.
Hai chiuso il Modulo 3. Ora hai una mappa del problema: sai che cosa funziona, cosa è fragile, quali confini sono confusi e quali decisioni rischiano di diventare costose.
Nel prossimo modulo entreremo in responsabilità, coesione e accoppiamento in modo più operativo.