modulo 11 di 24 / Ore 21-40

Moduli 9-16 / Checkpoint 40 ore

Mostrare risultati senza duplicare regole

Costruire la vista dei risultati nella Presentation usando l'esito del caso d'uso, senza replicare condizioni o regole del dominio nella funzione di rendering.

30 min Architettura del software

Mostrare risultati senza duplicare regole

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

Il problema della duplicazione

Quando la UI mostra i risultati di un’operazione, c’è la tentazione di aggiungere condizioni per decidere cosa mostrare. Alcune di queste condizioni sono logica di presentazione — appartengono alla UI. Altre sono regole del dominio — appartengono al dominio e non devono essere replicate.

La duplicazione crea due problemi:

  1. Inconsistenza: se la regola cambia nel dominio ma non nella UI, il comportamento diverge
  2. Manutenzione: la stessa logica va aggiornata in due punti ogni volta che cambia

Cosa appartiene alla UI e cosa no

Appartiene alla UI (logica di presentazione)

// Tradurre uno stato tecnico in un'etichetta leggibile
function etichettaStato(stato) {
  const etichette = {
    "disponibile": "Disponibile",
    "in_prestito": "In prestito",
    "guasto": "Guasto",
    "in_manutenzione": "In manutenzione"
  };
  return etichette[stato] ?? stato;
}

// Scegliere una classe CSS in base allo stato
function classeDaStato(stato) {
  return `strumento--${stato}`;
}

// Mostrare un messaggio di successo o errore
function mostraEsitoOperazione(successo, messaggioErrore) {
  if (successo) mostraSuccesso("Operazione completata.");
  else mostraErrore(messaggioErrore);
}

Non appartiene alla UI (regole del dominio)

// ❌ Queste condizioni sono regole del dominio — non metterle nel rendering
function renderListaStrumenti(strumenti) {
  strumenti.forEach(s => {
    const li = document.createElement("li");

    // SBAGLIATO — queste sono regole del laboratorio, non presentazione
    if (s.stato === "guasto" || s.stato === "in_prestito") {
      li.classList.add("non-prestabile");
      li.setAttribute("data-prestabile", "false");
    }

    contenitore.appendChild(li);
  });
}

Come mostrare l’esito senza duplicare — tre pattern

Pattern 1: mostrare l’esito del caso d’uso

Il caso d’uso restituisce un risultato. La UI lo mostra senza reinterpretarlo.

// Application — il caso d'uso decide l'esito
async function registraPrestito(comando) {
  const strumento = await archivioStrumenti.trovaPerId(comando.strumentoId);
  if (!strumento) throw new Error("STRUMENTO_NON_TROVATO");
  puoEsserePrestato(strumento); // lancia se non disponibile
  const prestito = apriPrestito(strumento.id, new Date().toISOString());
  await archivioPrestiti.salva({ ...prestito, assegnatario: comando.assegnatario });
  await archivioStrumenti.salva({ ...strumento, stato: "in_prestito" });
  return { prestitoId: prestito.id }; // ← esito minimo
}

// Presentation — mostra l'esito senza reinterpretare
try {
  const esito = await registraPrestito(comando);
  mostraSuccesso(`Prestito registrato. ID: ${esito.prestitoId}`);
} catch (errore) {
  mostraErrore(messaggi[errore.message] ?? "Operazione non riuscita.");
}

Pattern 2: rendering da stato, non da regola

La UI mostra lo stato degli oggetti ricevuti — non applica regole su di essi.

// ✅ Il rendering riflette lo stato — non applica regole
function renderStrumento(strumento) {
  return `
    <li class="strumento strumento--${strumento.stato}">
      <span>${strumento.nome}</span>
      <span class="badge">${etichettaStato(strumento.stato)}</span>
    </li>
  `;
  // La classe CSS dice lo stato, non se è prestabile.
  // Chi può prestare e chi no — lo decide il dominio quando si tenta l'operazione.
}

Pattern 3: stato vuoto e stato di caricamento

Mostrare stati speciali dell’interfaccia — non errori di dominio.

function renderListaStrumenti(contenitore, strumenti, statoCaricamento) {
  if (statoCaricamento === "caricamento") {
    contenitore.innerHTML = "<p>Caricamento in corso...</p>";
    return;
  }

  if (strumenti.length === 0) {
    contenitore.innerHTML = "<p>Nessuno strumento trovato.</p>";
    return;
  }

  contenitore.innerHTML = strumenti.map(renderStrumento).join("");
}

Questi stati (caricamento, vuoto) sono stati della UI — non regole del laboratorio.

Esempio: prima e dopo

Prima — regola duplicata nella UI

// ❌ La UI decide chi può prestare — regola del dominio nella Presentation
function renderListaStrumenti(strumenti) {
  return strumenti.map(s => {
    const prestabile = s.stato === "disponibile"; // ← regola del dominio!
    return `
      <li>
        ${s.nome}
        ${prestabile
          ? `<button data-id="${s.id}">Presta</button>`
          : `<span>Non disponibile</span>`}
      </li>
    `;
  }).join("");
}

Dopo — la UI usa lo stato, il dominio decide la regola

// ✅ La UI mostra lo stato — il dominio decide al momento dell'operazione
function renderListaStrumenti(strumenti) {
  return strumenti.map(s => `
    <li class="strumento--${s.stato}">
      ${s.nome}
      <span class="badge">${etichettaStato(s.stato)}</span>
      <button data-id="${s.id}" data-azione="presta">Presta</button>
    </li>
  `).join("");
  // Il pulsante c'è sempre.
  // Se si tenta di prestare uno strumento non disponibile,
  // il caso d'uso lancia l'errore e la UI mostra il messaggio.
}

