modulo 06 di 24 / Ore 0-20
Moduli 1-8 / Checkpoint 20 ore
Modellare Prestito: apertura, chiusura e responsabilità
Definire il modello Prestito come ciclo di vita distinto dallo strumento: apertura, chiusura, dati necessari e responsabilità.
Modellare Prestito: apertura, chiusura e responsabilità
Uno strumento è una cosa. Un prestito è un fatto che accade nel tempo.
Questa distinzione è fondamentale. Lo strumento “Arduino Uno” può esistere nel laboratorio per anni. Un prestito invece inizia in un certo giorno, coinvolge una persona o un gruppo, e prima o poi viene chiuso.
Se confondiamo strumento e prestito, all’inizio il programma sembra più semplice. Poi però diventa difficile rispondere a domande normali:
- chi ha preso lo strumento?
- quando è iniziato il prestito?
- il prestito è ancora aperto?
- quando è stato restituito?
- lo strumento è tornato funzionante o con problemi?
- ci sono stati prestiti precedenti dello stesso strumento?
In questa lezione modelliamo Prestito come concetto separato.
Obiettivo della lezione
Alla fine devi avere un primo modello Prestito con:
id;strumentoId;assegnatario;apertoIl;chiusoIl;stato;- funzione
apriPrestito; - funzione
chiudiPrestito; - regola che impedisce di chiudere due volte lo stesso prestito.
Devi anche saper spiegare la differenza tra:
- cambiare lo stato corrente dello strumento;
- registrare il ciclo di vita di un prestito.
Perché non mettere tutto dentro Strumento
Una soluzione fragile potrebbe essere questa:
const strumento = {
id: "str-001",
nome: "Arduino Uno",
categoria: "microcontrollori",
stato: "in_prestito",
prestatoA: "Luca Rossi 3A",
dataPrestito: "2026-05-09",
restituito: false,
};
Per una prima demo può funzionare. Ma dentro lo stesso oggetto abbiamo mescolato due cose diverse:
- dati dello strumento;
- dati del prestito corrente.
Il problema compare appena vogliamo conservare informazioni più precise. Se lo stesso Arduino viene prestato tre volte, dove mettiamo i tre prestiti? Se torna guasto, il guasto appartiene allo strumento o alla chiusura del prestito? Se vogliamo sapere quanto è durato un prestito precedente, abbiamo ancora quei dati?
Lo stato dello strumento dice la condizione corrente:
disponibile
in_prestito
guasto
in_manutenzione
Il prestito racconta una relazione temporanea:
questo strumento è stato assegnato a questa persona da questa data a questa data
Sono collegati, ma non sono la stessa cosa.
Modello minimo di prestito
Un prestito aperto può essere rappresentato così:
const prestito = {
id: "pre-001",
strumentoId: "str-001",
assegnatario: "Luca Rossi 3A",
apertoIl: "2026-05-09",
chiusoIl: null,
stato: "aperto",
};
Campi:
id: identifica il prestito;strumentoId: collega il prestito allo strumento;assegnatario: indica a chi è stato dato lo strumento;apertoIl: data di apertura;chiusoIl: data di chiusura, se il prestito è chiuso;stato: indica se il prestito è aperto o chiuso.
La parola assegnatario è volutamente generica. Può essere uno studente, un gruppo, una classe o un docente. Se nel tuo contesto serve essere più precisi, puoi usare studente o ricevente, ma scegli una parola e mantienila in tutto il progetto.
Stato del prestito
Per ora usiamo solo due stati:
aperto
chiuso
Possiamo definirli in src/domain/prestito.js:
export const StatoPrestito = {
APERTO: "aperto",
CHIUSO: "chiuso",
};
Non serve aggiungere subito stati come:
scaduto
annullato
contestato
in_verifica
Sono possibili estensioni future. Per il percorso attuale ci basta modellare bene apertura e chiusura.
Aprire un prestito
File:
src/domain/prestito.js
Prima funzione:
export const StatoPrestito = {
APERTO: "aperto",
CHIUSO: "chiuso",
};
export function apriPrestito({ id, strumentoId, assegnatario, apertoIl }) {
if (!id || id.trim() === "") {
throw new Error("ID_PRESTITO_OBBLIGATORIO");
}
if (!strumentoId || strumentoId.trim() === "") {
throw new Error("STRUMENTO_PRESTITO_OBBLIGATORIO");
}
if (!assegnatario || assegnatario.trim() === "") {
throw new Error("ASSEGNATARIO_PRESTITO_OBBLIGATORIO");
}
if (!apertoIl) {
throw new Error("DATA_APERTURA_PRESTITO_OBBLIGATORIA");
}
return {
id: id.trim(),
strumentoId: strumentoId.trim(),
assegnatario: assegnatario.trim(),
apertoIl,
chiusoIl: null,
stato: StatoPrestito.APERTO,
};
}
Questa funzione controlla che il prestito abbia i dati minimi per esistere.
Nota importante: qui non controlliamo ancora se lo strumento è disponibile. Perché? Perché questa funzione riceve solo i dati del prestito. La disponibilità riguarda anche lo strumento. Sarà responsabilità del caso d’uso RegistraPrestito coordinare il controllo:
trova strumento -> verifica se è prestabile -> apri prestito -> cambia stato strumento -> salva
Questa distinzione evita di trasformare Prestito in un oggetto che sa tutto del sistema.
Chiudere un prestito
Un prestito aperto può essere chiuso. Un prestito chiuso non può essere chiuso di nuovo.
Funzione:
export function chiudiPrestito(prestito, chiusoIl) {
if (prestito.stato === StatoPrestito.CHIUSO) {
throw new Error("PRESTITO_GIA_CHIUSO");
}
if (!chiusoIl) {
throw new Error("DATA_CHIUSURA_PRESTITO_OBBLIGATORIA");
}
return {
...prestito,
chiusoIl,
stato: StatoPrestito.CHIUSO,
};
}
Questa regola appartiene al dominio:
Un prestito chiuso non può essere chiuso di nuovo.
Non dipende dalla UI. Non dipende da localStorage. Non dipende dal pulsante che l’utente clicca. È una regola del ciclo di vita del prestito.
Perché restituiamo un nuovo oggetto
Nell’esempio chiudiPrestito restituisce un nuovo oggetto:
return {
...prestito,
chiusoIl,
stato: StatoPrestito.CHIUSO,
};
Invece di modificare direttamente:
prestito.chiusoIl = chiusoIl;
prestito.stato = StatoPrestito.CHIUSO;
Per questo corso non serve trasformare l’immutabilità in una regola assoluta. Però restituire un nuovo oggetto ha un vantaggio didattico: rende più chiaro che la funzione prende un prestito aperto e produce una versione chiusa.
È più facile da testare e riduce gli effetti nascosti. Se in un progetto futuro preferirai mutare l’oggetto, dovrai farlo consapevolmente.
Esempio di apertura valida
const prestito = apriPrestito({
id: "pre-001",
strumentoId: "str-001",
assegnatario: "Luca Rossi 3A",
apertoIl: "2026-05-09",
});
Risultato atteso:
{
id: "pre-001",
strumentoId: "str-001",
assegnatario: "Luca Rossi 3A",
apertoIl: "2026-05-09",
chiusoIl: null,
stato: "aperto",
}
Esempi non validi
Senza assegnatario:
apriPrestito({
id: "pre-002",
strumentoId: "str-001",
assegnatario: "",
apertoIl: "2026-05-09",
});
Errore atteso:
ASSEGNATARIO_PRESTITO_OBBLIGATORIO
Senza strumento:
apriPrestito({
id: "pre-003",
strumentoId: "",
assegnatario: "Sara Verdi 4B",
apertoIl: "2026-05-09",
});
Errore atteso:
STRUMENTO_PRESTITO_OBBLIGATORIO
Senza data di apertura:
apriPrestito({
id: "pre-004",
strumentoId: "str-002",
assegnatario: "Gruppo robotica",
apertoIl: null,
});
Errore atteso:
DATA_APERTURA_PRESTITO_OBBLIGATORIA
Esempio di chiusura
const prestitoAperto = apriPrestito({
id: "pre-001",
strumentoId: "str-001",
assegnatario: "Luca Rossi 3A",
apertoIl: "2026-05-09",
});
const prestitoChiuso = chiudiPrestito(prestitoAperto, "2026-05-16");
Risultato atteso:
{
id: "pre-001",
strumentoId: "str-001",
assegnatario: "Luca Rossi 3A",
apertoIl: "2026-05-09",
chiusoIl: "2026-05-16",
stato: "chiuso",
}
Se proviamo a chiuderlo di nuovo:
chiudiPrestito(prestitoChiuso, "2026-05-17");
Errore atteso:
PRESTITO_GIA_CHIUSO
Questa è una delle regole più semplici e importanti del dominio.
Responsabilità del modello Prestito
Il modello Prestito deve sapere:
- quali dati minimi servono per aprire un prestito;
- quando un prestito è aperto;
- quando un prestito è chiuso;
- quando un prestito può essere chiuso;
- come produrre una versione chiusa del prestito.
Non deve sapere:
- come leggere i dati dal form;
- come salvare in
localStorage; - come mostrare il messaggio di conferma;
- come cercare lo strumento in archivio;
- come cambiare lo stato dello strumento;
- come generare tutta la pagina HTML.
Queste responsabilità stanno in altri livelli.
Prestito e caso d’uso
Attenzione: aprire un prestito nel dominio non è lo stesso che registrare un prestito nel sistema.
La funzione apriPrestito costruisce un prestito valido. Il caso d’uso RegistraPrestito dovrà coordinare un’operazione più ampia:
1. ricevere il comando dalla UI;
2. trovare lo strumento nell'archivio;
3. verificare che lo strumento sia prestabile;
4. creare il prestito;
5. cambiare lo stato dello strumento in in_prestito;
6. salvare prestito e strumento aggiornato;
7. restituire un risultato alla UI.
Questa sequenza non deve stare tutta nel dominio Prestito. Il dominio offre regole e piccoli comportamenti. Il caso d’uso mette insieme i pezzi.
Questa distinzione tornerà spesso nel corso.
Scheda del modello
Aggiorna docs/modello-dominio.md o il README:
# Modello Prestito
## Scopo
Rappresenta l'assegnazione temporanea di uno strumento a una persona o a un gruppo.
## Campi
- id: identificativo stabile del prestito.
- strumentoId: id dello strumento prestato.
- assegnatario: persona o gruppo che riceve lo strumento.
- apertoIl: data di apertura del prestito.
- chiusoIl: data di chiusura, se il prestito è chiuso.
- stato: aperto o chiuso.
## Regole minime
- id obbligatorio.
- strumentoId obbligatorio.
- assegnatario obbligatorio.
- data di apertura obbligatoria.
- un prestito aperto può essere chiuso.
- un prestito chiuso non può essere chiuso di nuovo.
## Domande aperte
- Serve registrare chi ha autorizzato il prestito?
- Serve una data prevista di restituzione?
- Serve distinguere studente, gruppo e docente?
- Serve registrare problemi alla chiusura del prestito?
Le domande aperte ci preparano alle estensioni, ma non devono bloccare il modello minimo.
Attività pratica
Scrivi tre prestiti validi:
- uno per un Arduino;
- uno per un multimetro;
- uno per un kit sensori.
Poi scrivi quattro casi non validi:
- senza id;
- senza
strumentoId; - senza assegnatario;
- senza data di apertura.
Infine prendi un prestito valido e chiudilo. Poi prova a chiuderlo una seconda volta e annota l’errore atteso.
Per ogni caso scrivi:
- input;
- risultato atteso;
- regola che stai verificando.
Cosa produrre
Alla fine della lezione devi avere:
- file
src/domain/prestito.js; - costante
StatoPrestito; - funzione
apriPrestito; - funzione
chiudiPrestito; - almeno tre esempi validi;
- almeno quattro esempi non validi;
- una nota che distingue
StrumentoePrestito; - scheda del modello
Prestitonel README o indocs/modello-dominio.md.
Controllo finale
La lezione è completata quando puoi rispondere sì a queste domande:
- so spiegare la differenza tra strumento e prestito;
- un prestito ha un proprio id;
- un prestito si collega allo strumento tramite
strumentoId; - un prestito aperto può essere chiuso;
- un prestito chiuso non può essere richiuso;
- non ho messo lettura della UI dentro
Prestito; - non ho messo
localStoragedentroPrestito; - so spiegare che
RegistraPrestitosarà un caso d’uso più ampio della sola funzioneapriPrestito.
Nella prossima lezione diamo un nome alle regole che devono valere sempre: invarianti.