Coding Guidelines

Quando non si lavora più da soli per tutti gli sviluppatori arriva il momento di trovare delle linee guida nella scrittura del codice. Protocolli e standard che permettano di “leggere” facilmente ed intervenire (sempre facilmente) nel codice altrui.
Quando su un progetto ci lavorano più programmatori, spesso su linguaggi diversi, è obbligatorio trovare una forma comune di scrittura, di standard nella documentazione interna ed esterna al codice. Nel mio lavoro mi trovo normalmente ad interagire con:

  • Objetive-C, C/C++
  • PHP
  • HTML
  • Javascript
  • Actionscript
  • CSS


Quindi ho dovuto cercare uno standard che soddisfava le esigenze di diversi linguaggi, di diversi contesti e problematiche. Ogni ambiente di sviluppo ha le sue particolarità, ma a noi serviva trovare un modo unico per impostare un progetto, sia esso totalemente Web (PHP, Javascript) che applicativo (Objective-C, C/C++).
Fortunatamente i linguaggi di sviluppo sopra elencati non sono fortemente disomogenei, ma condividono molti tratti in comune. Questo mi ha permesso di delineare alcune procedure che, fino ad oggi, si sono rilevate “abbastanza” comode ed efficenti; usandole nel tempo qualsiasi miglioramento e aggiustamento è sempre ben accolto.

Linee Guida

La prima direttiva che bisogna darsi quando si lavora in gruppo è quella di scrivere il codice in modo chiaro, lasciando da parte “ottimizzazioni” o “compressioni” del caso. Questo avrà due vantaggi immediati: il codice sarà semplice da leggere anche per chi non l’ha scritto, e sarà semplice ri-leggerlo anche per l’autore, soprattutto a distanza di mesi.

Nomi delle Classi

I nomi delle classi iniziano sempre con la lettera maiuscola:

1
2
3
// Objective-C
@interface SMCustomClass <NSObject>
@end
1
2
3
// PHP
class SMCustomClass {
}
1
2
3
4
5
// Javascript
function SMCustomClass () {
}
// ....
var SMCustomClass = {};
1
2
3
// Actionscript
class SMCustomClass extends MovieClip {
}

Nomi delle funzioni/metodi

Metodi e funzioni iniziano in lower-case, ma sono poi in maiuscolo quando inizia una nuova parola. Utilizzare una nomenclatura chiara, che descriva la funzione nella sua interezza, non curandosi dell’eventuale lunghezza. Evitare quindi situazioni come:

1
2
3
4
function gbc() {} // NO
function get_bg_color() {} // NO
function getBackgroundColor() {} // Buono
function backgroundColorFromTopMostWindow() {} // Ottimo
1
2
// Objective-C
- (UIColor *)backgroundColorFromTopMostWindow;
1
2
// PHP
function backgroundColorFromTopMostWindow();
1
2
// Javascript
function backgroundColorFromTopMostWindow();
1
2
3
4
// Actionscript
function backgroundColorFromTopMostWindow():Number {
// ...
}

La regola è quindi di essere chiari, usare il camelize, evitare i get quando non sono strettamente necessari. Meglio, infatti, indicare cosa la funzione o metodo ritorna:

1
2
3
4
5
6
7
8
9
10
11
function getDetailUser() {} // No
function userDetail() // Si

function getObjectFromIndex( index ) {
// coding
}

// meglio sarebbe
function objectFromIndex( index ) {
// coding
}

Nomi delle variabili, costanti, MACRO e define

Come per le funzioni e metodi, i nomi di variabili iniziano in lower-case, proseguendo poi in maiuscolo quando inizia una nuova parola:

1
2
3
4
// PHP
var $streetAddress = "1 Infinite Loop";
var $cityName = "Cupertino";
var $countyName = "Santa Clara";
1
2
3
4
// Javascript
var streetAddress = "1 Infinite Loop";
var cityName = "Cupertino";
var countyName = "Santa Clara";
1
2
<!-- HTML -->
<span class="descriptionBelowThePayOff"></span>
1
2
3
4
5
6
7
8
// css
div#boxForHome {
    display: block;
    border: 1px solid #c00;
}
span.descriptionBelowThePayOff {
    color: #f00;
}

Come aiuto maggiore si può identificare subito il tipo di variabile, sfruttando l’auto completamento del codice ormai diffusissimo in tutte le IDE:

