7 consigli da non perdere sul refactoring
Introduzione
Il debito tecnico è una persecuzione con cui prima o poi, a vari livelli, tutti siamo costretti a confrontarci. Anche a te sarà sicuramente capitato di guardare sconfortato il monitor, fissando codice incomprensibile prodotto chissà quando, sotto chissà quali premesse e condizioni.
Se sei un essere umano, il tuo primo pensiero è stato augurarti di essere altrove.
Il tuo secondo pensiero, invece, sarà stato probabilmente quello di fare un refactoring, cioè una riscrittura totale o parziale del codice per migliorarne la qualità.
Se solo avessi il tempo di farlo. Perché anche tu sarai sotto analoghe condizioni di specifiche poco chiare e poco stabili, all’ombra di una release importante, sotto pressione, sempre alla rincorsa della prossima feature.
Vorresti prenderti qualche giorno per migliorare il codice, ma non puoi. Che fare?
Questi sono alcuni consigli che potrebbero aiutarti in questa situazione comune.
1. Abbassa le tue aspettative
Lo scopo di un refactoring non è avere del bel codice subito, è avere un codice migliore di prima. Spezza un grosso refactoring in tanti piccoli interventi autoconclusivi che sono oggettivamente migliorie e che ti serviranno a sgonfiare il debito tecnico.
Nel tempo vedrai che parti di codice incomprensibili, che avrebbero richiesto giorni di lavoro solo per essere decodificate e corrette, diventeranno sempre meno spaventose.
La mia personale checklist di interventi incrementali comprende:
- rimuovi codice morto, commentato o non usato
- rimuovi commenti inutili, non descrittivi, che appesantiscono la lettura del codice
- migliora il nome di variabili per quella che è la tua comprensione attuale del codice (ricorda che trovare il nome giusto a un oggetto o una variabile è un processo iterativo nel tempo)
- applica un coding standard, usando tool automatici se possibile
- sostituisci numeri magici nel codice con costanti con un nome descrittivo
- elimina i warning segnalati dai tool di analisi o dal compilatore
- spezza funzioni troppo grandi in funzioni più piccole con un nome descrittivo
- più funzioni che operano su una stessa porzione di dati possono diventare una classe, semplicemente spostando il codice
- classi troppo grandi possono diventare più classi con funzioni più specifiche
- rimuovi codice furbo e sostituiscilo con codice chiaro senza side-effect
2. Regola dei due minuti
Un intervento di refactoring dovrebbe essere conclusivo nel giro di pochi minuti. Qualunque intervento che richiede più tempo dovrebbe essere spezzato in interventi più piccoli e autoconclusivi, se possibile (e molto molto spesso lo è).
Due minuti per migliorare il nome di una classe, o per eliminare una parte di codice morto, si trovano sempre.
Il refactoring diventa quindi un processo quotidiano invece di un’attività straordinaria da pianificare e da contrattare con il management.
3. Tenere pulito è più facile che pulire
Cerca, se possibile, di frenare in ingresso il debito tecnico. Nessun refactoring ti può salvare se la velocità con cui il codice degrada è superiore alla velocità di miglioramento, e in ogni caso rischia di diventare un enorme spreco di tempo.
Migliorare il codice è un processo che, quando cominciato, richiede un po’ di disciplina da parte di tutto il team.
Uno strumento molto efficace in tal senso è la pratica di sottoporre il codice a code-review per individuare problemi e code-smell.
4. Pensa al lungo periodo
La lotta contro il debito tecnico non è uno scatto, ma una maratona. Il codice peggiora lentamente nel tempo, giorno dopo giorno, commit dopo commit… e nello stesso modo può migliorare.
Se riesci a bloccare il debito tecnico in ingresso e contemporaneamente a fare qualche decina di interventi migliorativi alla settimana, i risultati saranno visibili molto rapidamente.
Quando, iterativamente, i nomi delle variabili, delle funzioni e delle classe migliorano, sparisce il codice morto, diminuiscono le dimensioni di classi e funzioni, allora diventa progressivamente sempre più facile leggere e capire il codice nel tempo.
Interventi migliorativi che oggi richiederebbero ore di lavoro diventano man mano più facili e meno costosi.
5. Usa tools e IDE evoluti
Per riuscire a chiudere un ciclo di miglioramento nell’arco di pochi minuti è importante avere a disposizione tool che ti aiutino in questo. In particolare:
- tool di formattazione automatica del codice (es. clang-format)
- linter e analisi statiche (es. clang-tidy)
- visualizzazione automatica di codice non usato
- IDE con rinomina intelligente (es. QtCreator, CLion, etc.)
- IDE con estrazione del codice in funzioni e classi (es. Resharper)
6. Interventi architetturali a parte
I refactoring architetturali sono i più complicati e i più difficili da spezzare in refactoring più semplici. Per questo motivo è importante che tutto il lavoro di pulizia sia stato fatto prima di mettere le mani ad elementi architetturali.
Cerca di non mischiare mai interventi di pulizia spicciola del codice (rinominare classi, variabili, estrazione funzioni, rimozione codice e commenti inutili, etc.) con interventi architetturali (comunicazione tra componenti, astrazioni, etc.).
Ricorda inoltre che questi ultimi richiedono che la direzione del refactoring sia stata discussa e approvata da tutto il team. Tutti i membri del team infatti devono essere allineati su cosa deve essere cambiato e verso quale design stiamo andando.
È bene che queste decisioni siano scritte in un documento di supporto affinché non se ne perda traccia nel corso dello sviluppo.
7. Test automatici
Mettiti in condizione di poter scrivere velocemente test automatici e, almeno per tutti i nuovi sviluppi, assicurati di sottoporre a test i vari componenti. Questo aiuterà tantissimo il processo di refactoring e ti aiuterà a controllare lo stress. La parola chiave è sempre progresso incrementale.
Anche scrivendo un unico test al giorno (che richiede pochissimo sforzo) nel tempo ti ritroverai una suite corposa.
Lavora con noi!
Scopri un ambiente interessante e coinvolgente!
Conclusioni
Usando l’approccio divide et impera dovresti riuscire il più delle volte a smontare il debito tecnico un pezzettino alla volta, attraverso una costante serie di piccoli interventi di pochi minuti.
Questo dovrebbe aiutarti a costruire un processo migliorativo, giorno per giorno, che nel corso della vita del progetto diventerà sempre più significativo. Tutto questo dovrebbe essere compiuto, il più possibile, a colpi di iterazioni di pochi minuti che non richiedono autorizzazioni speciali o alterazioni nella pianificazione delle scadenze.
Il refactoring diventa così un processo costante, quotidiano, da affiancare sempre alla normale attività di sviluppo.