modulo 11 di 24 / Ore 21-40

Moduli 9-16 / Checkpoint 40 ore

Micro-sfida: sposta una regola fuori dalla UI

Trovare una regola del laboratorio nascosta in un event listener della UI, spostarla nel dominio o nel caso d'uso, e verificare che il comportamento rimanga identico.

30 minArchitettura del software

Micro-sfida: sposta una regola fuori dalla UI

Questa lezione appartiene al Modulo 11 — Presentation: l’interfaccia come bordo del sistema.

La sfida

Trova una condizione if nel tuo event listener che riguarda una regola del laboratorio. Spostala nel dominio o nel caso d’uso. Verifica che il comportamento del Registro sia identico prima e dopo.

Regola del pollice: se la condizione risponde a “il laboratorio permette questa operazione?”, appartiene al dominio — non alla UI.

Esempio concreto — prima e dopo

Prima: regola nella UI

// presentation/ui.js — PROBLEMA: la regola è nell'event listener
document.getElementById("btn-presta").addEventListener("click", () => {
  const strumento = archivioStrumenti.trovaPerId(strumentoId); // ← anche questo è sbagliato

  // Queste condizioni sono regole del laboratorio — non appartengono qui
  if (strumento.stato === "guasto") {
    mostraErrore("Strumento guasto.");
    return;
  }
  if (strumento.stato === "in_prestito") {
    mostraErrore("Già in prestito.");
    return;
  }

  // Salva direttamente — senza passare dal caso d'uso
  strumento.stato = "in_prestito";
  archivioStrumenti.salva(strumento);
  mostraSuccesso("Prestito registrato.");
});

Problemi in questo codice:

  1. Le regole (guasto, in_prestito) sono nel posto sbagliato — duplicabili, testabili solo con il browser
  2. L’event listener accede direttamente all’archivio — viola il confine Infrastructure
  3. Non c’è un caso d’uso — tutta la logica è nell’evento

Dopo: regola nel dominio, UI come bordo

// domain/strumento.js — le regole stanno qui
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/registraPrestito.js — il caso d'uso coordina
function creaRegistraPrestito({ archivioStrumenti, archivioPrestiti }) {
  return async function registraPrestito(comando) {
    const strumento = await archivioStrumenti.trovaPerId(comando.strumentoId);
    if (!strumento) throw new Error("STRUMENTO_NON_TROVATO");

    puoEsserePrestato(strumento); // ← chiama la regola del dominio

    const prestito = apriPrestito(strumento.id, new Date().toISOString());
    await archivioPrestiti.salva({ ...prestito, assegnatario: comando.assegnatario });
    await archivioStrumenti.salva({ ...strumento, stato: "in_prestito" });
  };
}
// presentation/ui.js — bordo pulito: solo input, chiamata, output
document.getElementById("btn-presta").addEventListener("click", async () => {
  const comando = {
    strumentoId: document.getElementById("strumento-id").value,
    assegnatario: document.getElementById("assegnatario").value
  };

  try {
    await registraPrestito(comando); // ← chiama il caso d'uso, non l'archivio
    mostraSuccesso("Prestito registrato.");
  } catch (errore) {
    const messaggi = {
      STRUMENTO_NON_TROVATO: "Strumento non trovato.",
      STRUMENTO_GUASTO_NON_PRESTABILE: "Questo strumento è guasto.",
      STRUMENTO_GIA_IN_PRESTITO: "Questo strumento è già in prestito.",
      STRUMENTO_IN_MANUTENZIONE: "Questo strumento è in manutenzione."
    };
    mostraErrore(messaggi[errore.message] ?? "Operazione non riuscita.");
  }
});

Come trovare la regola da spostare

Cerca nel tuo progetto queste condizioni negli event listener:

✓ strumento.stato === "guasto"         → regola del dominio
✓ strumento.stato === "in_prestito"    → regola del dominio
✓ prestito.chiusoIl !== null           → regola del dominio
✓ lista.length > LIMITE                → potrebbe essere regola del dominio
✗ form.value.trim() === ""             → validazione input, sta bene nell'event listener
✗ elemento.classList.add(...)          → presentazione, sta bene nell'event listener

I quattro passi della sfida

Passo 1: trova la condizione da spostare. Scrivi in una frase cosa fa:

"Se lo strumento è guasto, non permette il prestito."

Passo 2: crea o aggiorna la funzione nel dominio:

// domain/strumento.js — aggiungi o aggiorna
function puoEsserePrestato(strumento) {
  if (strumento.stato !== "disponibile") {
    throw new Error("STRUMENTO_NON_DISPONIBILE");
  }
}