1
2
3
4
5
6
NSString *stringName;
UIView *viewContainer;
UIView *viewBackup;
UIButton *buttonDone;
UIButton *buttonCancel;
UIImageView *imageViewForSplashScreen;

Per le Preprocessor Contants / Macros, come dettato dall’ANSI C, le definizione del pre-processore saranno tutte maiuscole e possono contenere il carattere underscore (_), unico caso in cui tollero gli “underscore”:

1
define( "MAX_ENTRIES", "20" );

Per le costanti un k davanti ne identifica subito il tipo:

1
NSString const *kAverageKey = @"Media";

Ottimizzare il codice? Si, ma dopo…

Ovvero spaziature, blocchi e valori di ritorno:

1
2
3
4
5
6
7
8
9
// No:
if(blah==="foo"){
   foo("bar","baz",{zoo:1});
}
   
// SI: più leggibile
if ( blah === "foo" ) {
   foo( "bar", "baz", {zoo: 1} );
}

if/else/for/while/try usare sempre le graffe anche quando abbiamo una singola linea; evitare di usare espressioni condizionali su una singola linea:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// NO:
if ( true ) return;
if ( true ) blah();
   
// SI:
if ( true ) {
    return;
}
   
if ( true ) {
    blah();
}

// SI:
if ( blah ) {
   baz();
} else {
   biz();
}

Questo permette di aggiungere codice nelle condizioni senza dover inserire “dopo” le graffe. Inoltre rende da subito il codice più leggibile, permettendo un più facile posizionamento dei commenti. Le if su singola linea, se da un lato sono permesse, non ottimizzano il codice quando compilato, ma solo a livello testuale, portando con se sempre un po’ di rischio nel momento in cui si altera la condizione.

Comodo per il debug è seguire anche la regola delle variabili di ritorno, ad esempio:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// NO:
function fileHandleFromFilename ( $filename ) {
    if( $filemame != "" ) {
        return fileHandle( $filename );
    }
    return false;
}

// SI:
function fileHandleFromFilename ( $filename ) {
    $result = false;
    if( $filemame != "" ) {
        $result = fileHandle( $filename );
    }
    return $result;
}

HTML + PHP

Quando possibile, soprattutto in codice misto PHP e HTML, usare le sintassi:

1
2
3
4
5
<?php if( $auto ) : ?>
    <span>auto</span>
    <?php else : ?>
    <span>manual</span>
<?php endif; ?>

Stessa cosa per i cicli for/while:

1
2
3
<?php foreach( $array as $key => $value ) : ?>
    <div>html code block</div>
<?php endforeach; ?>

Ulteriore nota sul discorso ottimizzazione

Ottimizzare il codice è argomento vasto ed articolato. Dipende sempre dal contesto e, soprattutto, va capito cosa si intende per ottimizzazione. In linea generale una prima ottimizzazione la si ottiene cercando di scrivere un codice semplice: meglio due funzioni invece che dieci, se il risultato finale non cambia.
Ma ottimizzare diventa facilmente sinonimo di velocizzare! In questo caso si apre un vero e proprio universo di soluzioni, legate al tipo di linguaggio e al tipo di applicazione che si sta scrivendo. Javascript, ad esempio, che è un linguaggio interpretato run time, soffre sicuramente del problema del sorgente rispetto ai linguaggi compilati. Durante la fase di compilazione i commenti non vengono presi in considerazione e i nomi delle funzioni, come quelli delle variabili, non hanno nessun effetto sulla velocità di esecuzione del codice.
In Javascript, come in parte anche in PHP, il modo in cui è scritto il codice sorgente ha una duplice importanza: primo perchè viene – al 99% dei casi – scaricato dalla rete, secondo perché viene interpretato run time.
Fotunatamente esistono strumenti, come i Javascript compressor, che permettono – una volta in esercizio – di aggirare elegantemente il problema.

Documentazione

