modulo 08 di 24 / Ore 0-20

Moduli 1-8 / Checkpoint 20 ore

Collegare la UI ai casi d'uso

Collegare la pagina del Registro del laboratorio ai casi d'uso senza riportare regole e salvataggio dentro la UI.

30 min Architettura del software

Collegare la UI ai casi d’uso

Ora colleghiamo la UI ai casi d’uso.

Questo passaggio e delicato: dopo aver separato i file, e facile riportare tutto dentro la pagina per far funzionare rapidamente qualcosa.

Non vogliamo una UI isolata.

Vogliamo una UI collegata bene.

Obiettivo

Alla fine devi avere una UI che:

  • legge input dai form;
  • costruisce comandi;
  • chiama casi d’uso;
  • mostra risultati;
  • mostra errori comprensibili;
  • non contiene regole di dominio;
  • non salva direttamente i dati.

Punto di composizione

Nel file di avvio possiamo comporre il sistema:

import { creaArchivioStrumentiInMemoria } from "./infrastructure/archivioStrumentiInMemoria.js";
import { creaArchivioPrestitiInMemoria } from "./infrastructure/archivioPrestitiInMemoria.js";
import { creaRegistraStrumento } from "./application/registraStrumento.js";
import { creaRegistraPrestito } from "./application/registraPrestito.js";
import { avviaUIRegistro } from "./presentation/uiRegistro.js";

const archivioStrumenti = creaArchivioStrumentiInMemoria();
const archivioPrestiti = creaArchivioPrestitiInMemoria();

const registraStrumento = creaRegistraStrumento({
  archivioStrumenti,
});

const registraPrestito = creaRegistraPrestito({
  archivioStrumenti,
  archivioPrestiti,
});

avviaUIRegistro({
  registraStrumento,
  registraPrestito,
});

Questo file non contiene regole.

Collega pezzi.

UI come funzione di avvio

Nel file:

src/presentation/uiRegistro.js

possiamo scrivere:

export function avviaUIRegistro({ registraStrumento, registraPrestito }) {
  const formStrumento = document.querySelector("#form-strumento");
  const formPrestito = document.querySelector("#form-prestito");
  const messaggio = document.querySelector("#messaggio");

  formStrumento.addEventListener("submit", (event) => {
    event.preventDefault();

    try {
      registraStrumento(leggiComandoStrumento());
      messaggio.textContent = "Strumento registrato.";
    } catch (errore) {
      messaggio.textContent = messaggioPerErrore(errore);
    }
  });

  formPrestito.addEventListener("submit", (event) => {
    event.preventDefault();

    try {
      registraPrestito(leggiComandoPrestito());
      messaggio.textContent = "Prestito registrato.";
    } catch (errore) {
      messaggio.textContent = messaggioPerErrore(errore);
    }
  });
}

La UI riceve casi d’uso gia pronti.

Non li costruisce da zero.

Costruire comandi

La UI puo avere funzioni come:

function leggiComandoStrumento() {
  return {
    id: document.querySelector("#strumento-id").value,
    nome: document.querySelector("#strumento-nome").value,
    categoria: document.querySelector("#strumento-categoria").value,
    stato: document.querySelector("#strumento-stato").value,
  };
}

Questo codice sta bene nella presentation.

Legge dalla pagina e costruisce un oggetto semplice.

Mostrare risultati

Dopo un caso d’uso, la UI puo aggiornare la schermata:

function renderizzaStrumenti(strumenti) {
  listaStrumenti.innerHTML = "";

  for (const strumento of strumenti) {
    const riga = document.createElement("li");
    riga.textContent = `${strumento.nome} - ${strumento.stato}`;
    listaStrumenti.append(riga);
  }
}

Questo e compito della UI.

Il dominio non deve sapere come viene renderizzata una lista.

Mostrare errori

File:

src/presentation/messaggiErrore.js

Esempio:

const messaggi = {
  NOME_STRUMENTO_OBBLIGATORIO: "Inserisci il nome dello strumento.",
  STRUMENTO_NON_TROVATO: "Strumento non trovato.",
  STRUMENTO_NON_PRESTABILE: "Questo strumento non puo essere prestato.",
  PRESTITO_GIA_CHIUSO: "Questo prestito e gia chiuso.",
};

export function messaggioPerErrore(errore) {
  return messaggi[errore.message] ?? "Operazione non riuscita.";
}

La UI mostra il messaggio.

Il dominio produce codici errore.

Controllo: cosa non deve ricomparire nella UI

Cerca nella UI:

if (strumento.stato === "guasto")
localStorage.setItem(...)
prestiti.push(...)
strumento.stato = "in_prestito"

Se trovi questi pezzi, chiediti se devono stare:

  • nel dominio;
  • nel caso d’uso;
  • nell’archivio.

La UI puo chiamare, non deve ricostruire tutto.

Esercizio

Collega almeno due casi d’uso alla UI:

  • RegistraStrumento;
  • RegistraPrestito.

Per ciascuno compila:

## Collegamento UI

Caso d'uso:

Form o evento:

Comando costruito:

Messaggio di successo:

Errori gestiti:

Codice che non deve stare nella UI:

Cosa produrre

Alla fine della lezione devi avere:

  • main.js o punto di avvio che compone archivi, casi d’uso e UI;
  • uiRegistro.js o file equivalente;
  • almeno due form collegati ai casi d’uso;
  • funzione per trasformare errori in messaggi;
  • nessuna regola di dominio duplicata nella UI.

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 collegare la UI ai casi d’uso, il punto centrale è questo: Un caso d’uso coordina un’operazione completa: riceve un comando, legge ciò che serve, applica regole, salva il risultato e restituisce un esito.

Il rischio tipico è far diventare il caso d’uso una seconda UI o un secondo database. Deve coordinare, non mostrare HTML e non conoscere dettagli tecnici di salvataggio. 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

  1. 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?”.
  2. Apri solo i file necessari. Se devi toccare più di tre file, fermati e scrivi prima una mini-mappa.
  3. Definisci input e output del caso d’uso.
  4. Leggi i dati attraverso un archivio o una dipendenza esplicita.
  5. Chiama le regole del dominio.
  6. Salva il risultato senza sapere come funziona la persistenza concreta.
  7. 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 registraPrestito(comando, archivioStrumenti, archivioPrestiti) {
  const strumento = archivioStrumenti.trovaPerId(comando.strumentoId);
  verificaStrumentoPrestabile(strumento);
  const prestito = apriPrestito(strumento.id, comando.nomePersona);
  archivioPrestiti.salva(prestito);
  archivioStrumenti.salva({ ...strumento, stato: "in_prestito" });
  return 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:

  • la UI chiama i casi d’uso;
  • la UI costruisce comandi;
  • i casi d’uso sono creati fuori dagli event listener;
  • la UI mostra errori comprensibili;
  • la UI non salva direttamente i dati;
  • la UI non contiene le regole principali.

Nella prossima lezione scriviamo i primi test sulle regole.