Parliamo di convenzioni: sì, quelle lunghe liste di "si può fare", "è meglio scrivere", "non dovete usare" e via dicendo. Le convenzioni sono essenziali per programmare, per due motivi:
- Migliorano la leggibilità dei vostri programmi consentendo facilmente ad altre persone di intervenire sul codice, sfruttare le vostre classi o semplicemente correggere un bug.
- Alcuni linguaggi, tra i quali Java, Python ed anche Ruby si basano su alcune convenzioni e modellano il loro comportamento in base ad esse.
Un paio di esempi.
Per Python non esistono parentesi e tutto si basa sull'indentazione del codice. Se il blocco di codice all'interno di una iterazione non è indentato rispetto alla condizione di iterazione, allora l'esecuzione probabilmente restituirà un errore.
Dall'altro lato, Ruby identifica una variabile scritta in maiuscolo come una costante e restituirà un messaggio di avviso se si tenta di modificarne il valore.
Poiché non stiamo giocando a fare i programmatori, prima di lanciarci nel codice nudo e crudo è essenziale spendere due parole sulle convenzioni.
A proposito di convenzioni e linee guida, consiglio di non lasciarsi scappare neanche un post della mini serie Linee guida nella scrittura di codice curata da Gianni Malanga.
Quella che segue è una personale raccolta di convenzioni, basate sull'esperienza e su quanto dettato dalla community di Ruby. Vi invito ad approfondire la lettura visitando Ruby Style Guide.
Convenzioni sui nomi
Esistono sostanzialmente tre tipi di convenzioni:
- Come per quasi tutti i linguaggi, i nomi delle costanti sono scritti completamente in maiuscolo (upper case), usando l'underscore
_
per separarare i termini. Per convenzione ogni variabile scritta completamente in maiuscolo è interpretata da Ruby come costante. - I nomi di classi e moduli adottano il PascalCase, ovvero l'uso del carattere maiuscolo per ogni parola che compone il nome.
- I nomi di metodi, variabili adottano lo snake case, ovvero completamente minuscolo con i termini separati da un carattere underscore
_
.
Formattazione dei file
Per quanto riguarda l'eterna lotta Tab vs Spazi, la convenzione è di non utilizzare Tab ma Soft Tab (ovvero tab convertite in automatico in spazi) o spazi direttamente. La dimensione di ogni Soft Tab è fissata a 2 caratteri, al contrario ad esempio di Java (4, 8 per i rientri) e PHP (4).
Per quanto riguarda la lunghezza di ogni riga non c'è convenzione fissata, tuttavia è abitudine non superare gli 80 caratteri per linea per agevolare la stampa del file. Oltre gli 80 caratteri alcuni editor non gestiscono correttamente la visualizzazione e l'impaginazione.
Stile di programmazione
Esistono poi diversi altri aspetti legati agli standard su Ruby, o per meglio dire, convenzioni adottate nel tempo.
Ad esempio, Ruby permette di scegliere se utilizzare o meno le parentesi per richiamare i metodi. Spesso è abitudine non utilizzarle, soprattutto nel caso in cui i metodi siano privi di parametri.
object.do_something object.do_something() object.do_something "foo" object.do_something("foo")
La mia personale esperienza è che troppa libertà porti al disordine. Per questo motivo mi sono imposto di utilizzare le parentesi per ogni chiamata di metodo, anche in caso non ci siano parametri. L'unica eccezione sono le chiamate in lettura/scrittura alle variabili di classe per le quali non utilizzo alcuna parentesi, sebbene in Ruby siano gestite internamente attraverso dei metodi.
object.do_something object.do_something("foo") object.bar = 'bar' bar = object.bar
Ovviamente si tratta di una linea guida personale, nulla vi vieta di agire diversamente.
Discorso analogo per l'istruzione return
. In Ruby ogni esecuzione restituisce un valore, compreso un costrutto if/else
.
Il valore restituito è il valore dell'ultima istruzione interpretata.
Ad esempio, un metodo che restituisce la data attuale potrebbe essere scritto come
def now() Time.now() end
Time.now()
è l'ultima istruzione elaborata dunque il metodo restituirà il suo valore. Anche in questo caso, poiché è una scelta, trovo che questa soluzione renda poco leggibile classi molto complesse, soprattutto se si miscela la direttiva return esplicita con un return implicito all'interno dello stesso metodo!
def now(return_false = true) return false if return_false Time.now() end
Per questo motivo ho adottato la convenzione di utilizzare sempre un ritorno esplicito, quando intenzionale.
Sempre per quanto riguarda Ruby, è importante tenere in considerazione qualche convenzione de facto:
- Utilizzate gli iteratori, sono vantaggiosi
- Preferite i Namespace ai prefissi
- Evitate di sottointendere troppo!
- I blocchi aiutano a gestire al meglio le risorse
Potete riscontrare queste convenzioni nella classe Person pubblicata nella puntata #05... spero di non averne dimenticata nessuna! :P
Avete qualche altro suggerimento? Quali convenzioni adottate nella scrittura del vostro codice?