Historial de cambios http://taquiones.net/historico.html Victor Moral: Nombrando objetos: plantillas gramaticales Victor Moral http://taquiones.net/perl/pbp/essential/grammatical_templates.html http://taquiones.net/perl/pbp/essential/grammatical_templates.html pbp perl sar Nombrando objetos: plantillas gramaticales

Una de las prácticas más recomendadas a la hora de escribir código es la coherencia en la nomenclatura de objetos, tanto si se trata de variables como si se trata de código ó de objetos (que vienen a ser una mezcla de ambos).

Conway recomienda utilizar lo que he traducido por plantillas gramaticales y sugiere (en su estilo) lo siguiente.

Paquetes y clases

La plantilla es la siguiente:

Espacio de Nombres  ->      Nombre :: Adjetivo :: Adjetivo
                        |   Nombre :: Adjetivo
                        |   Nombre

De manera que una jerarquía de clases sobre discos podría quedar así:

package Disk;
package Disk::Audio;
package Disk::DVD;
package Disk::DVD::Rewritable;

Es decir, cuanto más se especializa la clase más adjetivos se le añaden al sustantivo común Disk, y su propósito es ayudar a recordar las relaciones existentes entre clases de un sólo vistazo.

Variables

Para las variables la plantilla es:

Variable    ->  [ adjetivo _ ]* nombre

Los nombres de las variables deberían ser asignados con relación a su contenido y siendo tan específicos como fuese posible. Es decir el nombre (y los adjetivos) deben elegirse en los términos del problema y no en los términos de la implementación.

Ahora bien, en español nombrar las variables tal y como propone puede resultar bastante chocante, puesto que los adjetivos suelen ir a continuación del nombre y no precediéndole.

Conway también indica que aquellas variables cuyo ámbito es de más de un bloque deberían tener nombres largos (que consisten en varios sustantivos separados por un subrayado), mientras que los cortos deberían usarse en variables con un tiempo de vida más limitado.

Algunos ejemplos de nombres de variables:

my $next_client;         # no $next_item
my $final_total;         # no $sum
my $cumulative_total;    # no $partial_sum

Métodos y funciones

PENDIENTE DE COMPLETAR

Conmutadores y referencias

PENDIENTE DE COMPLETAR

]]>
Víctor Moral: Cuando faltan parámetros Víctor Moral http://taquiones.net/perl/pbp/essential/missing_arguments.html http://taquiones.net/perl/pbp/essential/missing_arguments.html pbp perl Cuando faltan parámetros ...

... en la llamada a una función lo normal es efectuar una comprobación al inicio de ésta. Ahora bien, un error común es emplear expresiones de este tipo

sub rellenar {
    my ($texto$ancho$relleno) = @_;

    croak "usage: ..." 
        if !texto || !$ancho || !$relleno;

    # etc.
}

puesto que alguno de los parámetros puede contener un valor que expande a cero (como el carácter de relleno 0) que sería aceptable en otro caso.

Existe una forma más fiable de verificar esto y consiste en aplicar un test de definición (defined) a cada uno de los elementos.

Gracias al módulo list moreutils disponemos de varias funciones para trabajar rápidamente con listas:

use List::MoreUtils qw(any);

sub rellenar {
    my ($texto$ancho$relleno) = @_;

    croak "usage: ..."
        if any { !defined $_ } $texto$ancho$relleno;

    # etc.
}

En el caso de que un valor undef sea aceptable para uno ó todos los parámetros bastará con comprobar si tenemos tantos como esperamos, pero sin inspeccionar su valor:

sub rellenar {
    croack "usage: ..." if @_ != 3; 

    my ($texto$ancho$relleno) = @_;

    # etc.
}

Como vimos en [[el paso de parámetros por nombre|perl/pbp/essential/named_arguments]] teníamos otra posibilidad bastante común: uno ó más parámetros fijos seguidos por un hash con el resto. Y en este caso también es posible verificar el número de parámetros (e incluso su contenido) de manera sencilla:

sub rellenar {
    croak "usage: ..." if @_ < 1 || @_ > 2;

    my ($text$arg_ref) = @_;

    # etc.
}
]]>
Víctor Moral: Usar un hash con los parametros si hay m&#xE1;s de tres Víctor Moral http://taquiones.net/perl/pbp/essential/named_arguments.html http://taquiones.net/perl/pbp/essential/named_arguments.html fixme pbp perl Usar un hash con los parametros si hay más de tres

Si una subrutina recibe más de tres parámetros (ó parece que puede ser así en el futuro) lo idóneo es empaquetarlos en un hash y enviarle una referencia (ojo con esto).

La función ejemplo sirve para rellenar un texto con una longitud dada, usando un caracter concreto y opcionalmente centrado sobre él. Para ello recibe como parámetros:

  • text: texto a centrar
  • cols: longitud final
  • centered: indicador de centrado
  • filler: carácter de relleno
sub rellenar {
    my ($arg_ref) = @_;

    my $sobrante = $arg_ref->{cols} - length $arg_ref->{text};
    my $izquierda = $arg_ref->{centered} ? int($sobrante/2) : 0;
    my $derecha = $sobrante - $izquierda;

    return  $arg_ref->{filler} x $izquierda 
            . $arg_ref->{text}
            . $arg_ref->{filler} x $derecha;
}

my $linea = rellenar( { text => $mytext, cols => 30, filler => '.' });

Por qué usar una referencia

Damian recomienda pasar una referencia y no un hash para que la comprobación de errores se realice en tiempo de compilación, y no en tiempo de ejecución.

