[Pubblichiamo un estratto dal libro Clean Code di recentissima uscita, nato per aiutare i programmatori a perseguire l’obiettivo di codice sempre più snello ed essenziale, curato come farebbe un artigiano del software.]
Nel suo meraviglioso libro Refactoring, Martin Fowler ha identificato molte avvertenze [NdT: in originale il termine, che rendeva bene il senso, era smells, letteralmente puzze.]. La lista che segue include molte delle avvertenze di Martin e ne aggiunge di nuove. Inoltre includo alcune perle ed euristiche che applico quotidianamente.
Ho compilato questo elenco occupandomi di svariati programmi ed eseguendone il refactoring. Mentre svolgevo ogni modifica, mi sono chiesto perché la stavo apportando e poi ho scritto il motivo. Il risultato è un elenco piuttosto lungo di cose che mi puzzano quando leggo del codice.
Questo elenco [di cui riportiamo alcune voci indicative. NdR] è concepito per essere letto da cima a fondo e per essere usato da riferimento.
Commenti
C4: Commenti mal scritti
Un commento che merita di essere scritto, merita anche di essere scritto bene. Se pensate di scrivere un commento, assicuratevi che sia il miglior commento che possiate scrivere. Scegliete le parole con attenzione. Usate bene la grammatica e la punteggiatura. Non divagate. Non raccontate ovvietà. Siate concisi.
Ambiente
E2: Test che richiedono più di un passo
Dovreste essere in grado di eseguire tutti gli unit test con un solo comando. Meglio ancora, potete lanciare tutti i test facendo clic su un solo pulsante dell’IDE. Al limite dovreste essere in grado di usare un unico, semplice comando in una shell. La capacità di eseguire tutti i test è così importante che dovrebbe essere rapida, facile e banale.
Funzioni
F4: Funzioni “morte”
I metodi che non vengono mai richiamati dovrebbero essere eliminati. Conservare del codice ormai inutile è uno spreco. Non temete di cancellare la funzione. Ricordate: il sistema di controllo del codice sorgente continuerà a ricordarsela.
Generali
G28: Incapsulate i costrutti condizionali
La logica booleana è difficile da comprendere senza entrare nel contesto di un’istruzione if o while. Estraete delle funzioni che spieghino lo scopo del costrutto condizionale.
Per esempio,
if (shouldBeDeleted(timer))
è preferibile a:
if (timer.hasExpired() && !timer.isRecurrent())
Java
J2: Non ereditate le costanti
L’ho visto parecchie volte e ogni volta mi fa sobbalzare. Un programmatore inserisce alcune costanti in un’interfaccia e poi ottiene l’accesso a tali costanti ereditando tale interfaccia. Date un’occhiata al seguente codice:
public class HourlyEmployee extends Employee {
private int tenthsWorked;
private double hourlyRate;
public Money calculatePay() {
int straightTime = Math.min(tenthsWorked, TENTHS_PER_WEEK);
int overTime = tenthsWorked - straightTime;
return new Money(
hourlyRate * (tenthsWorked + OVERTIME_RATE * overTime)
);
}
...
}
Da dove arrivano le costanti TENTHS_PER_WEEK e OVERTIME_RATE? Potrebbero provenire dalla classe Employee; vediamo come è fatta:
public abstract class Employee implements PayrollConstants
{
public abstract boolean isPayday();
public abstract Money calculatePay();
public abstract void deliverPay(Money pay);
}
No, qui non c’è. Ma allora dov’è? Osserviamo attentamente la classe Employee. Essa implementa PayrollConstants.
public interface PayrollConstants {
public static final int TENTHS_PER_WEEK = 400;
public static final double OVERTIME_RATE = 1.5;
}
Questa è una pratica perversa! Le costanti vengono nascoste proprio in cima alla gerarchia di ereditarietà. Ma accidenti! Non usate mai l’ereditarietà come un modo per aggirare le regole di visibilità del linguaggio. Usate piuttosto un’import statica.
import static PayrollConstants.*;
public class HourlyEmployee extends Employee {
private int tenthsWorked;
private double hourlyRate;
public Money calculatePay() {
int straightTime = Math.min(tenthsWorked, TENTHS_PER_WEEK);
int overTime = tenthsWorked - straightTime;
return new Money(
hourlyRate * (tenthsWorked + OVERTIME_RATE * overTime)
);
}
...
}
Nomi
N6: Evitate le codifiche
I nomi non dovrebbero contenere una codifica del tipo o della visibilità. Prefissi come m_ o f sono ormai inutili al giorno d’oggi. Anche le codifiche del progetto e/o del sottosistema, come vis_ (per Visual Imaging System) sono ridondanti e fonte di distrazione. Di nuovo, gli ambienti odierni forniscono tutte queste informazioni, senza deturpare i nomi. Proteggete i vostri nomi dall’inquinamento ungherese.
Test
T2: Usate uno strumento di copertura!
I report degli strumenti di copertura affiancano la vostra strategia di test. Aiutano a trovare con facilità i moduli, le classi e le funzioni che non sono sottoposti a sufficienti test. La maggior parte degli IDE fornisce un’indicazione visuale, contrassegnando in verde le righe “coperte” e in rosso quelle “scoperte”. Questo aiuta a trovare con facilità le istruzioni if o catch il cui contenuto non viene considerato.
Conclusioni
Questo elenco di euristiche e avvertenze non è affatto esaustivo. In effetti, penso che non possa esistere un elenco davvero completo. Ma forse l’obiettivo non dovrebbe essere la completezza, perché quello che fa questo elenco è stabilire un sistema di valori.
In effetti, tale sistema di valori è esattamente l’obiettivo e l’argomento dell’intero libro. Non si scrive codice pulito seguendo un semplice insieme di regole. Non diventerete artigiani sviluppatori imparando un semplice elenco di euristiche. La professionalità e l’abilità derivano dai valori che guidano la disciplina.
Bibliografia
- Martin Fowler et al., Refactoring: Improving the Design of Existing Code, Addison-Wesley, Boston 1999.
- Andrew Hunt, Dave Thomas, The Pragmatic Programmer, Addison-Wesley, Boston 2000. Edizione italiana, Il Pragmatic Programmer, Apogeo, Milano 2018.
- Gamma et al., Design Patterns: Elements of Reusable Object Oriented Software, Addison-Wesley, Boston 1996.
- Kent Beck, Smalltalk Best Practice Patterns, Prentice Hall, Upper Saddle River, New Jersey 1997.
- Kent Beck, Implementation Patterns, Addison-Wesley, Boston 2008.
- Robert C. Martin, Agile Software Development: Principles, Patterns, and Practices, Prentice Hall, Upper Saddle River, New Jersey 2002.
- Eric Evans, Domain Driven Design, Addison-Wesley, Boston 2003.