modulo 03 di 24 / Ore 0-20
Moduli 1-8 / Checkpoint 20 ore
Confini: utente, interfaccia, regole e dati salvati
Imparare a disegnare i confini del sistema distinguendo utente, interfaccia, regole del dominio, casi d'uso e dati salvati.
Confini: utente, interfaccia, regole e dati salvati
Un confine è una linea che separa responsabilità diverse.
In un progetto piccolo i confini non sono sempre visibili. Il codice può stare tutto in main.js, quindi sembra che tutto appartenga allo stesso posto.
Ma anche quando non li vedi, i confini esistono.
Nel Registro del laboratorio possiamo distinguere almeno queste aree:
Utente
Interfaccia
Casi d'uso
Regole
Dati salvati
Il problema del programma fragile è che queste aree si toccano senza controllo.
Questa lezione serve a disegnare quei confini prima di spostare codice.
Obiettivo della lezione
Alla fine devi avere:
- una mappa del flusso di una operazione del Registro;
- almeno tre esempi di confine confuso nel codice fragile;
- una distinzione chiara tra UI, caso d’uso, dominio e persistenza;
- una prima idea di quali collegamenti sono accettabili e quali sono pericolosi.
Il risultato non è una nuova cartella. È una mappa.
Dal comportamento al confine
Prendiamo un’azione concreta:
Registrare un prestito
Dal punto di vista dell’utente, l’azione è semplice:
- scrive l’identificativo dello strumento;
- scrive il nome della persona che lo prende;
- preme un pulsante;
- legge un messaggio.
Dal punto di vista del programma, invece, succedono più passaggi:
- la UI legge i campi;
- un caso d’uso coordina l’operazione;
- il dominio verifica le regole;
- l’infrastruttura legge e salva dati;
- la UI mostra il risultato.
Il confine serve a non confondere questi passaggi.
Il confine tra utente e interfaccia
L’utente non chiama funzioni.
L’utente:
- scrive testo;
- seleziona uno stato;
- clicca un bottone;
- guarda una lista;
- legge un messaggio.
La UI traduce queste azioni in dati per il programma.
Esempio:
const comando = {
strumentoId: inputStrumentoId.value,
nomePersona: inputPersona.value,
};
Questa parte appartiene alla Presentation.
Sta trasformando input HTML in un oggetto JavaScript.
Fin qui va bene.
Il problema nasce quando subito dopo la UI inizia anche a decidere regole, modificare array e salvare dati.
Il confine tra interfaccia e caso d’uso
La UI può dire:
Voglio registrare questo prestito.
Non dovrebbe però gestire tutti i passaggi interni dell’operazione.
Una UI più ordinata prepara un comando e chiama un caso d’uso:
const esito = registraPrestito({
strumentoId: inputStrumentoId.value,
nomePersona: inputPersona.value,
});
mostraMessaggio(esito.messaggio);
Questo esempio è ancora semplice, ma mostra un confine:
- la UI raccoglie input;
- il caso d’uso decide il flusso;
- la UI mostra l’esito.
La UI non deve sapere come viene cercato lo strumento, come viene creato il prestito o dove vengono salvati i dati.
Il confine tra caso d’uso e dominio
Un caso d’uso coordina.
Il dominio decide le regole.
Per RegistraPrestito, il caso d’uso può fare questo:
1. riceve strumentoId e nomePersona
2. chiede all'archivio lo strumento
3. chiede al dominio se lo strumento può essere prestato
4. crea o aggiorna i dati necessari
5. salva le modifiche
6. restituisce un risultato
La regola:
uno strumento guasto non può essere prestato
non deve nascere nel bottone e non deve dipendere dal salvataggio.
Deve stare nel dominio, perché riguarda il significato del problema.
Il confine tra dominio e dati salvati
Una regola deve valere indipendentemente da dove sono salvati i dati.
La regola “uno strumento guasto non può essere prestato” deve restare vera:
- con dati in memoria;
- con
localStorage; - con un file JSON;
- con un database;
- con una API.
Se per verificare questa regola devi usare per forza localStorage, il confine è confuso.
localStorage è un dettaglio tecnico.
La regola è parte del dominio.
Questa distinzione sarà importantissima quando cambieremo infrastruttura senza riscrivere i casi d’uso.
Mappa del flusso desiderato
Per il prestito, la mappa desiderata può essere questa:
Utente
clicca "Registra prestito"
|
v
Presentation / UI
legge gli input e prepara un comando
|
v
Application / Caso d'uso
coordina RegistraPrestito
|
v
Domain / Regole
verifica se lo strumento può essere prestato
|
v
Infrastructure / Archivio
legge e salva strumenti e prestiti
|
v
Presentation / UI
mostra un messaggio comprensibile
Questa mappa non dice che il codice debba essere lungo.
Dice che ogni responsabilità ha un posto riconoscibile.
Mappa del programma fragile
Nel programma fragile, invece, spesso succede questo:
Click del bottone
legge input
cerca nello stesso array globale
controlla regole
modifica stato
crea prestito
salva in localStorage
costruisce messaggio
aggiorna HTML
Non c’è un singolo errore evidente. Il problema è l’accumulo.
Più responsabilità si accumulano nello stesso punto, più diventa difficile cambiare una cosa senza toccarne altre.
Segnali di confine rotto
Un confine è probabilmente rotto quando:
- un event listener contiene una regola importante;
- una funzione di ricerca legge direttamente input HTML;
- una regola usa
localStorage; - un messaggio utente viene costruito dentro una funzione di dominio;
- un caso d’uso usa
document.querySelector; - cambiare il salvataggio obbliga a modificare la UI;
- testare una regola richiede il browser;
- lo stesso stato viene scritto in forme diverse, per esempio
"guasto"e"GUASTO"; - un file chiamato
main.jscontiene tutto il comportamento del sistema.
Questi segnali non sono una condanna. Sono indizi.
Servono a scegliere dove intervenire nei refactoring successivi.
Collegamenti accettabili e collegamenti pericolosi
Non tutti i collegamenti tra parti del sistema sono uguali.
Alcuni sono normali:
| Collegamento | Perché è accettabile |
|---|---|
| UI chiama un caso d’uso | l’utente avvia un’operazione |
| Caso d’uso usa regole di dominio | il flusso deve rispettare le regole |
| Caso d’uso usa un archivio | deve leggere e salvare dati |
| Infrastructure trasforma dati salvati | deve adattare formati esterni |
Altri sono pericolosi:
| Collegamento | Perché crea fragilità |
|---|---|
Domain usa localStorage |
le regole dipendono da un dettaglio tecnico |
Domain usa document.querySelector |
le regole dipendono dalla pagina |
| UI decide regole di prestito | la regola si duplica facilmente |
| Infrastructure mostra messaggi utente | il salvataggio conosce la UI |
Questa è una delle idee più importanti del corso: non basta separare i nomi, bisogna controllare le direzioni dei collegamenti.
Esempio: messaggio e regola sono cose diverse
Questa frase è una regola:
uno strumento guasto non può essere prestato
Questo è un messaggio per l’utente:
Non puoi registrare il prestito: lo strumento è segnato come guasto.
Sembrano simili, ma non sono la stessa cosa.
La regola decide se l’operazione è valida.
Il messaggio spiega all’utente cosa è successo.
Se li mescoli, diventa difficile cambiare il tono del messaggio senza toccare la regola. Diventa anche difficile testare la regola senza controllare testi della UI.
Attività guidata
Scegli una sola operazione del tuo Registro fragile:
- registrare uno strumento;
- cercare strumenti;
- registrare un prestito;
- chiudere un prestito;
- aprire una segnalazione di guasto.
Disegna la mappa attuale:
Operazione scelta:
Utente:
UI:
Caso d'uso:
Regole:
Dati salvati:
Messaggi:
Poi aggiungi una seconda sezione:
Confini confusi:
1.
2.
3.
Vincolo: devi citare punti reali del codice, non frasi generiche.
Micro-sfida
Trova tre punti in cui la UI attraversa un confine.
Formato richiesto:
Punto 1
Codice o blocco: event listener "Registra prestito"
Confine attraversato: UI -> Domain
Perché: il click decide che uno strumento guasto non può essere prestato.
Dove dovrebbe andare: regola di dominio.
Ripeti lo schema per tre esempi.
Prodotto da ottenere
Alla fine della lezione devi avere:
- una mappa del flusso attuale di una operazione;
- una mappa del flusso desiderato;
- tre confini confusi individuati;
- una distinzione scritta tra regola e messaggio;
- una nota su quale confine vuoi sistemare per primo.
Domande di comprensione
Rispondi per iscritto:
- Che cosa separa un confine?
- Perché la UI non dovrebbe possedere le regole principali?
- Perché il dominio non dovrebbe conoscere
localStorage? - Che differenza c’è tra regola e messaggio utente?
- Quale confine del tuo progetto è più confuso oggi?
Controllo finale
La lezione è completata quando puoi dire sì a queste domande:
- so distinguere utente, UI, casi d’uso, regole e dati salvati;
- ho disegnato una mappa del programma fragile;
- ho trovato almeno tre confini confusi;
- so spiegare perché
localStoragenon deve influenzare le regole; - so dire cosa dovrebbe fare la UI e cosa non dovrebbe fare;
- capisco che i confini servono a rendere il cambiamento meno rischioso.
Nel prossimo passo parleremo proprio di cambiamento: alcune decisioni sono facili da modificare, altre diventano costose.