Blog
Architecture
8 novembre 20259 min

Refactoring React Native: da 800 righe a 100 righe

C'è un momento in cui apri un file e senti fisicamente il peso del debito tecnico. La mia schermata principale era di 800 righe. Un singolo file. Logica di business, rendering UI, gestione dello stato, chiamate API — tutto mescolato in un componente monolitico impossibile da mantenere. E non era un caso isolato: avevo 16 schermate nello stesso stato.

Quello che ti racconterò qui è come ho trasformato una codebase caotica in un'architettura pulita. Non con una rivoluzione spettacolare, ma con un refactoring metodico, schermata per schermata, errore per errore.

Punti chiave da ricordare:
- Un hook custom per ogni schermata separa la logica di business dal rendering UI
- Il pattern "orchestratore + sottocomponenti" riduce i file da 800 a 100 righe
- ESLint con regole severe (zero any, promesse awaited) elimina bug silenziosi
- Il debito tecnico è un costo reale misurabile in tempo, bug e motivazione
- Refactoring schermata per schermata permette di rilasciare continuamente senza rompere l'esistente

Perché un componente di 800 righe è un problema?

La risposta ovvia: è illeggibile. Ma il vero problema è più insidioso. Un componente monolitico:

  • Nasconde i bug: quando tutto è nello stesso file, gli effetti collaterali sono imprevedibili. Modificare la logica del filtro può rompere l'animazione di transizione senza che tu capisca perché.
  • Rallenta lo sviluppo: ogni modifica richiede di comprendere l'intero file. Passi 20 minuti a "leggere" prima di poter scrivere 5 righe.
  • Rende il debug impossibile: quando si verifica un bug, hai 800 righe di sospetti. Nessun confine chiaro tra le responsabilità.
  • Deteriora la motivazione: aprire un file mostruoso ogni mattina, pesa. È il tipo di attrito invisibile che rallenta un progetto indie.

"Sei solo, chi leggerà questo codice?" Io. Io tra tre mesi quando avrò dimenticato perché questa schermata fa quello che fa. Il debito tecnico non è una metafora. È un costo reale che si paga in tempo, in bug e in motivazione.

Spazio di lavoro sviluppatore organizzato con due schermi che mostrano codice ben strutturato
Un codice ben strutturato è come una scrivania ordinata: tutto si trova più velocemente.

Quale strategia di suddivisione adottare?

Ho rifattorizzato le 16 schermate seguendo una struttura coerente. Il pattern è semplice ma potente:

1. Un hook custom per la logica di business

Ogni schermata ha il suo hook: useTaskDetail, useFeedScreen, useGroupScreen... L'hook incapsula tutta la logica: caricamento dei dati, gestione dello stato, callback. Il componente si limita a renderizzare JSX.

Prima:

// TaskDetailScreen.tsx - 800 righe
const TaskDetailScreen = () => {
  const [task, setTask] = useState(null);
  const [loading, setLoading] = useState(true);
  const [editing, setEditing] = useState(false);
  // ... 50 altri useState
  // ... 200 righe di useEffect
  // ... 300 righe di handlers
  // ... 250 righe di JSX
}

Dopo:

// TaskDetailScreen.tsx - 100 righe
const TaskDetailScreen = () => {
  const { task, loading, editing, handlers } = useTaskDetail();
  return (
    <TaskDetailHeader task={task} onEdit={handlers.edit} />
    <TaskDetailBody task={task} />
    <TaskDetailActions handlers={handlers} />
  );
}

L'hook useTaskDetail è di 200 righe. I sottocomponenti sono di 50-100 righe ciascuno. In totale, ci sono più righe di prima — ma ogni file è comprensibile isolatamente.

2. Sottocomponenti per il rendering

Ogni sezione visiva della schermata diventa un componente dedicato: TaskDetailHeader, TaskDetailBody, TaskDetailActions. Ognuno riceve le sue props e conosce solo la sua responsabilità.

