modulo 12 di 24 / Ore 21-40

Moduli 9-16 / Checkpoint 40 ore

Errore di dominio: regola violata

Riconoscere e gestire gli errori di dominio nel Registro: violazioni delle regole del laboratorio che devono essere rilevate e lanciate dal dominio stesso.

25 min Architettura del software

Errore di dominio: regola violata

Questa lezione appartiene al Modulo 12 — Errori, validazione e messaggi.

Cos’è un errore di dominio

Un errore di dominio nasce quando viene violata una regola del laboratorio — una regola che esiste indipendentemente da come il sistema è costruito, da dove i dati vengono salvati o da come l’utente interagisce.

Nel Registro del laboratorio, le regole del dominio sono:

  • uno strumento guasto non può essere prestato
  • uno strumento già in prestito non può essere prestato di nuovo
  • un prestito chiuso non si può chiudere una seconda volta
  • uno strumento in manutenzione non può essere prestato

Queste regole esistono perché descrivono la realtà del laboratorio — non perché il programmatore le ha inventate.

Dove deve stare il controllo

Le regole del dominio vanno verificate nel dominio, non nella UI e non nel caso d’uso.

// domain/strumento.js — la regola sta qui, non altrove
function verificaDisponibilita(strumento) {
  if (strumento.stato !== "disponibile") {
    throw new Error("STRUMENTO_NON_DISPONIBILE");
  }
}

// domain/prestito.js
function verificaPrestito(prestito) {
  if (prestito.chiusoIl !== null) {
    throw new Error("PRESTITO_GIA_CHIUSO");
  }
}

Se il controllo stesse nella UI, potrebbe essere aggirato aprendo un’altra pagina. Se stesse solo nel caso d’uso, non sarebbe riutilizzabile. Nel dominio, è disponibile a chiunque nel sistema.

Errori di dominio nel Registro

Codice erroreRegola violataDove viene lanciato
STRUMENTO_NON_DISPONIBILEStrumento non è in stato disponibiledomain/strumento.js
PRESTITO_GIA_CHIUSOPrestito ha già una data di chiusuradomain/prestito.js
STATO_NON_VALIDOStato non è tra i valori ammessidomain/strumento.js

Differenza rispetto agli altri errori

Errore di input      →  "il nome è vuoto"         — rilevato in Presentation / Application
Errore di dominio    →  "strumento guasto"         — rilevato in Domain
Errore applicativo   →  "strumento non trovato"    — rilevato in Application
Errore infrastrutturale → "salvataggio fallito"    — rilevato in Infrastructure

Un errore di dominio non dipende dall’archivio (un dominio che funziona in memoria ha le stesse regole di uno con localStorage). Non dipende dall’input dell’utente — i dati sono già stati validati prima.

Come viene lanciato e catturato

// Domain — lancia l'errore con codice chiaro
function puoEsserePrestato(strumento) {
  if (strumento.stato === "guasto") throw new Error("STRUMENTO_GUASTO_NON_PRESTABILE");
  if (strumento.stato === "in_prestito") throw new Error("STRUMENTO_GIA_IN_PRESTITO");
  if (strumento.stato === "in_manutenzione") throw new Error("STRUMENTO_IN_MANUTENZIONE");
}

// Application — chiama la funzione di dominio
async function registraPrestito(comando) {
  const strumento = await archivioStrumenti.trovaPerId(comando.strumentoId);
  if (!strumento) throw new Error("STRUMENTO_NON_TROVATO"); // ← errore applicativo

  puoEsserePrestato(strumento); // ← può lanciare errore di dominio
  // ...
}

// Presentation — cattura e traduce
try {
  await registraPrestito(comando);
} catch (errore) {
  const messaggi = {
    STRUMENTO_GUASTO_NON_PRESTABILE: "Questo strumento è guasto. Non può essere prestato.",
    STRUMENTO_GIA_IN_PRESTITO: "Questo strumento è già in prestito.",
    STRUMENTO_IN_MANUTENZIONE: "Questo strumento è in manutenzione.",
    STRUMENTO_NON_TROVATO: "Strumento non trovato."
  };
  mostraMessaggio(messaggi[errore.message] ?? "Operazione non riuscita.");
}

Perché i codici errore, non le stringhe libere

I codici errore (STRUMENTO_GUASTO_NON_PRESTABILE) sono costanti confrontabili. Una stringa libera (“Strumento guasto, impossibile prestare”) può cambiare forma senza che il test si accorga — il test confronta la stringa e smette di funzionare.

Con i codici, il test confronta solo il codice:

test("non apre un prestito per uno strumento guasto", () => {
  const strumento = { id: "s1", stato: "guasto" };
  expect(() => puoEsserePrestato(strumento)).toThrow("STRUMENTO_GUASTO_NON_PRESTABILE");
});

