modulo 14 di 24 / Ore 21-40

Moduli 9-16 / Checkpoint 40 ore

Esercizio: refactoring a passi piccoli con commit intermedi

Come eseguire un refactoring a passi piccoli nel Registro con commit intermedi: un passo equivale a una verifica equivale a un commit, con struttura dei messaggi di commit.

25 min Architettura del software

Esercizio: refactoring a passi piccoli con commit intermedi

Questa lezione appartiene al Modulo 14 — Refactoring.

Il lavoro continua il progetto guida, il Registro del laboratorio scolastico. In questa lezione esegui un refactoring reale a passi piccoli, ognuno verificato e committato separatamente prima di procedere al successivo.

Obiettivo della lezione

Eseguire un refactoring strutturato nel Registro applicando la regola: un passo di refactoring = una verifica che il sistema funziona ancora = un commit. Nessun passo grande, nessun commit con troppe modifiche insieme.

Alla fine devi avere: una sequenza di commit nel log git, ognuno con una modifica piccola e verificata, e il sistema funzionante identico a prima del refactoring.

Il principio del refactoring a passi piccoli

Il refactoring non aggiunge funzionalità — cambia la struttura del codice mantenendo il comportamento uguale. Il rischio del refactoring è rompere qualcosa mentre si migliora la struttura.

La strategia dei passi piccoli riduce questo rischio: ogni passo è abbastanza piccolo da poter verificare rapidamente che il comportamento non è cambiato. Se qualcosa si rompe, si torna al commit precedente senza perdere tutto il lavoro.

La struttura dei commit è: refactor: [cosa hai fatto] senza cambiare comportamento.

Un refactoring concreto nel Registro

Il soggetto di questo esercizio è la funzione apriPrestito — spesso la più complessa dei casi d’uso. Una versione con problemi strutturali:

// PRIMA — apriPrestito con problemi
export function apriPrestito({ strumentoId }, as, ap) {
  const s = as.caricaTutti();
  let trovato;
  for (let i = 0; i < s.length; i++) {
    if (s[i].id === strumentoId) { trovato = s[i]; break; }
  }
  if (!trovato) throw new Error("STRUMENTO_NON_TROVATO");
  if (trovato.stato !== "disponibile") throw new Error("STRUMENTO_NON_DISPONIBILE");
  trovato.stato = "in-prestito";
  as.salva(s);
  const ps = ap.caricaTutti();
  const np = { id: crypto.randomUUID(), strumentoId: strumentoId, dataApertura: new Date().toISOString().split("T")[0], dataChiusura: null };
  ps.push(np);
  ap.salva(ps);
  return np;
}

Problemi strutturali: nomi dei parametri non leggibili (as, ap, s, ps), ciclo for invece di find, tutto in una sola funzione senza struttura.

Procedura guidata

  1. Scegli la funzione da refactorizzare nel tuo Registro.
  2. Esegui ogni passo nell’ordine: modifica → verifica → commit.
  3. Non passare al passo successivo senza aver verificato e committato.
  4. Se un passo rompe qualcosa, usa git diff per capire cosa è cambiato e correggilo.
  5. Alla fine, verifica che il comportamento complessivo sia identico a prima.

Attività in classe

Prima di iniziare, pianifica i passi:

## Piano di refactoring

Funzione da refactorizzare: ___
Problema principale: ___

Passo 1: (descrizione)
Verifica: (come controlli che funziona ancora)
Commit message: refactor: ___

Passo 2: ___
Passo 3: ___

Spiegazione guidata per studiare

Un commit di refactoring dovrebbe avere un messaggio che inizia con refactor: e descrive cosa è cambiato nella struttura, non nel comportamento. “refactor: rinomina parametri as e ap in archivioStrumenti e archivioPrestiti” è un buon messaggio. “fix: migliorato il codice” non è utile.

Il test di verifica tra un passo e l’altro non deve essere complesso — basta eseguire il caso d’uso manualmente nel browser o con il file di test. Se il test passa, il passo è sicuro. Se non passa, si torna al commit precedente.

Passo per passo nel progetto

Esegui questi sette passi in ordine sul tuo Registro:

Passo 1 — rinomina i parametri:

// da: export function apriPrestito({ strumentoId }, as, ap)
// a:
export function apriPrestito({ strumentoId }, archivioStrumenti, archivioPrestiti)

Verifica: esegui apriPrestito nel browser — funziona ancora. Commit: git commit -m "refactor: rinomina parametri as/ap in archivioStrumenti/archivioPrestiti"

Passo 2 — rinomina le variabili locali:

// da: const s = archivioStrumenti.caricaTutti()
// a:
const strumenti = archivioStrumenti.caricaTutti();

E ps → prestiti, trovato → strumento, np → nuovoPrestito.