Passo 3: rimuovi la condizione dall’event listener e sostituisci con la chiamata al caso d’uso.

Passo 4: verifica che il comportamento sia identico:

  • premi il pulsante con uno strumento disponibile → deve funzionare
  • premi il pulsante con uno strumento guasto → deve mostrare il messaggio di errore corretto
  • premi il pulsante con uno strumento in prestito → deve mostrare il messaggio di errore corretto

Attività in classe

## Micro-sfida: sposta una regola fuori dalla UI

Regola trovata nell'event listener (scrivi in linguaggio naturale):

File e riga dove stava:

Funzione creata o aggiornata nel dominio:

File dell'event listener modificato:

Verifica eseguita:
  - Caso valido: [comportamento]
  - Caso non valido 1: [comportamento]
  - Caso non valido 2: [comportamento]

Comportamento cambiato rispetto a prima (sì/no):
(Deve essere "no" — il refactoring non cambia il comportamento)

Spiegazione guidata per studiare

Un event listener deve fare tre cose: leggere l’input, chiamare il caso d’uso, mostrare il risultato. Non deve decidere se un’operazione è permessa — quella è la responsabilità del dominio.

Il punto centrale è: se sposti la regola nel dominio e il comportamento del Registro rimane identico, hai fatto un refactoring corretto. La verifica è il momento più importante della sfida — non la modifica stessa.

Il rischio tipico è spostare la regola nel dominio ma lasciare una copia nell’event listener “per sicurezza”. Questo crea duplicazione: domani aggiorni la regola nel dominio ma dimentichi l’event listener, e il comportamento diverge.

Passo per passo nel progetto

  1. Apri tutti i file della presentation/.
  2. Cerca condizioni if che controllano lo stato di strumenti o prestiti.
  3. Per ogni condizione: è una regola del laboratorio o una logica di presentazione?
  4. Sposta una regola nel dominio — una sola, per questa sfida.
  5. Rimuovi la copia dall’event listener — non lasciare duplicati.
  6. Verifica con almeno tre scenari: caso valido, un caso non valido, un secondo caso non valido.

Esempio da leggere lentamente

// Trovato nell'event listener:
if (strumento.stato === "guasto" || strumento.stato === "in_prestito") {
  alert("Strumento non disponibile");
  return;
}

// Spostato nel dominio come:
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");
}

// L'event listener diventa:
try {
  await registraPrestito(comando); // il caso d'uso chiama puoEsserePrestato internamente
} catch (errore) {
  mostraErrore(messaggi[errore.message] ?? "Operazione non riuscita.");
}

Il comportamento è identico. La regola è ora nel posto giusto: testabile, riutilizzabile, non duplicabile.

Prova di comprensione

  • Hai trovato la regola da spostare nel tuo progetto?
  • Dove stava prima? Dove sta adesso?
  • Il comportamento del Registro è cambiato? (Deve essere: no.)
  • Se aggiungi un quarto stato "dismesso" — dove aggiungi il controllo?

Errori da evitare

  • spostare la regola nel dominio e lasciare una copia nell’event listener;
  • spostare la logica di presentazione invece della regola di dominio;
  • non verificare i casi non validi dopo lo spostamento;
  • modificare il comportamento mentre si fa il refactoring (deve restare identico).

Prodotto da consegnare

Può essere:

  • la funzione puoEsserePrestato (o analoga) aggiornata nel dominio;
  • l’event listener modificato che chiama il caso d’uso invece di controllare lo stato;
  • la scheda della sfida compilata con i risultati delle verifiche.

Checklist di chiusura

  • Ho trovato una condizione nell’event listener che è una regola del laboratorio
  • L’ho spostata nel dominio come funzione con nome chiaro
  • Ho rimosso la copia dall’event listener (nessun duplicato)
  • Ho verificato almeno: caso valido, strumento guasto, strumento in prestito
  • Il comportamento del Registro è identico prima e dopo

Domande per la revisione

  • Quante condizioni simili hai trovato nel progetto? Ne hai spostata solo una — quali restano?
  • Se aggiungi uno stato "dismesso", quanti file devi toccare ora? E prima dello spostamento?
  • Hai trovato regole che invece appartengono davvero all’event listener? Quali?

Risultato atteso

Alla fine lo studente deve saper dire:

Ho trovato la regola "[descrizione]" nell'event listener di [file].
L'ho spostata in [domain/strumento.js o altra funzione del dominio].
Ho rimosso il controllo dall'event listener.
Ho verificato con questi scenari: [lista].
Il comportamento è rimasto identico.

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