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 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 |
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 |
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!








4
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
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…
@mauro:
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:
2
3
function backgroundColorFromTopMostWindow() {}
function backgroundColorFromScreen() {}
ad esempio… quindi differenziare già dal nome è di aiuto