Questo pattern è direttamente ispirato al Thinking in React ufficiale. Non è nuovo, ma è incredibile quanto lo si dimentichi quando si ha fretta di rilasciare.

3. Un componente principale per l'orchestrazione

Il componente principale diventa un direttore d'orchestra di 100 righe: chiama l'hook, distribuisce le props ai sottocomponenti e gestisce il layout globale. Nient'altro.

Lavagna con diagrammi di architettura software che mostrano la separazione dei componenti
Il pattern hook + sottocomponenti + orchestratore: semplice ed efficace.

Come passare da 71 a 0 errori ESLint?

Parallelamente al refactoring delle schermate, ho lanciato ESLint sul backend con regole severe. Risultato: 71 errori.

La tentazione: disattivare le regole che generano più errori. Questo è ciò che fa il 90% degli sviluppatori. Io ho fatto l'opposto: ho corretto ogni errore individualmente.

Le correzioni più impattanti

Eliminazione degli any: ogni any in TypeScript è una bomba a orologeria. Compila, supera i test, ma si blocca in produzione quando arriva un valore inatteso. Ho sostituito ogni any con un tipo esplicito. Alcuni casi hanno richiesto la creazione di interfacce dedicate, ma il risultato è un codice auto-documentato.

Promesse correttamente awaited: chiamate asincrone senza await che fallivano silenziosamente. Nessun errore, nessun avviso — solo un comportamento errato in produzione. ESLint ha rilevato 12 casi di promesse non awaited. 12 potenziali bug eliminati in un'ora.

Variabili inutilizzate: import dimenticati, variabili dichiarate e poi mai usate. Non bug, ma rumore che rende il codice più difficile da leggere. Ogni riga inutile è una distrazione per il "te del futuro" che cerca di capire il codice.

Bisogna rifattorizzare tutto in una volta o progressivamente?

Progressivamente. Sempre progressivamente. Un "big bang refactoring" in cui riscrivi tutto in una settimana è la ricetta per il disastro per uno sviluppatore solo. Rompi tutto, non puoi più rilasciare, e se un bug critico si verifica in produzione, non puoi correggerlo rapidamente.

Il mio metodo:

  1. Scegliere la schermata più dolorosa (quella che temi di aprire)
  2. Estrarre l'hook custom per primo (la logica, non il rendering)
  3. Testare che tutto funzioni ancora esattamente come prima
  4. Estrarre i sottocomponenti uno per uno
  5. Rilasciare la schermata rifattorizzata, passare alla successiva

Ogni schermata rifattorizzata richiedeva tra 2 ore e mezza giornata. Le più complesse (il Feed, la schermata di gruppo) hanno richiesto una giornata intera. Ma ad ogni fase, l'app rimaneva funzionale e rilasciabile.

Questo flusso di lavoro è simile a quello che Martin Fowler descrive nel suo libro sul refactoring: trasformazioni piccole, incrementali e sempre reversibili.

Quali sono i guadagni concreti dopo il refactoring?

Dopo due settimane di lavoro:

  • 16 schermate rifattorizzate: ognuna segue lo stesso pattern (hook + sottocomponenti + orchestratore)
  • 0 errori ESLint sul backend (contro 71 prima)
  • Tempo di comprensione diviso per 3: aprire una schermata e capire cosa fa richiede 2 minuti invece di 10
  • Bug ridotti: le 3 settimane successive sono state le più stabili del progetto
  • Motivazione ritrovata: aprire un file pulito al mattino, cambia tutto

Il guadagno meno misurabile ma più importante: la fiducia. Dopo il refactoring, non avevo più paura di modificare una schermata. Sapevo esattamente dove si trovava ogni cosa, quali erano le dipendenze e cosa avrebbe impattato un cambiamento.

Scaffale di libri di programmazione ben organizzato con quaderni ordinati, concetto di ordine e chiarezza
Il refactoring è passare dal caos alla chiarezza. Richiede tempo, ma ne vale la pena.

