modulo 20 di 24 / Ore 41-60
Moduli 17-24 / Checkpoint 60 ore
Log tecnici e messaggi per l'utente
Come separare i log tecnici (console.error con dettaglio) dai messaggi per l'utente (UI leggibile) nel Registro — con un wrapper logger minimale e esempi di uso corretto.
Log tecnici e messaggi per l’utente
Questa lezione appartiene al Modulo 20 — Logging e osservabilità minima.
Obiettivo della lezione
Separare in modo netto i log tecnici (destinati allo sviluppatore che analizza la console) dai messaggi per l’utente (destinati al docente o al tecnico che usa il Registro). Alla fine i due canali sono distinti nel codice e nella UI.
Perché serve nel percorso
Quando un’operazione fallisce nel Registro, accadono due cose distinte: lo sviluppatore deve capire cosa è successo (log tecnico), e l’utente deve sapere cosa fare (messaggio UI). Se questi due canali si mescolano, succede uno di questi problemi:
- l’utente vede
Cannot read properties of undefined— incomprensibile; - lo sviluppatore vede solo “Si è verificato un errore” — inutile per il debug.
Nel Registro del laboratorio
Il logger tecnico va nella console, contiene dettagli tecnici, non viene mai mostrato all’utente:
// src/infrastructure/logger.js
export const logger = {
info(evento, contesto = {}) {
console.info(`[INFO] ${evento}`, contesto);
},
warn(evento, contesto = {}) {
console.warn(`[WARN] ${evento}`, contesto);
},
error(evento, errore, contesto = {}) {
// Logga il messaggio tecnico completo, incluso lo stack
console.error(`[ERROR] ${evento}`, { messaggio: errore?.message, ...contesto });
}
};
Il messaggio per l’utente va nella UI, è scritto in italiano comprensibile, non contiene stack trace o codici interni:
// src/presentation/messaggi.js
export function mostraMessaggio(elemento, testo, tipo = "info") {
elemento.textContent = testo;
elemento.className = `messaggio messaggio--${tipo}`;
}
export function traduciErrore(codice) {
const messaggi = {
STRUMENTO_NON_TROVATO: "Lo strumento cercato non esiste più nel registro.",
STRUMENTO_GUASTO_NON_PRESTABILE: "Questo strumento è guasto e non può essere prestato.",
PRESTITO_GIA_CHIUSO: "Questo prestito è già stato chiuso.",
NOME_STRUMENTO_NON_VALIDO: "Il nome inserito non è valido (minimo 2 caratteri)."
};
return messaggi[codice] ?? "Si è verificato un errore. Riprova o contatta il tecnico.";
}
Come si usano insieme:
// src/application/registraPrestito.js
import { logger } from "../infrastructure/logger.js";
export function registraPrestito({ strumentoId, studenteId }, archivioStrumenti, archivioPrestitif) {
const strumento = archivioStrumenti.trovaPerId(strumentoId);
if (!strumento) {
logger.warn("prestito_strumento_non_trovato", { strumentoId }); // canale tecnico
throw new Error("STRUMENTO_NON_TROVATO"); // codice per la UI
}
// ...
}
// src/presentation/azioniPrestito.js
import { traduciErrore, mostraMessaggio } from "./messaggi.js";
try {
registraPrestito({ strumentoId, studenteId }, archivioStrumenti, archivioPrestiti);
mostraMessaggio(elementoUI, "Prestito registrato.", "successo");
} catch (err) {
logger.error("ui_registra_prestito_fallita", err, { strumentoId }); // canale tecnico
mostraMessaggio(elementoUI, traduciErrore(err.message), "errore"); // canale utente
}
Procedura guidata
- Crea
src/infrastructure/logger.jscon le funzioniinfo,warn,error. - Crea
src/presentation/messaggi.jsconmostraMessaggioetraduciErrore. - Cerca tutti i posti nel codice dove un errore viene gestito.
- Per ogni gestione errori: aggiungi il log tecnico nel canale
loggere il messaggio italiano nel canale UI. - Verifica che nessun
err.messagetecnico arrivi direttamente atextContentoinnerHTML.
Attività in classe
Questo codice confonde i due canali — trova i problemi:
document.getElementById("btn-chiudi").addEventListener("click", () => {
try {
chiudiPrestito({ prestitoId }, archivioPrestiti);
alert("Successo");
} catch (err) {
// Problema 1: mostra err.message in UI
document.getElementById("errore").textContent = err.message;
// Problema 2: nessun log tecnico
}
});
Riscrivi il codice separando i due canali, poi compila la scheda:
## Separazione log/messaggi
File modificati:
Log tecnici aggiunti (evento, contesto):
Messaggi utente aggiunti (testo italiano):
Verifica: err.message appare in UI? sì/no
Spiegazione guidata per studiare
I due canali hanno pubblici diversi e quindi formati diversi:
| Aspetto | Log tecnico | Messaggio utente |
|---|---|---|
| Destinatario | Sviluppatore | Docente/tecnico |
| Dove appare | Console del browser | UI della pagina |
| Contenuto | Codice errore, ID, stack | Frase in italiano |
| Obiettivo | Debug | Azione da intraprendere |
Il logger non deve essere complesso. Per il Registro scolastico, la versione mostrata sopra è sufficiente. Non serve un sistema di log esterno, non serve scrivere su file, non serve un database di log.
La funzione traduciErrore è un dizionario: prende un codice stringa ("STRUMENTO_NON_TROVATO") e restituisce una frase italiana. Il codice viene dall’errore lanciato dal caso d’uso o dall’infrastruttura, e la traduzione avviene solo nella UI — mai nel dominio.
Pattern completo:
Domain/Application → lancia Error("CODICE_ERRORE")
↓
Infrastructure/Logger → logga il dettaglio tecnico
↓
Presentation → cattura l'errore, logga nella console, mostra il messaggio tradotto in UI
Passo per passo nel progetto
- Crea
src/infrastructure/logger.jsconinfo,warn,error. - Crea
src/presentation/messaggi.jsconmostraMessaggioetraduciErrore. - Aggiungi al dizionario di
traduciErroretutti i codici errore che il Registro può lanciare. - Apri ogni file in
src/presentation/e sostituisci le gestioni errori con il pattern:logger.error+mostraMessaggio(traduciErrore(...)). - Verifica nella console e nella UI che i due canali funzionino separatamente.
Prova di comprensione
- Perché
err.messagenon dovrebbe apparire mai direttamente nell’UI? - Chi dovrebbe chiamare
traduciErrore— il caso d’uso o la UI? - Cosa succede se aggiungi un nuovo tipo di errore ma dimentichi di aggiungerlo al dizionario?
- Come si verifica che il log tecnico contiene informazioni sufficienti per il debug?
Errori da evitare
- mostrare
err.messageoerr.stacknella UI — incomprensibili per l’utente; - mettere messaggi in italiano nei casi d’uso — il dominio non deve sapere come parla la UI;
- dimenticare il log tecnico — senza di esso, quando qualcosa va storto non hai informazioni per il debug;
- usare
alert()per i messaggi — non è separabile, non è accessibile, non è testabile.
Prodotto da consegnare
I file src/infrastructure/logger.js e src/presentation/messaggi.js funzionanti, con tutti i casi d’errore del Registro coperti dal dizionario di traduciErrore. Nessun err.message diretto in UI.
Checklist di chiusura
logger.jsesiste insrc/infrastructure/coninfo,warn,errormessaggi.jsesiste insrc/presentation/conmostraMessaggioetraduciErrore- tutti i codici errore del Registro sono nel dizionario
- nessun handler della UI mostra
err.messagedirettamente - ogni gestione errori usa entrambi i canali:
logger.erroremostraMessaggio
Risultato atteso
Ho creato logger.js in src/infrastructure/ e messaggi.js in src/presentation/.
Il dizionario di traduciErrore copre tutti i codici errore del Registro.
Ogni handler della UI usa logger.error per il canale tecnico e mostraMessaggio per la UI.
Nella console vedo eventi con ID e dettagli tecnici.
Nella UI vedo frasi in italiano leggibili senza dettagli tecnici.