Stile ed Efficacia

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.

Scrivere Codice Perl Manutenibile

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:

Scrivere in Perl Idiomatico

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.

Scrivere Codice Perl Efficace

La manutenibilità è, in ultima analisi, un problema di progettazione. A sua volta, una buona capacità di progettazione deriva dalla pratica di alcune buone abitudini:

Eccezioni

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.

Sollevare Eccezioni

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.

Catturare Eccezioni

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;
        ...
    }

Avvertenze sulle Eccezioni

Mentre sollevare eccezioni è relativamente semplice, catturarle lo è di meno. Usare $@ correttamente vi richiede di scansare svariati rischi piuttosto insidiosi:

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 $_.

Eccezioni Predefinite

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).

Direttive

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.

Direttive e Scope

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';
        ...
    }

Uso delle Direttive

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
    }

Direttive Utili

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:

CPAN ha iniziato a raccogliere delle direttive non predefinite:

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.