Micro-refactor per orientarsi in una codebase difficile
Questa guida è pensata per sviluppatori che si trovano davanti a una codebase che sembra completamente da buttare e non sanno da che parte cominciare.
Introduzione
Quando una codebase sembra irrecuperabile, la tentazione è quella di riscriverla da zero. Prima di arrivare a quel punto, però, conviene fare dei piccoli refactor per orientarsi nei refactor reali.
❌ Non fate l'errore di iniziare un refactor architetturale in un codice che non riuscite ancora a leggere.
Questi micro-refactor potrebbero anche essere definiti come un semplice "riordinare". In questo post vedremo il metodo che Kent Beck usa nel suo libro Tidy First?, che non tratteremo nella sua interezza e che quindi consigliamo assolutamente!
Guard Clauses
Cercate di fare delle guardie al posto di inscatolare il codice in mille condizioni annidate, restando comunque sotto alle 8 guardie.
⚠️ Se si iniziano a mettere troppe guardie il codice è comunque difficile da digerire: sarebbe quindi meglio scomporre quella funzione in più parti.
Dead Code
Rimuovete sempre il codice che non è più necessario. Non serve neanche tenerlo commentato: tanto è versionato, o al massimo verrà riscritto meglio in base a delle evoluzioni future.
Il codice non raggiungibile rende solo più criptico il codice e, a volte, a causa della reflection non è così ovvio da individuare!
Normalize Symmetries
Scegliete il modo più semplice per ottenere un risultato e convertite tutti gli algoritmi in modo che utilizzino quella maniera precisa per il raggiungimento del risultato.
Più standard ci auto imponiamo, più il codice sarà leggibile senza doverci ragionare su.
Reading Order & Cohesion Order
Stando attenti alle limitazioni del linguaggio (alcune volte non può essere chiamata una funzione se è definita più sotto, ecc.), è molto utile organizzare i file in modo da fornire le informazioni in ordine: dobbiamo immaginare di doverli spiegare a una persona estranea e rendere la ricerca facile.
È importante anche mettere tutto quello che è accoppiato (se non è immediato e banale disaccoppiarlo) il più vicino possibile alle altre componenti: che siano funzioni dentro lo stesso file, che siano file nella stessa cartella e così via!
Non esiste uno standard scolpito su pietra, ma esiste il buon senso.
Move Declaration and Initialization Together
Le variabili vanno inizializzate il prima possibile una volta dichiarate. Una buona norma è spesso quella di metterle sempre in cima, ma può essere sensato anche metterle in fasi intermedie.
L'importante è metterle dove servono, subito prima che vengano usate e non in punti casuali.
Explaining Variables & Constants
Se la funzione è troppo elaborata e con espressioni lunghe, è un'ottima occasione per usare delle variabili parlanti, per semplificare la lettura e allo stesso tempo aiutare gli altri dev.
Lo stesso discorso può essere fatto con i magic numbers: se hanno un significato preciso interno alla logica, creare una costante rende più facili i refactor e ne chiarisce il significato.
Chunk Statements
Se la funzione o il file sono molto grossi, naturalmente sarebbe meno confusionario dividerli in sezioni.
È la fix più semplice di tutte, ma può dare enormi soddisfazioni per orientarsi, soprattutto nei widget di Flutter!
Explicit Parameters
Se possibile è sempre meglio fare funzioni pure, ovvero che modificano l'esterno solo tramite il loro output. Inoltre è sempre meglio fare in modo che i dati in input siano specificati esplicitamente nei parametri.
Esempio da non fare: usare le variabili d'ambiente richiamandole dentro il corpo, al posto di chiederle come parametri.
Extract Helper
Create dei metodi, mixin o file helper per la risoluzione di problemi comuni.
In conclusione: prima di rifattorizzare bisogna capire, e per capire bisogna riordinare. I micro-refactor costano poco, non cambiano il comportamento del codice e vi restituiscono la mappa di cui avete bisogno per affrontare i cambiamenti veri.