Per la documentazione del codice, sotto consiglio, mi sono affidato ad un ottimo strumento open source: Doxygen. Strumenti come questo permettono di estrarre automaticamente la documentazione contenuta nei sorgenti (C++, C, Java, Objective-C, Python, IDL (Corba and Microsoft flavors), Fortran, VHDL, PHP, C#, …) producendo documentazione in HTML, LaTeX o PDF, con un semplice click del mouse. La cosa importante è rispettare alcune semplicissime regola durante la stesura della documentazione interna al codice.

Doxygen fa parte di una famiglia di sistemi (open e a pagameto) dedicati all’estrapolazione dei commenti nei codici sorgenti per la produzione di documentazione in vari formati, dall’HTML al Latex.
Strumenti come Doxygen hanno il vantaggio di rendere disponibile una completa documentazione a partire da un click, elaborando numerosi file sorgente e collegandoli in automatico, fornendo strumenti di indice, ricerca e grafici. Con l’occasione ecco alcuni tips che ho scoperto ultimamente:

Creare un contentuo per la index.html

Doxygen crea una pagina introduttiva normalmente bianca. Per inserire una prefazione o introduzione, inserite il commento qui sotto nel sorgente principale:

1
2
3
4
5
6
7
8
9
10
11
12
/*! \mainpage My Personal Index Page
 *
 * \section intro_sec Introduction
 *
 * This is the introduction.
 *
 * \section install_sec Installation
 *
 * \subsection step1 Step 1: Opening the box
 *  
 * etc...
 */

Escludere sezioni dall’estrazione della documentazione

Se desiderate nascondere parti o sezioni dalla documentazione ufficiale, potete usare queste espressioni condizionali:

1
2
3
//! @cond
... contenuto da escludere ...
//! @endcond

Documentazione delle categorie in Objective-C

Le categorie in Objective-C se non commentate a dovere, rischiano di essere escluse dalla documentazione. Per evitarlo non lasciare spazi tra il nome della classe e la sua categoria:

1
2
3
4
5
// Sbagliato
@interface NSFileManager (Helper)

// Corretto
@interface NSFileManager(Helper)

L’header può essere:

1
2
3
4
5
6
7
8
9
/// NSFileManager(Helper)
/**
 @category NSFileManager(Helper)
 @author Giovambattista Fazioli http://www.saidmade.com <g.fazioli@saidmade.com>
 @date Feb, 2011
 @version 1.0
 
 Estende la classe NSFileManager
 */

Sub versioning

Su questo argomento una sola cosa: usate un sistema di versioning, vi salva la vita! Ne esistono da tempo immemorabile un’infinità, oggi ancora più accessibili grazie al Web. Potete scegliere il classico Subversion (SVN) locale o affidarvi a servizi gratuiti o a pagamento come Google Code o GitHub. Scegliete voi, ma fatelo!

3 commenti a: “Coding Guidelines”

  1. 16 feb, 2011 Emanuele:

    Ottimo post. Aggiungerei anche la dichiarazione delle variabili messa sempre in alto, in modo da sapere direttamente dove andare a cercare invece di dover ravanare nel codice per individuarne dichiarazione ed inizializzazione…
    Ciao,
    Emanuele

  2. 16 feb, 2011 mauro:
    1
    2
    function getBackgroundColor() {} // Buono
    function backgroundColorFromTopMostWindow() {} // Ottimo

    Personalmente credo sia ottima la prima e buona la seconda, funzioni con nomi troppo lunghi sono difficili da ricordare se non le hai scritte tu stesso, due tre termini in camel case ed una buona documentazione! well done! Molta gente/aziende dovrebbero leggere questo post… Purtroppo dovrebbe essere scontato…

  3. 16 feb, 2011 Giovambattista Fazioli:

    @mauro:

    funzioni con nomi troppo lunghi sono difficili da ricordare

    Si, questo può essere vero, anche se l’ho segnalato appositamente perché da un lato oggi le IDE hanno tutte la funzione di intelli-sense, dall’altro perchè ci sono situazioni dove si ha:

    1
    2
    3
    function backgroundColorByName() {}
    function backgroundColorFromTopMostWindow() {}
    function backgroundColorFromScreen() {}

    ad esempio… quindi differenziare già dal nome è di aiuto :)

Lascia un commento

TAG XHTML PERMESSI: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> INSERIMENTO CODICE:
<pre></pre> // blocco generico
					<code></code> // blocco generico
					[cc_actionscript][/cc_actionscript] // Actionscript
					[cc_actionscript3][/cc_actionscript3] // Actionscript 3
					[cc_css][/cc_css] // CSS Style Sheet
					[cc_html][/cc_html] // HTML
					[cc_js][/cc_js] // Javascript
					[cc_objc][/cc_objc] // Objective-C
					[cc_php][/cc_objc] // PHP
					[cc_sql][/cc_sql] // SQL


Stop SOPA