Il messaggio per l’utente viene costruito altrove — nella Presentation — e può cambiare senza toccare il test.

Procedura guidata

  1. Apri domain/strumento.js e domain/prestito.js nel tuo progetto.
  2. Per ogni regola del laboratorio, verifica che ci sia una funzione che la controlla e lancia un errore con codice chiaro.
  3. Verifica che quelle funzioni vengano chiamate nei casi d’uso, non nella UI.
  4. Scrivi un test per almeno una regola: il dominio lancia l’errore corretto quando la regola è violata?
  5. Verifica che la UI traduca il codice in un messaggio comprensibile.

Attività in classe

## Errore di dominio nel mio Registro

Regola del dominio analizzata:

Funzione che la verifica:

Codice errore lanciato:

Dove viene catturato:

Messaggio utente corrispondente:

Test scritto:

Spiegazione guidata per studiare

Gli errori di dominio nascono nel dominio perché le regole del laboratorio appartengono al dominio. Non dipendono dall’interfaccia, dall’archivio o dalla tecnologia scelta.

Il punto centrale è: il dominio lancia, la Presentation traduce. Il dominio usa codici brevi e univoci (STRUMENTO_GUASTO_NON_PRESTABILE). La UI usa frasi comprensibili per l’utente. I due livelli non si mescolano.

Il rischio tipico è mettere il controllo della regola direttamente nell’event listener della UI: if (strumento.stato === "guasto") { mostraMessaggio("Guasto"); }. In questo modo la regola esiste solo nella UI — se domani si aggiunge una seconda pagina, la regola va replicata. E se una delle due repliche è sbagliata, il comportamento è inconsistente.

Passo per passo nel progetto

  1. Elenca le regole del laboratorio che il tuo Registro deve rispettare.
  2. Per ogni regola, la verifica sta nel dominio? O è dispersa in altri livelli?
  3. Ogni controllo lancia un errore con codice chiaro?
  4. La UI ha una tabella o funzione che traduce i codici in messaggi?
  5. Almeno una regola ha un test nel dominio?

Esempio da leggere lentamente

// domain/strumento.js — tutte le regole di prestabilità in un posto
function puoEsserePrestato(strumento) {
  if (strumento.stato === "guasto") {
    throw new Error("STRUMENTO_GUASTO_NON_PRESTABILE");
  }
  if (strumento.stato === "in_prestito") {
    throw new Error("STRUMENTO_GIA_IN_PRESTITO");
  }
  if (strumento.stato === "in_manutenzione") {
    throw new Error("STRUMENTO_IN_MANUTENZIONE");
  }
  // Se arriva qui, lo strumento è disponibile
}

Nota: la funzione non restituisce true/false — lancia un errore con il motivo preciso. Questo rende i test più chiari e il codice chiamante più semplice (non deve controllare il valore di ritorno).

Prova di comprensione

  • Elenca tre regole del dominio del tuo Registro. Per ognuna: dove sta il controllo?
  • Perché è sbagliato mettere il controllo della regola direttamente nella UI?
  • Cosa succede se lo stesso controllo è scritto in due posti e uno dei due è sbagliato?

Errori da evitare

  • verificare le regole del dominio direttamente negli event listener della UI;
  • usare messaggi utente come codici errore nel dominio (throw new Error("Strumento guasto"));
  • avere la stessa regola verificata in più punti del codice;
  • far dipendere la verifica della regola dall’archivio (il dominio non deve conoscere localStorage).

Prodotto da consegnare

Può essere:

  • una funzione puoEsserePrestato completa con tutti i controlli nel dominio;
  • un test per ogni regola di dominio verificata;
  • una tabella codici-errore → messaggi-utente nella Presentation.

Checklist di chiusura

  • Ogni regola del laboratorio ha una funzione nel dominio che la verifica
  • I codici errore sono costanti chiare e univoche
  • Il dominio non conosce messaggi per l’utente
  • La UI traduce i codici in messaggi comprensibili
  • Almeno una regola ha un test automatico

Domande per la revisione

  • Hai trovato regole del dominio messe nella UI o nel caso d’uso? Dove?
  • Il tuo dominio potrebbe funzionare con un archivio diverso senza toccare le regole?
  • Un test che rompi deliberatamente una regola — il codice errore corretto viene lanciato?

Risultato atteso

Alla fine lo studente deve saper dire:

Nel mio Registro, la regola "[X]" è verificata in [file/funzione].
Lancia l'errore [Y] quando viene violata.
La UI mostra il messaggio: "[Z]".
Ho un test che verifica questo comportamento.

Se questa spiegazione non è possibile, la lezione non è ancora davvero conclusa.