Por ejemplo en el siguiente código:

my $linea = rellenar( { text => $mytext, cols => 30..40, filler => '.' });

El error Odd number of elements in anonymous hash ... se producirá según Perl lee y compila el código, mientras que en el caso de usar un hash:

    1  sub rellenar {
    2      my  %args = @_;
    3  
    4  
    5  }
    6  
    7  my $linea = rellenar( text => $mytext, cols => 30..40, filler => '.' );

El error se producirá en la línea 2, cuando se copie @_ sobre el hash %args en forma de una excepción. Es menos intuitivo según él.

Ventajas de usar un hash

Por contra, utilizar un hash permite hacer un pequeño truco que a mí particularmente me gusta mucho, y es el asignar valores por defecto según se reciben los parámetros:

our %defaults = ( cols => 80, filler => ' ', centered => 0 );

sub rellenar {
    my  %args = ( %defaults@_ );

}

Así que, mientras recibamos un hash correcto, tenemos la seguridad de que existen unos valores predeterminados en los parámetros.

Ahora bien, ¿ y si queremos hacer lo mismo con una referencia en lugar de una copia ?

our %defaults = ( cols => 80, filler => ' ', centered => 0 );

sub rellenar {
    my  $arg_ref = shift;
    my  %args    = ref $arg_ref eq 'HASH' ? ( %defaults%$arg_ref } )
                    : %defaults;

    # etc.
}

Es decir, sólo tomamos los parámetros si son una referencia a un hash, en caso contrario usamos sólo los valores por defecto.

Si alguno de los parámetros es fijo

En el caso de que uno ó varios parámetros se envíen siempre es recomendable pasarlos primero, por posición, y añadir después el hash con el resto de ellos.

En el caso de la función ejemplo el texto a centrar es obligatorio siempre (otra cosa no tiene mucho sentido) por lo que podemos redefinirla de alguna de estas dos formas:

sub rellenar {
    my  ($text$arg_ref) = @_;

}

sub rellenar {
    my  $text   =   shift;
    my  %args   =   ( %defaults@_ );

}
]]>
Pr&#xE1;cticas esenciales http://taquiones.net/perl/pbp/essential.html http://taquiones.net/perl/pbp/essential.html fixme pbp perl Diez prácticas fundamentales ...

... durante el desarrollo

  1. Diseñar lo primero el interfaz del módulo.

  2. Escribir test para probar el código antes de empezar éste.

  3. Construir plantillas estándar en formato POD para módulos y aplicaciones.

  4. Utilizar un sistema de control de versiones.

  5. Crear interfaces de órdenes y archivos configuración consistentes.

  6. Acordar un estilo coherente para codificar y automatizarlo con perltidy.

  7. Incluír código en párrafos comentados

  8. Generar excepciones en lugar de retornar valores especiales ó señalizar indicadores en caso de error.

  9. Añadir nuevos test antes de comenzar la depuración.

  10. No intentar optimizar el código sin haber medido antes su tiempo de ejecución (benchmark).

... mientras escribimos código

  1. Utilizar siempre las directivas strict y warnings.

  2. Al crear identificadores usar [[plantillas gramaticales|perl/pbp/essential/grammatical_templates]] para dotar de coherencia a las variables, clases, funciones y métodos.

  3. Utilizar variables de ámbito léxico y no variables de paquete ó clase.

  4. Etiquetar todos los bucles en los que exista una salida explícita, así como en los operadores next, last y redo.

  5. Don't use bareword filehandles; use indirect filehandles.

  6. En una subrutina extraer lo primero de todo los parámetros de @_, usar un hash de parámetros si éstos son más de tres y comprobar siempre si faltan parámetros.

  7. Siempre salir de una función ó un método con una instrucción return explícita.

  8. En las expresiones regulares utilizar siempre los indicadores /x, /m y /s, así como los delimitadores `\A' y '\Z'.

  9. En las expresiones regulares utilizar paréntesis para captura de datos sólo cuando realmente se vaya a extraer información. En este caso, además, es conveniente darle nombres a cada token recuperado, en lugar de usar las variables $1, $2, ...

  10. Nunca hacer que una variable sea parte del interfaz de un módulo. Utilizar un método de clase ú objeto, ó una función.

... cuando construímos módulos y librerías

  1. Escribir los programas de testeo usando los módulos Test::Simple ó Test::More.

  2. Utilizar el módulo English para aquellas variables cuyo nombre es un signo de puntuación, ya que nos son menos familiares.

  3. Crear constantes con nombre con el módulo Readonly. No estoy demasiado de acuerdo con esto dada la no disponibilidad del módulo en el paquete perl-modules, pero entiendo las razones que da para recomendarlo.

  4. Usar las funciones que proporcionan los módulos Scalar::Util, List::Util y List::MoreUtils, dado que son prácticamente funciones integradas (builtins).

  5. Utilizar el módulo IO::Prompt cuando se necesiten entradas de datos interactivas.

  6. Utilizar los módulos Carp y Exception::Class para gestionar errores mediante excepciones orientadas a objeto, de manera que se informe de dónde se produce el error y no donde se detecta.

  7. Usar el módulo Fatal para que las funciones integradas lancen excepciones al encontrarse errores.

  8. Crear alias mediante los módulos Data::Alias ó Lexical::Alias.

  9. Utilizar el módulo Regexp::Common en lugar de escribir expresiones regulares desde cero.

  10. Utilizar el módulo Class::Std para construir clases adecuadamente encapsuladas.

]]>