Verifica: esegui apriPrestito — funziona ancora. Commit: git commit -m "refactor: rinomina variabili locali con nomi leggibili"

Passo 3 — sostituisci il ciclo for con Array.find:

// da: ciclo for
// a:
const strumento = strumenti.find(s => s.id === strumentoId);

Verifica: esegui il test dei casi limite — STRUMENTO_NON_TROVATO funziona ancora. Commit: git commit -m "refactor: sostituisce ciclo for con Array.find"

Passo 4 — estrai la creazione del nuovo prestito in una funzione:

function creaNuovoPrestito(strumentoId) {
  return {
    id: crypto.randomUUID(),
    strumentoId,
    dataApertura: new Date().toISOString().split("T")[0],
    dataChiusura: null
  };
}

Verifica: il prestito viene creato correttamente. Commit: git commit -m "refactor: estrae creaNuovoPrestito come funzione separata"

Passo 5 — aggiungi una riga vuota tra le due fasi dell’operazione (commento separatore):

export function apriPrestito({ strumentoId }, archivioStrumenti, archivioPrestiti) {
  // fase 1: aggiorna lo strumento
  const strumenti = archivioStrumenti.caricaTutti();
  const strumento = strumenti.find(s => s.id === strumentoId);
  if (!strumento) throw new Error("STRUMENTO_NON_TROVATO");
  if (strumento.stato !== "disponibile") throw new Error("STRUMENTO_NON_DISPONIBILE");
  strumento.stato = "in-prestito";
  archivioStrumenti.salva(strumenti);

  // fase 2: crea il prestito
  const prestiti = archivioPrestiti.caricaTutti();
  const nuovoPrestito = creaNuovoPrestito(strumentoId);
  prestiti.push(nuovoPrestito);
  archivioPrestiti.salva(prestiti);

  return nuovoPrestito;
}

Verifica: il flusso completo funziona. Commit: git commit -m "refactor: aggiunge commenti di separazione fasi in apriPrestito"

Esempio JS — il risultato finale

// DOPO — apriPrestito leggibile dopo il refactoring
function creaNuovoPrestito(strumentoId) {
  return {
    id: crypto.randomUUID(),
    strumentoId,
    dataApertura: new Date().toISOString().split("T")[0],
    dataChiusura: null
  };
}

export function apriPrestito({ strumentoId }, archivioStrumenti, archivioPrestiti) {
  // fase 1: verifica disponibilità e aggiorna strumento
  const strumenti = archivioStrumenti.caricaTutti();
  const strumento = strumenti.find(s => s.id === strumentoId);
  if (!strumento) throw new Error("STRUMENTO_NON_TROVATO");
  if (strumento.stato !== "disponibile") throw new Error("STRUMENTO_NON_DISPONIBILE");
  strumento.stato = "in-prestito";
  archivioStrumenti.salva(strumenti);

  // fase 2: registra il prestito
  const prestiti = archivioPrestiti.caricaTutti();
  const nuovoPrestito = creaNuovoPrestito(strumentoId);
  prestiti.push(nuovoPrestito);
  archivioPrestiti.salva(prestiti);

  return nuovoPrestito;
}

Il comportamento è identico. Il codice è molto più leggibile. Cinque commit separati, ognuno verificato.

Prova di comprensione

Rispondi per iscritto:

  • Qual è la differenza tra un commit di refactoring e un commit di bugfix?
  • Perché non fare tutto il refactoring in un unico commit grande?
  • Cosa succede se il passo 3 (sostituzione del ciclo for) introduce un bug? Come lo identifichi?
  • Hai eseguito i test dopo ogni passo? Cosa avresti perso se li avessi saltati?

Errori da evitare

  • fare refactoring e aggiungere funzionalità nello stesso commit;
  • fare passi troppo grandi — se un passo cambia più di 10 righe, è troppo grande;
  • non verificare dopo ogni passo — la verifica è parte del processo, non un optional;
  • scrivere messaggi di commit vaghi come “migliorato il codice”.

Prodotto da consegnare

La sequenza di commit nel log git (git log --oneline) che mostra i passi del refactoring. Come verifica: esegui git log --oneline e mostra i commit con i messaggi refactor: al docente.

Checklist di chiusura

  • ogni passo di refactoring ha un commit separato;
  • ogni commit ha un messaggio che inizia con refactor:;
  • ho verificato il comportamento dopo ogni passo;
  • il sistema funziona identicamente a prima del refactoring;
  • i test dei casi limite passano ancora tutti.

Risultato atteso

Ho eseguito 5 passi di refactoring su apriPrestito.
Ogni passo ha un commit separato con messaggio refactor:.
Il comportamento è identico a prima — i test passano.
Il codice è più leggibile: nomi chiari, Array.find, funzione estratta.
git log --oneline mostra 5 commit di refactoring in sequenza.