Il pulsante è sempre visibile. Se l’utente preme “Presta” su uno strumento guasto, il caso d’uso lancia STRUMENTO_GUASTO_NON_PRESTABILE e la UI mostra il messaggio. La regola sta nel dominio — non nella UI.

Procedura guidata

  1. Apri le funzioni di rendering della tua UI (renderListaStrumenti, renderStrumento, ecc.).
  2. Cerca condizioni if che controllano stato, chiusoIl, o altri campi del dominio.
  3. Per ogni condizione: è logica di presentazione o è una regola del laboratorio?
  4. Sposta le regole del laboratorio fuori dal rendering.
  5. Verifica che il comportamento rimanga identico.

Attività in classe

## Mostrare risultati senza duplicare regole

Funzione di rendering analizzata:

Condizioni trovate nel rendering:

Per ogni condizione: logica di presentazione o regola del dominio?

Condizioni spostate fuori dal rendering:

Verifica del comportamento dopo la modifica:

Spiegazione guidata per studiare

La funzione di rendering ha un solo compito: trasformare dati in HTML. Non deve decidere se un’operazione è permessa — deve mostrare i dati che riceve.

Il punto centrale è: il rendering è puro — riceve dati e restituisce HTML, senza effetti collaterali e senza regole di dominio. Se una funzione di rendering ha un if (stato === "guasto") che decide cosa mostrare sulla base di una regola del laboratorio, quella condizione appartiene altrove.

Il rischio tipico è ottimizzare l’esperienza utente nascondendo pulsanti “non applicabili” direttamente nel rendering. Funziona, ma duplica la regola. La soluzione alternativa è mostrare sempre il pulsante e lasciare che il dominio risponda con un errore comprensibile.

Passo per passo nel progetto

  1. Apri tutte le funzioni di rendering.
  2. Elenca ogni if o operatore ternario che appare nel rendering.
  3. Classifica: logica di presentazione (CSS, etichette, layout) o regola del dominio (chi può fare cosa)?
  4. Sposta le regole del dominio — non duplicarle.
  5. Verifica con scenari: strumento disponibile, guasto, in prestito — il rendering mostra lo stato corretto?

Esempio da leggere lentamente

// Rendering pulito — solo presentazione
function renderStrumento(strumento) {
  const etichette = {
    "disponibile": "Disponibile",
    "in_prestito": "In prestito",
    "guasto": "Guasto",
    "in_manutenzione": "In manutenzione"
  };

  return `
    <li class="strumento strumento--${strumento.stato}">
      <strong>${strumento.nome}</strong>
      <span>${strumento.categoria}</span>
      <span class="badge badge--${strumento.stato}">
        ${etichette[strumento.stato] ?? strumento.stato}
      </span>
      <button data-id="${strumento.id}">Presta</button>
    </li>
  `;
  // Nessuna regola del dominio.
  // La classe CSS comunica lo stato all'utente tramite colore.
  // Il tentativo di prestare uno strumento non disponibile viene
  // gestito dal caso d'uso al momento del click.
}

Prova di comprensione

  • Hai trovato nel tuo rendering condizioni che duplicano regole del dominio?
  • Qual è la differenza tra “mostrare lo stato” e “applicare una regola”?
  • Se la regola di prestabilità cambia (es. si aggiunge lo stato "dismesso"), quanti file devi toccare nel tuo progetto attuale?

Errori da evitare

  • nascondere pulsanti nel rendering in base a regole del dominio — duplica la regola;
  • non mostrare mai stati intermedi (caricamento, lista vuota) — l’interfaccia sembra rotta;
  • mescolare la traduzione delle etichette con la logica di business nello stesso blocco;
  • rimuovere il rendering di uno stato senza verificare tutti gli scenari.

Prodotto da consegnare

Può essere:

  • funzione renderStrumento che usa solo logica di presentazione, senza regole del dominio;
  • tre scenari testati manualmente: strumento disponibile, guasto, in prestito — screenshot o descrizione del comportamento;
  • nota tecnica che spiega la differenza tra logica di presentazione e regola del dominio nel contesto del Registro.

Checklist di chiusura

  • Le funzioni di rendering non contengono condizioni sulle regole del laboratorio
  • Lo stato di ogni strumento viene mostrato con etichetta e classe CSS
  • Lo stato vuoto (nessun risultato) è gestito con un messaggio
  • Il pulsante di azione è sempre visibile — gli errori vengono gestiti dal caso d’uso
  • Ho verificato il comportamento con strumenti in stati diversi

Domande per la revisione

  • Hai trovato condizioni nel rendering che erano regole del dominio?
  • Dopo le modifiche, quanti file bisogna aggiornare se cambia una regola di prestabilità?
  • Il rendering funziona correttamente con una lista vuota? E con 100 strumenti?

Risultato atteso

Alla fine lo studente deve saper dire:

La mia funzione renderStrumento mostra [nome, categoria, stato, badge].
Non contiene condizioni sulle regole del laboratorio.
Ho verificato il rendering con strumenti in stati: disponibile, guasto, in prestito.
Se si tenta di prestare uno strumento non disponibile, il messaggio viene gestito da [caso d'uso].

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