Come il debito tecnico influisce su un progetto solo?

Il debito tecnico in un progetto solo ha effetti specifici che non si trovano in un team:

Nessuna rete di sicurezza. In un team, un collega può rivedere il tuo codice, rilevare una regressione o correggere un bug quando sei assente. Da solo, se il tuo codice è incomprensibile, sei tu — e solo tu — a pagarne il prezzo.

L'effetto composto. Ogni scorciatoia che prendi oggi si moltiplica. Un any qui, un // TODO: fix later là, e in pochi mesi, hai una codebase in cui ogni modifica richiede 3 volte più tempo di quanto dovrebbe.

La spirale di demotivazione. Codice sporco → bug → frustrazione → patch rapide → codice ancora più sporco. Ho visto questa spirale in altri progetti. Il refactoring l'ha interrotta bruscamente.

È la stessa logica che applico alla ristrutturazione del database e all'audit di sicurezza: investire tempo ora per guadagnarne esponenzialmente di più in seguito.

Quali regole ESLint consigliare per un progetto React Native?

Ecco le regole che hanno avuto il maggiore impatto sulla qualità del codice TAMSIV:

  • @typescript-eslint/no-explicit-any: proibisce gli any. Non negoziabile.
  • @typescript-eslint/no-floating-promises: rileva le promesse non awaited. Critico per evitare bug silenziosi.
  • @typescript-eslint/no-unused-vars: elimina il rumore del codice morto.
  • react-hooks/exhaustive-deps: verifica le dipendenze degli hook. Essenziale in React Native.
  • no-console: impone l'uso di un logger invece di console.log in produzione.

Attivale tutte in modalità "error", non "warn". Un warning si ignora. Un errore si corregge.

Cosa ho imparato da questa settimana di refactoring

Questa settimana è stata la migliore del progetto. Non la più entusiasmante — nessuna feature visibile per l'utente. Ma la più impattante per il futuro. Ogni feature che ho costruito dopo — il sistema di gamification, i gruppi gerarchici, l'agenda collaborativa — ha beneficiato di questa architettura pulita.

Se sei uno sviluppatore solo e rimandi un refactoring perché "non rilascia nulla di visibile", smetti. È l'investimento più redditizio che tu possa fare. Non glamour, non eccitante, ma fondamentalmente necessario.

La migliore settimana del progetto. E lo ripeto senza esitazione.

FAQ

Quanto tempo richiede un refactoring di 16 schermate?

Per me, circa due settimane a tempo pieno. Ogni schermata richiede tra 2 ore e una giornata a seconda della sua complessità. La schermata più semplice (un modulo base): 2 ore. La più complessa (il Feed con gamification): una giornata intera.

Il refactoring introduce nuovi bug?

Questo è il rischio principale. Per minimizzarlo, ho rifattorizzato una schermata alla volta e testato manualmente ogni flusso prima di passare al successivo. Nessuna regressione maggiore è apparsa durante le due settimane di refactoring.

Bisogna scrivere test prima di rifattorizzare?

Idealmente, sì. In realtà, su un progetto solo con 16 schermate da rifattorizzare, scrivere test esaustivi prima del refactoring raddoppierebbe il tempo. Ho optato per test manuali rigorosi e test automatizzati dopo il refactoring, sull'architettura pulita.

Il pattern hook + sottocomponenti funziona per tutte le schermate?

Sì, con variazioni. Alcune schermate semplici non hanno bisogno di sottocomponenti — l'hook da solo è sufficiente. Altre schermate complesse hanno più livelli di sottocomponenti. Il principio rimane lo stesso: separare logica e rendering.

ESLint rallenta lo sviluppo quotidiano?

Le prime ore, sì — il tempo di correggere gli errori esistenti. Poi, è il contrario: ESLint accelera lo sviluppo rilevando gli errori prima ancora di avviare l'app. È come un copilota che corregge la tua traiettoria in tempo reale.