modulo 19 di 24 / Ore 41-60

Moduli 17-24 / Checkpoint 60 ore

Esercizio: piccola analisi dei colli di bottiglia

Analisi sistematica dei colli di bottiglia nel Registro: come misurare con console.time, quali operazioni analizzare, come interpretare i risultati.

25 min Architettura del software

Esercizio: piccola analisi dei colli di bottiglia

Questa lezione appartiene al Modulo 19 — Performance e ottimizzazione pratica.

Il lavoro continua il progetto guida, il Registro del laboratorio scolastico. In questa lezione esegui una piccola analisi sistematica delle operazioni più costose del Registro usando console.time.

Obiettivo della lezione

Identificare le tre operazioni più lente del Registro attraverso misurazioni reali, documentare i risultati e decidere se e cosa ottimizzare — con motivazione basata sui numeri, non sulle sensazioni.

Alla fine devi avere: una tabella di misurazioni con almeno sei operazioni misurate e una decisione documentata su cosa ottimizzare (o perché non ottimizzare nulla).

Cosa misurare nel Registro

Le operazioni da analizzare nel Registro sono:

  • caricaTutti per gli strumenti (lettura da localStorage + parse JSON)
  • caricaTutti per i prestiti (stessa operazione, dimensioni diverse)
  • salva per gli strumenti (serializzazione + scrittura localStorage)
  • cercaStrumenti con filtro (lettura + filtraggio array)
  • apriPrestito (lettura strumenti + lettura prestiti + scrittura strumenti + scrittura prestiti)
  • registraStrumento (lettura + aggiunta + scrittura)

Come si usa console.time

console.time("nome-operazione");
// operazione da misurare
console.timeEnd("nome-operazione");
// stampa: "nome-operazione: X.XXms"

Il nome deve essere identico in time e timeEnd. Puoi usare più timer contemporaneamente con nomi diversi.

Nel Registro del laboratorio

Per misurare in modo significativo, devi avere dati reali in localStorage. Con 5 strumenti e 2 prestiti, i tempi sono troppo bassi per essere significativi. Carica almeno 100 strumenti e 50 prestiti prima di misurare.

Procedura guidata

  1. Carica dati di volume in localStorage (script nella sezione successiva).
  2. Aggiungi misurazioni con console.time alle sei operazioni elencate.
  3. Apri il Registro nel browser e esegui ogni operazione.
  4. Leggi i tempi nella console di DevTools.
  5. Documenta i risultati.
  6. Identifica l’operazione più lenta e spiega perché.
  7. Decidi se ottimizzare — con motivazione basata sui numeri.

Attività in classe

Compila questa tabella durante le misurazioni:

## Risultati misurazioni

Operazione             | Tempo (ms) | Note
caricaTutti strumenti  |            |
caricaTutti prestiti   |            |
salva strumenti        |            |
cercaStrumenti (filtro)|            |
apriPrestito           |            |
registraStrumento      |            |

Operazione più lenta: ___
Motivo: ___
Ottimizzazione necessaria? sì / no — perché: ___

Spiegazione guidata per studiare

Un collo di bottiglia è un’operazione che rallenta il sistema in modo percepibile dall’utente. Per il Registro scolastico, “percepibile” significa più di 100ms — sotto quella soglia, l’utente non nota la differenza.

La maggior parte dei colli di bottiglia nel Registro non dipende da localStorage in sé (che è veloce per quantità piccole) ma da operazioni ripetute inutilmente: caricaTutti chiamato tre volte invece di una, o salva chiamato dopo ogni singola modifica invece di raccogliere le modifiche.

Misurare prima di ottimizzare è la regola fondamentale. Un’ottimizzazione che riduce da 0.2ms a 0.1ms non ha impatto percepibile. Un’ottimizzazione che riduce da 5 chiamate a caricaTutti a 1 ha impatto reale.

Passo per passo nel progetto

  1. Carica 100 strumenti in localStorage per avere dati significativi:
// incolla in console del browser
const strumentiVolume = Array.from({ length: 100 }, (_, i) => ({
  id: `str-${String(i).padStart(3, "0")}`,
  name: `Strumento ${i}`,
  category: i % 3 === 0 ? "misura" : i % 3 === 1 ? "saldatura" : "perforazione",
  status: i % 5 === 0 ? "in-prestito" : i % 7 === 0 ? "guasto" : "disponibile"
}));
localStorage.setItem("registro_strumenti", JSON.stringify(strumentiVolume));
console.log("100 strumenti caricati");
  1. Aggiungi misurazioni temporanee ai casi d’uso. Esempio per cercaStrumenti:
// application/cercaStrumenti.js — con misurazione
export function cercaStrumenti({ filtro }, archivio) {
  console.time("cercaStrumenti-caricaTutti");
  const tutti = archivio.caricaTutti();
  console.timeEnd("cercaStrumenti-caricaTutti");

  if (!filtro || filtro.trim() === "") return tutti;

  console.time("cercaStrumenti-filtraggio");
  const filtroLower = filtro.toLowerCase();
  const risultato = tutti.filter(s =>
    s.nome.toLowerCase().includes(filtroLower) ||
    s.categoria.toLowerCase().includes(filtroLower)
  );
  console.timeEnd("cercaStrumenti-filtraggio");

  return risultato;
}
  1. Aggiungi misurazione a apriPrestito per vedere il costo totale dell’operazione:
// application/apriPrestito.js — con misurazione totale
export function apriPrestito({ strumentoId }, archivioStrumenti, archivioPrestiti) {
  console.time("apriPrestito-totale");

  console.time("apriPrestito-caricaStrumenti");
  const strumenti = archivioStrumenti.caricaTutti();
  console.timeEnd("apriPrestito-caricaStrumenti");

  const strumento = strumenti.find(s => s.id === strumentoId);
  if (!strumento) { console.timeEnd("apriPrestito-totale"); throw new Error("STRUMENTO_NON_TROVATO"); }
  if (strumento.stato !== "disponibile") { console.timeEnd("apriPrestito-totale"); throw new Error("STRUMENTO_NON_DISPONIBILE"); }

  strumento.stato = "in-prestito";

  console.time("apriPrestito-salvaStrumenti");
  archivioStrumenti.salva(strumenti);
  console.timeEnd("apriPrestito-salvaStrumenti");

  const prestiti = archivioPrestiti.caricaTutti();
  const nuovoPrestito = { id: crypto.randomUUID(), strumentoId, dataApertura: new Date().toISOString().split("T")[0], dataChiusura: null };
  prestiti.push(nuovoPrestito);
  archivioPrestiti.salva(prestiti);

  console.timeEnd("apriPrestito-totale");
  return nuovoPrestito;
}
  1. Apri la console del browser, esegui le operazioni e leggi i tempi.
  2. Cerca pattern di inefficienza. Esempio di output da analizzare:
cercaStrumenti-caricaTutti: 0.4ms
cercaStrumenti-filtraggio: 0.1ms
apriPrestito-caricaStrumenti: 0.4ms
apriPrestito-salvaStrumenti: 0.6ms
apriPrestito-totale: 1.8ms

Con 100 strumenti, 1.8ms totali è accettabile. Non c’è nulla da ottimizzare.

  1. Rimuovi tutte le misurazioni temporanee prima della presentazione finale.

Esempio JS — interpretare i risultati

// Se vedi questo output:
// caricaTutti: 0.3ms   → normale per 100 record
// salva: 0.5ms         → normale, include JSON.stringify
// apriPrestito-totale: 4.2ms → insolito — verifica se caricaTutti è chiamato più volte

// Se vedi questo:
// caricaTutti: 0.3ms (prima chiamata)
// caricaTutti: 0.3ms (seconda chiamata nello stesso caso d'uso)
// → due letture inutili — elimina la seconda

Prova di comprensione

Rispondi per iscritto:

  • Qual è l’operazione più lenta nel tuo Registro? Il tempo è percepibile dall’utente?
  • Hai trovato chiamate ridondanti a caricaTutti nella stessa operazione?
  • Con 100 strumenti, i tempi sono problematici? Con 10.000 lo sarebbero?
  • Hai deciso di ottimizzare qualcosa? Se sì, quale criterio hai usato per scegliere?

Errori da evitare

  • ottimizzare senza misurare — “sembra lento” non è una misura;
  • misurare con 5 record invece di 100+ — i tempi non sono significativi;
  • lasciare le misurazioni console.time nel codice di produzione;
  • ottimizzare operazioni che durano meno di 1ms e non impattano sull’utente.

Prodotto da consegnare

La tabella delle misurazioni compilata con sei operazioni e una decisione documentata su cosa ottimizzare (o perché non ottimizzare nulla). Come verifica: mostra la tabella al docente e spiega il ragionamento dietro la decisione.

Checklist di chiusura

  • ho caricato almeno 100 strumenti in localStorage prima di misurare;
  • ho misurato almeno sei operazioni con console.time;
  • la tabella è compilata con i tempi reali;
  • la decisione su cosa ottimizzare è motivata dai numeri;
  • le misurazioni temporanee sono state rimosse dal codice.

Risultato atteso

Ho misurato 6 operazioni con 100 strumenti in localStorage.
Operazione più lenta: apriPrestito — 1.8ms.
Chiamate ridondanti trovate: sì / no — [descrizione].
Decisione: [ottimizzare / non ottimizzare] — perché: [motivazione con numeri].
Le misurazioni temporanee sono state rimosse.