La qualità è importante.
I programmi hanno dei bug. Necessitano di manutenzione e di estensioni. E coinvolgono molteplici programmatori.
Programmare bene richiede un equilibrio tra la necessità di raggiungere velocemente gli obiettivi e quella di poter continuare a raggiungerli in futuro. Potete bilanciare tra di loro il tempo, le risorse e la qualità. La capacità di arrivare a un buon bilanciamento determina il vostro livello di abilità e di pragmatismo come artigiani.
Conoscere Perl a fondo è importante. Altrettanto importante è sviluppare un senso estetico. L'unico modo di raggiungere questi obiettivi è fare pratica con la manutenzione del codice e con la lettura e scrittura di codice di qualità. Non ci sono scorciatoie, ma almeno potete seguire alcune linee guida.
La manutenibilità è il nebuloso concetto che misura la facilità di comprendere e modificare un programma scritto in precedenza. Mettete via un pezzo di codice per sei mesi, e poi tornate a guardarlo. La manutenibilità misura le difficoltà che dovete affrontare per modificarlo.
La manutenibilità non è né un problema sintattico né una misura di come il vostro codice appare a un non-programmatore. Potete assumere che chi ha a che fare con il codice sia un programmatore competente che ha una buona comprensione della natura del problema che il codice deve risolvere. Quali ostacoli si possono incontrare quando si tenta di risolvere un bug o di fare una miglioria in modo corretto?
La capacità di scrivere codice manutenibile deriva da esperienza guadagnata sul campo con fatica e dalla padronanza degli idiomi, delle tecniche e dello stile dominante del linguaggio. Ciò nonostante, anche i principianti possono migliorare la manutenibilità del loro codice osservando alcuni principi:
I sistemi ben progettati hanno poche duplicazioni. Utilizzano funzioni, moduli, oggetti e ruoli per isolare il codice duplicato in componenti riusabili che modellano in modo accurato il dominio del problema. I migliori progetti vi permettono di aggiungere funzionalità rimuovendo del codice.
Alcuni problemi richiedono soluzioni particolarmente intelligenti. Incapsulate questo codice dietro a semplici interfacce e documentate bene i vostri colpi di genio.
La semplicità non è una scusa per evitare il controllo degli errori o la modularità o la validazione o la sicurezza. Il codice semplice può usare funzionalità avanzate e moduli CPAN in abbondanza; può anche richiedere un certo impegno per essere capito. Ciò che conta è che risolve efficacemente i problemi senza sforzi inutili.
Certe volte vi serve codice robusto e potente. Altre volte ciò di cui avete bisogno è un programma lungo una linea. Semplicità significa conoscere la differenza tra questi casi e ottenere il risultato desiderato.
Perl prende a prestito liberamente da altri linguaggi e vi permette di scrivere il codice che volete. I programmatori C scrivono spesso codice Perl in C-style, proprio come i programmatori Java scrivono codice Perl in stile Java. I buoni programmatori Perl scrivono codice Perl in stile Perl, adottando gli idiomi del linguaggio.
Gli sviluppatori CPAN, i Perl Monger e i membri delle mailing list hanno esperienze guadagnate sul campo nella soluzione di problemi in innumerevoli modi diversi. Parlategli. Leggete il loro codice. Fate domande. Imparate da loro e lasciate che loro imparino da voi.
Perl::Critic), la riformattazione (Perl::Tidy) e i sistemi privati di distribuzione (CPAN::Mini). Sfruttate l'infrastruttura CPAN; seguite il modello di scrittura, documentazione, packaging, testing e distribuzione del codice di CPAN.La manutenibilità è, in ultima analisi, un problema di progettazione. A sua volta, una buona capacità di progettazione deriva dalla pratica di alcune buone abitudini:
Se trovate un bug, segnalatelo e, se possibile, risolvetelo. Se trovate un errore di battitura, correggetelo. Chiedete nuove funzionalità. E ricordatevi di dire "Grazie!". Siamo meglio come comunità che come individui separati. E abbiamo tutti più potenza ed efficacia se riusiamo il codice.
Quando avete risolto un nuovo problema e vi sentite pronti, condividetelo. Unitevi a noi. Anche noi risolviamo problemi.
Programmare bene significa anticipare le situazioni impreviste. File che dovrebbero esistere e non ci sono. Un hard disk enorme che non dovrebbe mai riempirsi ma lo fa. La connessione di rete che dovrebbe sempre essere disponibile ma non lo è. Un database infallibile che fallisce. Le cose eccezionali succedono e un software robusto dovrebbe saperle gestire. Se potete ripristinare il funzionamento, è un'ottima cosa! Ma se non potete, fate almeno il logging delle informazioni rilevanti e riprovate.
Perl 5 gestisce le situazioni eccezionali attraverso le eccezioni: un meccanismo di controllo di flusso con scope dinamico progettato per segnalare e gestire gli errori.
Supponete di voler scrivere su un file di log. Se non riuscite ad aprire tale file, qualcosa sta andando storto. Usate die per sollevare un'eccezione:
sub apri_file_log
{
my $nome = shift;
open my $fh, '>>', $nome
or die "Apertura del file di log '$nome' non riuscita: $!";
return $fh;
}
die() imposta il valore della variabile globale $@ a quello del proprio operando ed esce immediatamente dalla funzione corrente senza restituire nulla. L'eccezione sollevata continua il suo percorso nello stack di chiamate (Esecuzione Controllata) finchè incontra del codice che la cattura. Se nessuna chiamata cattura l'eccezione, il programma termina con un errore.
La gestione delle eccezioni adotta lo scope dinamico (Scope Dinamico) come i simboli local.
Talvolta è utile che un'eccezione faccia terminare il programma. Un programma eseguito come processo temporizzato potrebbe sollevare un'eccezione quando i log di errore sono pieni, in modo che venga inviato un SMS agli amministratori. Tuttavia non tutte le eccezioni dovrebbero essere fatali. I programmi ben scritti talvolta riescono a ripristinare il funzionamento o almeno a salvare il proprio stato e terminare in modo controllato.
Usate la forma a blocco dell'operatore eval per catturare un'eccezione:
# l'apertura del file di log potrebbe fallire
my $fh = eval { apri_file_log( 'paperopoli.log' ) };
Se l'apertura del file ha successo, $fh conterrà il filehandle. Se fallisce, $fh resta non definito, e il flusso del programma continua.
Il blocco passato come argomento a eval introduce un nuovo scope, sia lessicale che dinamico. Se apri_file_log() chiamasse altre funzioni e una di queste lanciasse un'eccezione, questo eval la catturerebbe.
Un gestore di eccezioni dev'essere uno strumento generico, dato che potrebbe catturare tutte le eccezioni nel suo scope dinamico. Per capire quale eccezione è stata catturata (e anzitutto se c'è stata un'eccezione) controllate il valore di $@. Ricordatevi di localizzare $@ prima di tentare di catturare un'eccezione, dato che $@ è una variabile globale:
local $@;
# l'apertura del file di log potrebbe fallire
my $fh = eval { apri_file_log( 'paperopoli.log' ) };
# eccezione catturata
if (my $eccezione = $@) { ... }
Copiate immediatamente $@ in una variabile lessicale per evitare che il codice eseguito successivamente possa sovrascrivere la variabile globale $@. Non potete sapere se da qualche parte c'è un blocco eval che può reimpostare $@.
Solitamente $@ contiene una stringa che descrive l'eccezione. Ispezionatene il contenuto per capire se potete gestire l'eccezione:
if (my $eccezione = $@)
{
die $eccezione
unless $eccezione =~ /^Il file di log non puo' essere aperto/;
$fh = log_su_syslog();
}
Rilanciate un'eccezione chiamando di nuovo die(). Passatele l'eccezione corrente oppure una nuova eccezione a seconda delle vostre esigenze.
Applicare delle espressioni regolari a eccezioni stringa è poco robusto, dato che i messaggi d'errore possono cambiare nel tempo. Questo vale anche per le eccezioni predefinite sollevate dallo stesso Perl. Per fortuna, potete anche passare a die un riferimento—e perfino un riferimento blessed. Ciò vi permette di fornire molte più informazioni nella vostra eccezione: numeri di linea, file e altre informazioni di debug. Ottenere queste informazioni da un'entità strutturata è molto più facile che estrarle interpretando una stringa. Catturate queste eccezioni come fareste con qualunque altra eccezione.
La distribuzione CPAN Exception::Class facilita la creazione e l'uso di oggetti eccezione:
package Zoo::Eccezioni
{
use Exception::Class
'Zoo::AnimaleFuggito',
'Zoo::GestoreFuggito';
}
sub gabbia_aperta
{
my $self = shift;
Zoo::AnimaleFuggito->throw
unless $self->contiene_animale;
...
}
sub ufficio_aperto
{
my $self = shift;
Zoo::GestoreFuggito->throw
unless $self->contiene_gestore;
...
}
Mentre sollevare eccezioni è relativamente semplice, catturarle lo è di meno. Usare $@ correttamente vi richiede di scansare svariati rischi piuttosto insidiosi:
localizzato della variabile $@ all'interno dello scope dinamico potrebbe modificarla$@ potrebbe contenere un oggetto che sovrascrive il proprio valore booleano in modo da restituire falsoDIE) potrebbe modificare $@eval e cambiare $@ Alcuni di questi problemi sono stati risolti in Perl 5.14. Se da una parte essi si presentano molto raramente, dall'altra sono spesso difficili da diagnosticare e risolvere. La distribuzione CPAN Try::Tiny migliora l'affidabilità e la sintassi della gestione di eccezioni In effetti, Try::Tiny è stato di ispirazione per le migliorie alla gestione delle eccezioni in Perl 5.14..
Try::Tiny è facile da usare:
use Try::Tiny;
my $fh = try { apri_file_log( 'paperopoli.log' ) }
catch { log_eccezione( $_ ) };
try sostituisce eval. Il blocco opzionale catch viene eseguito solo quando try cattura un'eccezione. catch riceve l'espressione catturata nella variabile topic $_.
Perl 5 può sollevare svariate eccezioni. perldoc perldiag elenca numerosi "errori fatali intercettabili". Mentre alcuni di essi sono errori di sintassi sollevati durante il processo di compilazione, altri possono essere catturati durante l'esecuzione. Quelli di maggiore interesse sono:
Naturalmente, potete anche catturare le eccezioni prodotte da autodie (La direttiva autodie) e i warning lessicali promossi a eccezioni (Registrare i Vostri Warning).
Molte delle estensioni di Perl 5 sono moduli che forniscono nuove funzioni o definiscono classi (Moose). Alcuni moduli, invece, come strict e warnings, influenzano il comportamento del linguaggio stesso. Tali moduli sono detti direttive. Per convenzione, le direttive hanno nomi con soli caratteri minuscoli per differenziarli dagli altri moduli.
Il funzionamento delle direttive consiste nell'esportare comportamenti o informazioni specifiche nello scope lessicale dei loro chiamanti. Così come dichiarare una variabile lessicale rende disponibile in uno scope il nome di un simbolo, usare una direttiva attiva il suo comportamento in un certo scope:
{
# $lessicale non e` visibile; strict non e` attiva
{
use strict;
my $lessicale = 'disponibile qui';
# $lessicale e` visibile; strict e` attiva
...
}
# $lessicale e` di nuovo invisible; strict non e` attiva
}
Inoltre, così come le dichiarazioni lessicali interessano anche gli scope più interni, le dichiarazioni rimangono attive in tali scope:
# scope di file
use strict;
{
# scope interno, dove strict continua a essere attivo
my $interno = 'un altro lessicale';
...
}
Fate la use di una direttiva come fareste con qualunque altro modulo. Le direttive possono ricevere argomenti, ad esempio un numero minimo di versione accettabile e una lista di argomenti per modificarne il comportamento:
# richiede la dichiarazione delle variabili e proibisce le bareword
use strict qw( subs vars );
Talvolta vi servirà disattivare del tutto o in parte gli effetti di una direttiva in uno scope lessicale annidato. L'istruzione predefinita no annulla un'importazione (Importazione), il che disattiva gli effetti di una direttiva se essa si conforma alle regole. Per esempio, se volete disattivare la protezione di strict quando dovete manipolare direttamente dei simboli:
use Modern::Perl;
# oppure use strict;
{
no strict 'refs';
# manipolazione della tabella dei simboli
}
In Perl 5.10.0 è stata aggiunta la possibilità di scrivere le proprie direttive lessicali in puro codice Perl. perldoc perlpragma vi spiega come fare e la descrizione di $^H in perldoc perlvar vi spiega il suo funzionamento.
Già prima della versione 5.10, Perl 5 includeva svariate direttive predefinite utili:
strict attiva il controllo durante la compilazione dei riferimenti simbolici, dell'uso di bareword e della dichiarazione di variabili.warnings attiva l'emissione di warning per comportamenti deprecati, inappropriati o confusi del codice.utf8 forza il parser a interpretare il codice sorgente con la codifica UTF-8.autodie attiva il controllo automatico degli errori nelle chiamate alle funzioni di sistema e predefinite.constant vi permette di creare valori costanti durante la compilazione (vedete il modulo CPAN Const::Fast per un'alternativa).vars vi permette di dichiarare variabili globali di package, come $VERSION e @ISA (Riferimenti Blessed).feature vi permette di attivare e disattivare singolarmente le funzionalità post-5.10. La direttiva use feature ':5.14'; è equivalente a use 5.14;, ovvero attiva tutte le funzionalità di Perl 5.14 più la direttiva strict. Questa direttiva è più utile per disattivare singolarmente delle funzionalità in uno scope lessicale.less illustra come scrivere una direttiva.CPAN ha iniziato a raccogliere delle direttive non predefinite:
autobox attiva un comportamento ad oggetti per i tipi predefiniti di Perl 5 (scalari, riferimenti, array e hash).perl5i combina e attiva numerose estensioni sperimentali del linguaggio in un tutto coerente.autovivification disattiva l'autovivificazione (Autovivificazione)indirect previene l'uso dell'invocazione indiretta (Oggetti Indiretti)Attualmente, questi strumenti non sono molto usati. Gli ultimi due vi aiutano a scrivere codice più corretto, mentre coi primi due vale la pena di fare degli esperimenti all'interno di piccoli progetti. Essi rappresentano delle interessanti potenzialità di Perl 5.