Questa guida allo stile di codifica è una versione semplificata di un'altra che è stata usata con buon successo sia nella pratica industriale sia per corsi universitari.
Una guida dello stile di codifica è un insieme di requisiti obbligatori in materia di disposizione e di impostazione del codice. Uno stile uniforme agevola la lettura del codice scritto dai vostri docenti e dai vostri compagni di corso: avrete modo di apprezzarlo soprattutto quando farete un progetto di gruppo. Rende anche più facile cogliere rapidamente l'essenza dei vostri programmi a chi dovrà valutarlo.
Una guida dello stile vi rende più produttivi come programmatori perché riduce le scelte inutili. Se non dovete prendere continuamente decisioni su questioni banali, potete dedicare le vostre energie alla soluzione dei problemi veri.
In queste linee guida, svariati costrutti sintattici sono espressamente banditi. Questo non vuol dire che i programmatori che se ne servono siano malvagi o incompetenti. Significa, però, che questi costrutti non sono essenziali e si possono esprimere altrettanto bene o persino meglio con altri costrutti del linguaggio.
Se avete già esperienza di programmazione, in Java o in un altro linguaggio, forse vi sentirete a disagio nel rinunciare a certe abitudini alle quali siete affezionati. Tuttavia, è un segno di professionalità mettere da parte le preferenze personali nelle questioni di minore importanza e accettare un compromesso a vantaggio del vostro gruppo.
Queste linee guida sono per necessità piuttosto noiose. Fanno inoltre riferimento a funzionalità che potreste non ancora aver studiato. Ecco i punti più salienti:
minuscoli
,
con qualche carattereMaiuscolo
all'interno.Maiuscola
.MAIUSCOLO
, con qualche
CARATTERE_DI_SOTTOLINEATURA
all'interno.main
e i metodi di libreria sovrascritti,
deve avere un commento.continue
né break
.final
devono essere private.Nota per il docente: Naturalmente, molti programmatori e molte organizzazioni hanno convinzioni radicate in merito allo stile di codifica. Se questa guida allo stile è incompatibile con le vostre preferenze personali o con le abitudini locali, ritenetevi liberi di modificarla. A tale scopo, questa guida allo stile di codifica è disponibile in forma elettronica nel sito Internet abbinato a questo libro.
Ogni programma Java è un insieme di uno o più file sorgenti. Il programma eseguibile viene ottenuto compilando questi file. Organizzate il materiale di ciascun file nel modo seguente:
package
, se serveimport
public
Il commento che spiega lo scopo del file deve essere nel formato che viene
riconosciuto dal programma javadoc
. Iniziate con /**
e
usate i marcatori @author
e @version
:
/**
COPYRIGHT (c) 1997 Harry Hacker. All Rights Reserved.
Classes to manipulate widgets.
Solves CS101 homework assignment #3
@author Harry Hacker
@version 1.01 1997-02-15
*/
Ogni classe deve essere preceduta da un commento che ne spiega lo scopo.
Elencate dapprima le caratteristiche pubbliche, secondo l'ordine che segue:
Lasciate una riga vuota dopo ciascun metodo.
Tutte le variabili che non sono final
devono essere private.
(Tuttavia, le variabili istanza di una classe interna private
possono essere pubbliche.) Metodi e variabili final
possono essere
pubblici o privati, secondo il caso.
Tutte le caratteristiche devono essere contrassegnate come public
o private
. Non utilizzate la visibilità predefinita (vale a dire,
la visibilità del package) o l'attributo protected
.
Evitate le variabili statiche (eccetto quelle final
) tutte le
volte che vi è possibile. Nei rari casi in cui vi servissero variabili statiche,
vi è consentita una sola variabile statica per classe.
Ciascun metodo (salvo il metodo main
) inizia con un commento in
formato javadoc
:
/**
Converte date del calendario attuale in date del calendario giuliano.
Nota: questo algoritmo è tratto da Press et al; Numerical Recipes
in C, 2nd ed., Cambridge University Press, 1992.
@param day giorno della data da convertire
@param month mese della data da convertire
@param year anno della data da convertire
@return il numero del giorno del calendario giuliano che inizia
a mezzogiorno della data di calendario indicata.
*/
public static int dat2jul(int day, int year)
{
...
}
I metodi devono svilupparsi al massimo su 30 righe di codice. L'intestazione del metodo, i commenti, le righe vuote e le righe che contengono soltanto parentesi graffe non sono comprese in questo conteggio. Questa regola vi costringe a spezzare elaborazioni complesse in più metodi.
Non definite tutte le variabili all'inizio di un blocco:
{
double xold;
double xnew; // Non fatelo
boolean more;
...
}
Definite ciascuna variabile appena prima che venga usata per la prima volta:
{
...
double xold = Integer.parseInt(input);
boolean more = true;
while (more)
{
double xnew = (xold + a / xold) / 2; // OK
...
}
...
}
Non definite due variabili sulla stessa riga:
int dimes = 0, nickels = 0; // Non fatelo
Usate invece due definizioni separate:
int dimes = 0; // OK
int nickels = 0;
In Java, le costanti devono essere definite con la parola chiave final
.
Se la costante viene utilizzata da più metodi, dichiaratela come static
final
. È buona norma definire private le variabili static final
se nessun'altra classe è interessata a loro.
Non utilizzate numeri magici! Un numero magico è una costante numerica integrata nel codice, senza usare una definizione di costante. Qualsiasi numero, a eccezione di -1, 0, 1 e 2, è considerato magico:
if (p.getX() < 300) // Non fatelo
Utilizzate invece variabili final
:
final double WINDOW_WIDTH = 300;
...
if (p.getX() < WINDOW_WIDTH) // OK
Persino la più ragionevole costante cosmica cambierà un giorno o l'altro. Pensate che vi siano 365 giorni in un anno? I vostri clienti su Marte saranno molto infastiditi dal vostro sciocco pregiudizio.
Create una costante
public static final int DAYS_PER_YEAR = 365;
così potrete produrre agevolmente una versione marziana senza dover stanare nel vostro codice tutti i valori 365, 364, 366, 367 e così via.
Quando dichiarate variabili array, inserite le parentesi quadre [ ]
dopo il nome del tipo, non dopo il nome della variabile:
int[] values; // OK
int values[]; // Brutto retaggio del linguaggio C
if
Evitate la trappola "if ... if ... else
". Il codice
if ( ... )
if ( ... ) ...;
else ...;
non farà quello che il livello di rientro suggerisce e ci possono volere ore
per stanare un errore di questo genere. Usate sempre un paio di parentesi graffe
in più, {...}
, quando avete a che fare con "if ... if ...
else
":
if ( ... )
{
if ( ... ) ...;
} // le graffe {...} sono necessarie
else ...;
if ( ... )
{
if ( ... ) ...;
else ...;
} // le graffe {...} non sono necessarie,
// ma vi tengono lontano dai guai
for
Utilizzate cicli for
soltanto quando una variabile passa da un
valore a un altro con un incremento/decremento costante:
for (int i = 0; i < a.length; i++)
System.out.println(a[i]);
Non ricorrete a cicli for
per creare strani costrutti, come
questo:
for (a = a / 2; count < ITERATIONS;
System.out.println(xnew))
// Non fatelo
Usate invece un ciclo while
. In questo modo, la successione
delle istruzioni è molto più chiara.
a = a / 2;
while (count < ITERATIONS) // OK
{
...
System.out.println(xnew);
}
Vi raccomando di non utilizzare l'enunciato switch
, perché è
facile cadere accidentalmente in un caso non desiderato. Utilizzate invece
if
/else
.
Evitate gli enunciati break
o continue
. Utilizzate
un'altra variabile booleana per controllare il flusso dell'esecuzione.
Non contrassegnate un metodo con una specifica di eccezione troppo generale:
Widget readWidget(Reader in)
throws Exception // Pessimo
Invece, dichiarate specificamente eventuali eccezioni controllate che il vostro metodo potrebbe sollevare:
Widget readWidget(Reader in)
throws IOException, MalformedWidgetException // Ottimo
Non "sopprimete" le eccezioni:
try
{
double price = in.readDouble();
}
catch (Exception e)
{} // Pessimo
I principianti spesso fanno questo errore per "far contento il compilatore".
Al contrario, se il metodo corrente non è adatto per gestire l'eccezione, usate
semplicemente una clausola throws
e lasciate che sia uno dei suoi
chiamanti a gestirla.
Le seguenti regole spiegano quando utilizzare lettere maiuscole e minuscole nei nomi degli identificatori:
minuscole
(eventualmente con
qualche carattereMaiuscolo
all'interno); per esempio,
firstPlayer
.MAIUSCOLE
(eventualmente con qualche CARATTERE_DI_SOTTOLINEATURA
all'interno); per esempio, CLOCK_RADIUS
.Maiuscola
seguita da lettere minuscole (eventualmente con qualche
LetteraMaiuscola
all'interno); per esempio, BankTeller
.I nomi devono essere ragionevolmente lunghi e descrittivi. Utilizzate
firstPlayer
e non fp
. Nn tglt l vcl (non togliete le
vocali!). Le variabili locali di uso comune possono essere brevi (ch
,
i
) se sono soltanto noiosi segnaposto per un carattere in ingresso,
per il contatore di un ciclo e così via. Inoltre, non utilizzate ctr
,
c
, cntr
, cnt
, c2
per le
variabili dei vostri metodi. Tali variabili avranno certamente scopi specifici e
si può dar loro un nome che li ricordi al lettore (per esempio, current
,
next
, previuos
, result
, ...).
Impostate gli arresti di tabulazione a un valore pari a tre spazi. Questo vuol dire che (molto probabilmente) dovrete modificare quelli impostati nel vostro editor!
Utilizzate liberamente righe vuote per separare parti di un metodo che sono logicamente distinte.
Mettete uno spazio vuoto prima e dopo qualsiasi operatore binario:
x1 = (-b - Math.sqrt(b * b - 4 * a * c)) / (2 * a);
// Ottimo
x1=(-b-Math.sqrt(b*b-4*a*c))/(2*a);
// Pessimo
Lasciate uno spazio vuoto dopo (e non prima) ogni virgola e punto e virgola.
Non lasciate uno spazio prima o dopo una parentesi tonda o quadra. Lasciate uno
spazio attorno alla parte (...)
di un enunciato if
,
while
, for
o catch
.
if (x == 0) y = 0;
f(a, b[i]);
Ciascuna riga deve stare su 80 colonne. Se dovete spezzare un enunciato, aggiungete un livello di rientro per la continuazione:
a[n] = .............................................
+ ..........................;
Iniziate la riga rientrata con un operatore (se possibile).
Se la condizione per un enunciato if
o while
deve
essere spezzata, badate di racchiudere il corpo fra parentesi graffe, anche se
consiste di un solo enunciato:
if ( ...............................................
&& ..................................
|| ............................ )
{
...
}
Se non ci fossero le graffe, sarebbe arduo distinguere visivamente la continuazione della condizione dall'enunciato che deve essere eseguito.
Le parentesi graffe di apertura e di chiusura si devono allineare, orizzontalmente oppure verticalmente:
while (i < n) { System.out.println(a[i]); i++; }
while (i < n)
{
System.out.println(a[i]); // OK
i++;
}
Alcuni programmatori non allineano le parentesi graffe in verticale, ma
mettono la {
dopo la parola chiave:
while (i < n) { // Non fatelo
System.out.println(a[i]);
i++;
}
Facendo così si rende più difficile la verifica della corrispondenza delle parentesi graffe.
Alcuni programmatori si compiacciono molto di allineare certe colonne nel loro codice:
firstRecord = other.firstRecord;
lastRecord = other.lastRecord;
cutoff = other.cutoff;
L'aspetto è indubbiamente pulito, ma la disposizione non è stabile in relazione alle modifiche. Una nuova variabile che abbia un nome più lungo del numero di colonne prestabilite impone di spostare tutte le voci:
firstRecord = other.firstRecord;
lastRecord = other.lastRecord;
cutoff = other.cutoff;
marginalFudgeFactor = other.marginalFudgeFactor;
È proprio questo tipo di insidie che vi porta a decidere di usare invece un
nome breve, come mff
, per la nuova variabile.
Non ricorrete alle doppie barre //
per i commenti che si
sviluppano per più di due righe. Troverete scomodo dover spostare le barre
//
ogni volta che modificate il commento.
// commento - non fate in questo modo
// altro commento
// ancora commenti
Usate invece la notazione /* ... */
per i commenti. Quando vi
servite di questa notazione, non "abbellitela" con ulteriori asterischi:
/* commento - non fate in questo modo
* altro commento
* ancora commenti
*/
L'aspetto sarà anche gradevole, ma costituisce un forte disincentivo ad aggiornare il commento. Qualcuno utilizza editor di testi che dispongono automaticamente i commenti, ma, anche se lo fate, non sapere se la prossima persona che farà interventi di manutenzione sul vostro codice dispone di un editor di quel genere.
Invece, disponete i commenti lunghi in questo modo:
/*
commento
altro commento
ancora commenti
*/
oppure così:
/*
commento
altro commento
ancora commenti
*/
Questi commenti sono più facili da tenere aggiornati quando il vostro programma viene modificato. Se dovete scegliere fra commenti eleganti ma non aggiornati e commenti brutti da vedere ma aggiornati, la verità prevale sulla bellezza.