Nilson Santos Figueiredo JúniorPublicado em 20/08/2006
r3 - 20 Aug 2006 - JoenioCosta
----
----
Essas recomendações foram fortemente baseadas no "perlstyle" - a manpage que é o guia de estilo de programação "oficial" de Perl. Além disso uma outra apresentação com sugestões de estilo para garantir a legibilidade do código também foi utilizada como base. Essa apresentação pode ser gerada a partir do script contido no endereço:
Cada programador terá as suas próprias preferências relativas à formatação do código. Porém, existem algumas sugestões gerais que tornarão os programas mais fáceis de ler, entender e manter.
A primeira e mais importante providência a se tomar é executar os programas sob a flag -w ou então garantir que exista um "use warnings" no início de cada arquivo. Os programas também devem sempre rodar sob "use strict". Essas duas recomendações garantem com que muitos problemas nem cheguem a aparecer no futuro. Caso você tenha algum problema, um "use diagnostics" tentará dar uma explicação do que significa um warning e os motivos usuais dele estar sendo disparado. Às vezes é interessante que os warnings se tornem fatais, para que o programa se recuse a executar caso existam warnings. Nesse caso, utilize:
use warnings FATAL => 'all';
Esses são apenas guias de estética. As recomendações mais importantes estão marcadas com um astericos. Um "bloco" é definido por uma abertura e fechamento de chaves.
@animais = ( 'cachorro', 'gato', 'avestruz',
'urubu', 'leão', 'girafa' );
Essas foram algumas sugestões mais superficiais. Bem ligadas à estética tradicional do código. Algumas sugestões mais substanciais são:
open(my $fh, 'arq') or die "Não foi possível abrir 'arq': $!";
é melhor que
die "Não foi possível abrir 'arquivo': $!" unless open(my $fh, 'arq');
porque a segunda forma esconde o ponto principal da sentença em um modificador. Por outro lado
print "Iniciando análise\n" if $verbose;
é melhor que
$verbose && print "Iniciando análise\n";
porque o ponto principal não é se o usuário está em modo verbose ou não.
for my $i (1..10) {
my $resultado = funcao($i);
# termina o loop se o resultado for verdadeiro
last if $resultado;
processa_inteiro($i);
}
LINE: while (<$fh>) {
next LINE if /xxx/;
CHAR: for my $char (split '') {
next CHAR if /[A-F]/;
next LINE if /[0-9]/
print $char;
}
}
$fh>
$ALL_CAPS_HERE constantes (cuidado pois existem nomes reservados)
$Some_Caps_Here variáveis globais
$no_caps_here variáveis de escopo local ( my() ou local() )
Nomes de funções e métodos normalmente ficam melhores sempre em letras minúsculas.
Você pode utilizar um underscore como caracter inicial de um identificador para indicar que uma variável ou função não deve ser utilizada fora do pacote em que ela foi definida (variáveis / métodos privados).
Ao invés de
$output .= "\n";
$output .= " \n";
$output .= " \n";
$output .= " \n";
$output .= "\n";
Utilize
$output .= <<'ENDOFHTML';
ENDOFHTML
Note que a string de fim do documento deve estar sozinha numa linha, sem caracteres (incluindo espaços) antes ou depois. A indentação observada acima é do documento e não do código.
Escreva módulos que aceitam a forma
Modulo->funcao(@parâmetros);
Ao invés de
Modulo::funcao(@parâmetros);
O primeiro ponto a ser levantado é um dos mais importantes: sempre que fizer sentido, pense em reusabilidade. Porque desperdiçar seu esforço com uma solução específica se depois você provavelmente precisará de fazer algo similar novamente? Pense em generalizar o seu código. Pense em escrever um módulo ou uma classe.
Sempre lembre que você está programando em Perl. Como foi citado na seção anterior, "só porque você PODE fazer alguma coisa de uma maneira específica não significa que você DEVA fazer dessa forma". Se você se encontrar escrevendo linhas de programa que se pareçam com C, Java ou Pascal, você não está no caminho correto. Você precisa aprender a programar o "Perl nativo". Não evite certas formas de escrever o código só porque ela utiliza um recurso pouco conhecido e/ou inexistente em outras linguagens. Quem for manter seu código no futuro deve ser alguém que conhece a linguagem. Você não escreve português para que um alemão ou francês entenda, você escreve português para que pessoas que entendam português leiam.
Procure sempre escrever programas que são funcionais, minimalísticos, flexíveis e compreensíveis (não necessariamente nessa ordem). Pense primeiro, depois comece a programar. Se as coisas parecerem muito ruins, jogue tudo fora e comece do zero de novo. Nunca tente "remendar" algo que está ruim: sempre que possível, refaça do zero. Isso melhora o seu entendimento, aprimora a criatividade e produz um produto final mais refinado. Lembre-se: o bom senso é o que reina nas boas práticas de programação. Algumas vezes, um código menor o torna mais mantível, outras vezes não.
Faça comentários relevantes, sem parafrasear o código. Fique longe de grandes blocos de comentários com pouco conteúdo e caracteres de pontuação em volta "desenhando" o seu contorno. Porém, não faça comentários de linhas específicas mas, sim, comentários relativos a um bloco de código inteiro. Normalmente, é mais importante que suas estruturas de dados estejam bem comentadas que os algoritmos propriamente ditos. Isso não é uma regra geral, mas, normalmente, um código que precisa de comentários para ser entendido por um programador fluente na linguagem é um indício de um código mal escrito.
Quebre tarefas complexas em subrotinas. Quebre subrotinas em pedaços que são mais facilmente gerenciáveis. Não tente colocar tudo em uma só expressão regular. Quando você vê funcionalidade similar em dois lugares, unifique o código em uma subrotina mais genérica.
Para evitar os comentários é fundamental que a escolha dos nomes de variáveis, funções, procedimentos, etc. seja feita de forma pensada. Não basta seguir uma convenção: novamente, o bom senso é muito importante.
Como regra geral, os nomes de procedimentos (subs que não retornam nada) devem refletir o que elas fazem. Os nomes de funções devem refletir o que elas retornam. Dê nome às coisas de forma que elas leiam bem na linguagem na em que o código é escrito. Caso estejamos usando inglês para nomear uma função que retorna verdadeiro ou falso, "is_ready" é um nome melhor que "ready". E assim por diante, utilizando os predicados "is", "does", "can", "has", etc. Assim sendo, teremos "canonize" como um procedimento, "canonical_version" com uma função que retorna um valor e "is_canonical" como uma verificação booleana. Para funções de conversão ou de mapeamento, "abc2xyz" ou "abc_to_xyz" são nomes normalmente utilizados. Hashes normalmentes especificam uma propriedade das suas chaves e são usadas como uma relação de possessividade. Em outras palavras, dê nome às hashes pelos seus valores não pelas suas chaves. Por ex:
%color = ('apple' => 'red', 'banana' => 'yellow');
print $color{'apple'}; # Prints `red'
%fruit = ('apple' => 'red', 'banana' => 'yellow');
print $fruit{'apple'}; # Prints `red'
Ao nomear alguns tipos de variáveis, muitas vezes é interessante utilizar algumas convenções relativas ao seu tipo. Abaixo estão algumas sugestões para prefixos de nomes de variáveis retiradas diretamente da manpage do "DBI":
$dbh Database handle object
$sth Statement handle object
$fh A filehandle
\%attr Reference to a hash of attribute values passed to methods
Algumas seções atrás, quando falávamos sobre filosofia de desenvolvimento, citamos que existem recursos que fazem com que seu código deixe de se parecer com outras linguagens e se torne "Perl nativo". Aqui serão listadas algumas dessas técnicas.
Quando trabalhando com expressões regulares é comum precisar de copiar valores e modificar somente a cópia. Com Perl, você pode copiar e mudar de uma vez só. Alguns exemplos:
# ex1
chomp($answer = );
# ex2
($a += $b) *= 2;
# ex3
# strip to basename
($progname = $0) =~ s!^.*/!!;
# ex4
# Make All Words Title-Cased
($capword = $word) =~ s/(\w+)/\u\L$1/g;
# ex5
# /usr/man/man3/foo.1 changes to /usr/man/cat3/foo.1
($catpage = $manpage) =~ s/man(?=\d)/cat/;
# ex6
@bindirs = qw( /usr/bin /bin /usr/local/bin );
for (@libdirs = @bindirs) { s/bin/lib/ }
print "@libdirs\n";
# saída: "/usr/lib /lib /usr/local/lib"
Para pegar o último elemento de uma array, dê preferencia a $array-1 ao invés de $array$#array. Um bom efeito colateral disso é que utilizando a forma sugerida, você consegue pegar o último elemento de uma lista também. Ex:
print( (1, 2, 3, 4)[-1] ); # imprime "4"
Lembre-se que substr, index, rindex e splice também aceitam índices negativos para contar de trás pra frente. Lembre-se que você pode atribuir valores a uma substring ou modificá-la de qualquer outra forma:
substr($s, -10) =~ s/ /./g;
Você só estará começando a pensar em Perl quando pensa seus algoritmos em termos de hashes. Utilize uma hash sempre que você quiser representar um conjunto, uma relação, uma tabela, uma estrutura ou um registro.
Use loops foreach. Seu poder de localização das variáveis locais é bastante útil. Supondo que você tenha duas arrays de números e queira multiplicar todos os seus elementos por pi. Faça dessa maneira:
foreach my $e (@a, @b) { $e *= 3.14159 }
Quando você modifica a variável $e dentro do loop, o elemento da array original é modificado e não uma cópia dele. Lembre-se que você pode copiar e modificar de uma vez só. Portanto, como exemplo, caso você queira criar uma array com os elementos de outra elevados ao quadrado, faça da seguinte maneira:
foreach my $n (@square = @single) { $n **= 2 }
Atente para o fato de que as funções também são estruturas de dados. Então você pode utilizar referências para funções como argumentos para outras funções ou em estruturas de dados. Por exemplo:
%State_Table = (
Initial => \&show_top,
Execute => \&run_query,
Format => \&get_format,
Login => \&resister_login,
Review => \&review_selections,
Sorting => \&get_sorting,
Wizard => \&wizards_only,
);
foreach my $state (sort keys %State_Table) {
my $function = $State_Table{$state};
my $how = ($action == $function)
? SCREEN_DISPLAY
: SCREEN_HIDDEN;
$function->($how);
}
Existe um recurso que Perl incorporou das linguagens de programação funcionais (como Lisp, Haskell, etc) que é bastante útil em alguns casos. Esse recurso são os closures. Você pode clonar funções similares utilizando-os:
no strict 'refs';
for my $color (qw[red yellow orange green blue purple violet]) {
*$color = sub { qq<@_> };
}
Perl não possui uma função de switch como a de C. Porém, você pode ter a mesma funcionalidade utilizando um for. Aprenda fazer um switch utilizando for:
SWITCH: for ($where) {
/In Card Names/ && do { push @flags, '-e'; last; };
/Anywhere/ && do { push @flags, '-h'; last; };
/In Rulings/ && do { last; };
die "unknown value for form variable where: `$where'";
}
Mais recomendações para garantir um código mantível
$idade{"João"} = 23;
$pai{"João"} = "Joaquim";
Quando você deveria fazer isso
$pessoas{"João"}{idade} = 23;
$pessoas{"João"}{pai} = "Joaquim;
m#^/usr/spool/m(ail|queue)#
Antes
if (...) {
X; Y;
} else {
X; Z;
}
Depois
X;
if (...) {
Y;
} else {
Z;
}
Como foi dito várias vezes ao longo desse texto: o mais importante de tudo é utilizar o bom senso. Tente pensar se o código escrito estaria claro caso outra pessoa fosse entendê-lo e tivesse que corrigir algum problema, por exemplo. Seja sincero consigo mesmo e saiba reconhecer os seus vícios que não são "saudáveis" para o código.
----
Nilson Santos Figueiredo Júnior