modulo 03 di 24 / Ore 0-20
Moduli 1-8 / Checkpoint 20 ore
Decisioni facili da cambiare e decisioni costose
Distinguere le decisioni reversibili da quelle costose, usando il Registro del laboratorio per capire quali scelte architetturali vanno prese con più attenzione.
Decisioni facili da cambiare e decisioni costose
Non tutte le decisioni tecniche pesano allo stesso modo.
Alcune decisioni sono facili da cambiare.
Altre, se vengono prese male, si attaccano a tutto il progetto.
L’architettura serve soprattutto a proteggere le decisioni che diventano costose.
Obiettivo della lezione
Alla fine devi saper:
- distinguere una decisione facile da una decisione costosa;
- spiegare perché certe scelte rendono fragile il Registro;
- riconoscere quali decisioni conviene proteggere con un confine;
- compilare una piccola tabella del costo del cambiamento;
- scegliere una decisione da sistemare nei moduli successivi.
Questa lezione non introduce nuove cartelle. Introduce una domanda:
se domani cambio questa cosa, quanto mi costa?
Decisioni facili
Sono decisioni facili quelle che hanno un impatto piccolo e locale.
Esempi:
- cambiare il testo di un bottone;
- cambiare il colore di un messaggio;
- cambiare l’ordine di due campi nel form;
- rinominare una variabile locale dentro una funzione piccola;
- aggiungere una classe CSS a un elemento.
Esempio:
messaggioElement.textContent = "Prestito registrato";
Se vuoi cambiare il testo:
messaggioElement.textContent = "Il prestito è stato registrato correttamente";
Probabilmente tocchi un solo punto.
Questa è una decisione facile. Non serve costruire un sistema complesso per ogni frase.
Decisioni costose
Sono decisioni costose quelle che influenzano molte parti del progetto.
Nel Registro del laboratorio sono costose decisioni come:
- dove stanno le regole di prestito;
- come rappresentiamo gli stati degli strumenti;
- come salviamo i dati;
- quanto la UI conosce dei casi d’uso;
- quanto il dominio dipende dal browser;
- quanto codice conosce
localStorage; - come distinguiamo messaggi utente ed errori tecnici.
Queste decisioni diventano pericolose quando sono sparse.
Se una regola vive in tre punti diversi, cambiarla non significa fare una modifica. Significa inseguire copie.
Esempio: aggiungere un nuovo stato
Immagina di aggiungere lo stato:
smarrito
Se gli stati sono scritti come stringhe sparse, devi cercare ovunque:
- nella
selectper filtrare; - nella
selectper cambiare stato; - nei controlli sul prestito;
- nel render della lista;
- nei messaggi;
- nei dati già salvati;
- nei test;
- nella documentazione.
Questa non è una modifica impossibile. È una modifica costosa.
La decisione costosa non è “aggiungere smarrito”.
La decisione costosa è avere gli stati sparsi senza un punto di riferimento unico.
Esempio: cambiare persistenza
All’inizio possiamo salvare così:
localStorage.setItem("strumenti", JSON.stringify(strumenti));
Per un prototipo va bene.
Il problema nasce se localStorage compare ovunque:
- nel click di registrazione;
- nel click di prestito;
- nella ricerca;
- nella chiusura del prestito;
- nella segnalazione di guasto;
- nel caricamento iniziale;
- nei test.
Domani potremmo voler passare a:
- un file JSON;
- una API;
- un database leggero;
- un archivio finto per i test.
Se ogni operazione conosce direttamente localStorage, cambiare persistenza significa modificare il programma intero.
Per questo più avanti creeremo un archivio sostituibile.
Esempio: mettere regole nella UI
Questa condizione sembra comoda:
if (strumento.stato === "guasto") {
messaggioElement.textContent = "Uno strumento guasto non può essere prestato";
return;
}
Funziona.
Ma se resta dentro l’event listener, la regola dipende dalla UI.
Questo diventa costoso quando:
- vuoi testare la regola senza browser;
- vuoi creare una seconda interfaccia;
- vuoi cambiare il messaggio ma non la regola;
- vuoi applicare la stessa regola anche da una API;
- vuoi aggiungere lo stato
in_manutenzione.
La decisione costosa non è scrivere un if.
La decisione costosa è mettere un if di dominio nel bordo della UI.
Tre livelli di costo
Per il laboratorio useremo una classificazione semplice:
| Costo | Significato | Esempio |
|---|---|---|
| Basso | cambia un punto solo | testo di un messaggio |
| Medio | cambia pochi punti collegati | nome pubblico di una funzione usata in due file |
| Alto | cambia molte parti o rompe confini | stati sparsi, regole nella UI, persistenza ovunque |
Non serve essere perfetti. Serve imparare a vedere il rischio.
Quando non sei sicuro, chiediti:
Questa scelta sarà citata da molte parti del progetto?
Se la risposta è sì, probabilmente merita un confine.
Decisioni reversibili e decisioni difficili da invertire
In teoria quasi tutto si può cambiare.
In pratica, alcune decisioni sono veloci da invertire e altre richiedono molte correzioni.
Una decisione è più reversibile quando:
- è concentrata in un punto;
- ha un nome chiaro;
- è coperta da test;
- non è mescolata con dettagli tecnici;
- non obbliga livelli diversi a conoscersi troppo.
Una decisione è meno reversibile quando:
- è copiata in molti file;
- dipende da stringhe libere;
- usa direttamente browser,
localStorageo DOM dentro regole importanti; - non ha test;
- non è documentata nemmeno con una frase.
Il nostro obiettivo non è prevedere tutto. È evitare che le scelte instabili si incollino ovunque.
Decisioni instabili nel Registro
Nel progetto guida sappiamo già che alcune cose cambieranno durante il corso:
| Decisione | Perché è instabile |
|---|---|
| Persistenza | passeremo da memoria a localStorage o JSON, poi forse database/API |
| Stati degli strumenti | aggiungeremo e controlleremo stati diversi |
| Regole di prestito | diventeranno più precise e testabili |
| UI | potrà cambiare senza riscrivere il dominio |
| Errori | passeremo da errori tecnici a messaggi comprensibili |
| Test | diventeranno più strutturati |
Queste sono le parti da proteggere.
Non perché siano complicate, ma perché sappiamo già che cambieranno.
Proteggere non significa complicare
Proteggere una decisione può voler dire una cosa molto semplice.
Esempio:
const StatoStrumento = {
DISPONIBILE: "disponibile",
IN_PRESTITO: "in_prestito",
GUASTO: "guasto",
IN_MANUTENZIONE: "in_manutenzione",
};
Questo non è un pattern avanzato.
È un modo per evitare stringhe sparse.
Un altro esempio:
function salvaStrumenti(strumenti) {
localStorage.setItem("strumenti", JSON.stringify(strumenti));
}
Anche questo è un passo semplice.
Non abbiamo ancora un adapter completo, ma abbiamo iniziato a isolare una scelta tecnica.
Attività guidata
Nel file note-architettura.md crea una tabella:
| Decisione | Costo se cambia | Perché | Possibile protezione |
| --- | --- | --- | --- |
| testo del messaggio di successo | basso | sta nella UI | nessuna protezione speciale |
| stati degli strumenti | alto | sono usati in filtri, regole e dati | definire StatoStrumento |
| localStorage negli event listener | alto | lega UI e persistenza | creare funzioni o archivio dedicato |
Compila almeno otto righe.
Usa decisioni del tuo codice, non esempi inventati.
Micro-sfida
Scegli una decisione costosa e scrivi una protezione futura.
Formato:
Decisione costosa:
gli stati sono stringhe sparse.
Perché costa:
se aggiungo uno stato devo modificare UI, regole, filtri e dati salvati.
Protezione futura:
creare StatoStrumento in un punto solo e usarlo in dominio, UI e test.
Quando farlo:
prima di aggiungere nuovi stati.
Vincolo: non implementare ancora la protezione. Devi solo ragionare sul costo.
Prodotto da ottenere
Alla fine della lezione devi avere:
- una tabella con almeno otto decisioni del Registro;
- una classificazione tra costo basso, medio e alto;
- almeno una decisione costosa motivata bene;
- una protezione futura scritta in modo concreto;
- una frase su cosa conviene non anticipare.
Esempio di frase accettabile:
Non anticipo un database perché oggi il problema non è il volume dei dati:
il problema è separare le regole dalla UI e rendere sostituibile la persistenza.
Domande di comprensione
Rispondi per iscritto:
- Qual è una decisione facile nel tuo Registro?
- Qual è una decisione costosa?
- Perché gli stati sparsi aumentano il costo del cambiamento?
- Perché
localStoragedentro gli event listener rende il progetto più fragile? - Che differenza c’è tra proteggere una decisione e progettare troppo?
Controllo finale
La lezione è completata quando puoi dire sì a queste domande:
- so distinguere decisioni facili e costose;
- ho analizzato almeno otto decisioni del Registro fragile;
- so spiegare perché gli stati sparsi sono costosi;
- so spiegare perché
localStoragenegli event listener è costoso; - ho scritto almeno una protezione futura;
- ho capito che architettura non significa anticipare tutto, ma proteggere ciò che cambia.
Nel prossimo passo costruiremo una mappa del sistema Registro del laboratorio, per vedere insieme utente, UI, casi d’uso, regole e dati.