modulo 06 di 24 / Ore 0-20
Moduli 1-8 / Checkpoint 20 ore
Invarianti: regole che devono valere sempre
Capire il concetto di invariante e applicarlo alle regole fondamentali del Registro del laboratorio.
Invarianti: regole che devono valere sempre
Una invariante e una regola che deve restare vera.
Non solo quando l’utente usa bene il programma.
Non solo quando la UI mostra il bottone giusto.
Sempre.
Nel Registro del laboratorio, per esempio:
Uno strumento guasto non puo essere prestato.
Questa regola deve valere anche se:
- la UI ha un bug;
- qualcuno chiama direttamente una funzione;
- un test usa dati preparati a mano;
- in futuro cambiamo localStorage con una API.
Per questo le invarianti stanno nel dominio.
Obiettivo
Alla fine devi avere:
- una lista di invarianti del Registro del laboratorio;
- esempi di violazione;
- una prima idea di dove controllarle nel codice;
- almeno un test o scenario per ogni invariante principale.
Invariante non significa regola complicata
Una invariante puo essere semplice.
Esempi:
Uno strumento deve avere un nome.
Uno strumento deve avere uno stato valido.
Uno strumento guasto non puo essere prestato.
Uno strumento in manutenzione non puo essere prestato.
Uno strumento gia in prestito non puo essere prestato di nuovo.
Un prestito chiuso non puo essere chiuso di nuovo.
Un prestito deve riferirsi a uno strumento esistente.
La forza di una invariante non sta nella complessita. Sta nel fatto che protegge il sistema da stati impossibili.
Stato impossibile
Uno stato impossibile e una combinazione di dati che non dovrebbe esistere.
Esempio:
const strumento = {
id: "s-001",
nome: "Arduino Uno",
stato: "guasto",
};
const prestito = {
id: "p-001",
strumentoId: "s-001",
stato: "aperto",
};
Qui abbiamo uno strumento guasto con un prestito aperto.
Puo succedere? Dipende dalla storia.
Se lo strumento e diventato guasto dopo la restituzione, il prestito dovrebbe essere chiuso.
Se invece lo strumento era gia guasto, il prestito non doveva aprirsi.
Quindi dobbiamo chiarire le regole.
Dove controllare le invarianti
Non basta nascondere un bottone nella UI.
Questo non e sufficiente:
if (strumento.stato === "guasto") {
buttonPresta.disabled = true;
}
E utile per l’interfaccia, ma non protegge il dominio.
La regola deve stare anche in una funzione del dominio:
export function verificaStrumentoPrestabile(strumento) {
if (strumento.stato !== "disponibile") {
throw new Error("STRUMENTO_NON_PRESTABILE");
}
}
Poi la UI puo usare questa regola indirettamente tramite il caso d’uso.
Invarianti e casi d’uso
Alcune invarianti riguardano un solo oggetto.
Esempio:
Uno strumento deve avere un nome.
Possiamo controllarla in creaStrumento.
Altre invarianti riguardano piu oggetti.
Esempio:
Uno strumento gia in prestito non puo essere prestato di nuovo.
Qui servono:
- lo strumento;
- i prestiti aperti;
- il caso d’uso che coordina l’operazione.
La regola puo essere espressa nel dominio, ma il caso d’uso dovra chiamarla al momento giusto.
Lista iniziale per il Registro
Crea una lista come questa:
# Invarianti del Registro del laboratorio
## Strumento
- Uno strumento deve avere un id.
- Uno strumento deve avere un nome.
- Uno strumento deve avere una categoria.
- Uno strumento deve avere uno stato valido.
## Prestito
- Un prestito deve avere un id.
- Un prestito deve riferirsi a uno strumento.
- Un prestito deve avere un assegnatario.
- Un prestito aperto non ha data di chiusura.
- Un prestito chiuso ha data di chiusura.
- Un prestito chiuso non puo essere chiuso di nuovo.
## Prestito di uno strumento
- Solo uno strumento disponibile puo essere prestato.
- Uno strumento guasto non puo essere prestato.
- Uno strumento in manutenzione non puo essere prestato.
- Uno strumento gia in prestito non puo essere prestato di nuovo.
Questa lista puo stare in:
docs/regole-dominio.md
oppure nel README.
Dal requisito al test
Per ogni invariante scrivi almeno uno scenario.
Esempio:
## Invariante
Uno strumento guasto non puo essere prestato.
## Scenario
Dato uno strumento con stato guasto,
quando provo a prestarlo,
allora il dominio rifiuta l'operazione.
Altro esempio:
## Invariante
Un prestito chiuso non puo essere chiuso di nuovo.
## Scenario
Dato un prestito gia chiuso,
quando provo a chiuderlo una seconda volta,
allora il dominio restituisce errore PRESTITO_GIA_CHIUSO.
Questi scenari diventeranno test.
Esercizio: trova il punto fragile
Guarda questo codice:
function registraPrestito(id, studente) {
const strumento = strumenti.find((item) => item.id === id);
prestiti.push({
id: crypto.randomUUID(),
strumentoId: id,
studente,
stato: "aperto",
});
strumento.stato = "in_prestito";
}
Quali invarianti non sono protette?
Possibili risposte:
- non controlla se lo strumento esiste;
- non controlla se lo strumento e disponibile;
- non controlla se lo strumento e guasto;
- non controlla se lo strumento e gia in prestito;
- non controlla se lo studente e indicato.
Il codice crea facilmente stati impossibili.
Cosa produrre
Alla fine della lezione devi avere:
- file o sezione
regole-dominio; - almeno dieci invarianti;
- almeno cinque scenari di violazione;
- indicazione del punto in cui ogni regola dovrebbe essere controllata;
- almeno due regole candidate per test automatici.
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 invarianti: regole che devono valere sempre, il punto centrale è questo: Il dominio contiene il significato del problema: strumenti, prestiti, stati ammessi e regole che devono valere anche se cambia la UI o il modo in cui salviamo i dati.
Il rischio tipico è confondere un controllo di schermata con una regola del progetto. Se una regola protegge il senso del Registro, deve vivere nel dominio o vicino al caso d’uso. 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.
- Scrivi la regola in linguaggio naturale.
- Trasformala in una funzione o in un metodo con un nome leggibile.
- Verifica almeno un caso valido e un caso non valido.
- Controlla che la regola non sia duplicata nella UI.
- 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 verificaStrumentoPrestabile(strumento) {
if (strumento.stato === "guasto") {
throw new Error("STRUMENTO_GUASTO_NON_PRESTABILE");
}
if (strumento.stato === "in_prestito") {
throw new Error("STRUMENTO_GIA_IN_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 spiegare cosa e una invariante;
- ho distinto regole semplici e regole che coinvolgono piu oggetti;
- ho scritto scenari per verificare le regole;
- non mi affido solo alla UI per proteggere il sistema;
- so quali invarianti useremo nelle prossime lezioni.
Ora affrontiamo una regola concreta: uno strumento guasto non puo essere prestato.