9 de abril de 2012

Como escrever códigos mais eficientes


Como em qualquer tipo de empreendimento o difícil está sempre nos detalhes. É como diz o velho ditado: "O Diabo está no detalhe".

Um código pode parecer óptimo no papel, mas se não for implementado com extrema atenção aos detalhes, usando técnicas de programação sólidas e com uma pitada de arte, ele de certo, será um fracasso. Ele provavelmente vai cumprir a lista de tarefas, mas não vai ser atraente, intuitivo ou prático. 

A parte mais importante de se implementar um programa, não é fazer as coisas funcionarem, é não deixa-las estragarem. 
Discute-se muito tratamento de erros, como captura-los, como manuseá-los, etc... Estas coisas se fixam no que fazer depois do leite derramado, ou seja, depois do erro ocorrer. Elas são importantes para o sucesso do seu programa, mas não se comparam a prevenção de erros, esta sim deve ser enfatizada. 

Prevenção de erros deve ser o prato principal do projecto e não uma simples sobremesa. Este post foca algumas técnicas de prevenção de erros, vulgarmente conhecida por validação,  e outros assuntos ligados ao desenvolvimento de software. 

Clareza: Cada função ou procedimento deve ter um, e somente um, propósito claro. Este propósito deve ser comunicado no primeiro comentário. Assim como cada bloco comentado de código numa rotina deve ter só um claro propósito. 

O mesmo se aplica a variáveis. Cada uma deve ter um só propósito. Variáveis multiusos devem ser reduzidas ao mínimo, e claramente identificadas como tal. 

Seguindo esta regra geral a clareza do código vai ser melhorada e este vai ficar mais robusto e fácil de manter. 

Escopo: Sempre considere o escopo. Suas variáveis são locais, ou globais? Suas classes são públicas ou privadas? 

Geralmente o escopo deve ser o mais restrito possível. Na dúvida, comece declarando a variável como local. Se ela for necessária a outras rotinas do formulário mude seu escopo para modular (válida somente no módulo ou formulário em que foi declarada). Por fim se for necessária em outros módulos faça-a Global. Não se esqueça de mudar seu nome para que este reflita sua nova abrangência. 

Mais uma vez, faça todo o possível para manter as variáveis locais. Modulares ou globais só devem ser declaradas se absolutamente necessárias. Passando variáveis como parâmetros de funções ou procedimentos (Subs) e criando propriedades num módulo de classe são alternativas muito mais recicláveis e fáceis de mudar quando necessário. 

Quanto a funções, mantenha-as privadas a não ser que tenham que ser públicas. Não exponha nenhuma função ao usuário sem ter certeza absoluta que todo o código de prevenção de erros está no lugar e funcionando. Não exponha ao usuário funções internas as quais ele não necessita. 

Tente não usar constantes públicas desnecessárias. Embora sejam de grande valia elas fazem com que um módulo seja menos auto suficiente e reciclável. 

Identificadores: Um nome apropriado consiste de um prefixo, normalmente 3 letras, para indicar o tipo, seguido de uma descrição da sua função no todo. Por exemplo, uma nova TextField, ela deve ter o  nome imediatamente mudado para algo como txtNomeDoUsuario. Isto indica que se trata de uma TextField, que recebe o nome do usuário. 

Sempre use os prefixos padrão para que outros que venham a usar o seu código entendam com mais facilidade. Abaixo está uma lista com alguns tipos padrão que uso: 

txt - TextField
lbl - Label
cmb - ComboBox
chk - CheckBox
opt - OptionButton
img - Image
pic - Picture
vsc - Vertical ScrollBar
hsc - Horizontal ScrollBar
tmr - Timer

Arcana: Sempre use o mais simples, directo e legível código possível. As duas linhas abaixo fazem a mesma coisa:

1. bool função Existe(x, lista)
 parm tipoitem x;
          tipolista lista;
{
 int i;
 para i de lista.primeiro ate lista.ultimo
 faca se lista.item[i] = x
         entao retorna verdadeiro;
         senao retorna falso;
}

2. bool função Existe(x, lista)
 parm tipoitem x;
          tipolista lista;
{
 int i;
 para i de lista.primeiro ate lista.ultimo
 retorna lista.item[i]=x
}


A linha 1 é muito mais legível do ponto de vista humano. A 2 é mais complicada e demora mais tempo para a maioria dos programadores entender. É verdade que a linha 2 é mais compacta e avançada, mas clareza deve estar sempre em primeiro lugar.

Comentários: Porquê comentar o meu código? Fui eu que escrevi, daí não preciso de lembrete. De qualquer maneira um código fonte coeso é sempre auto explicativo e evidente. Comentar meu código seria dizer em voz alta que ele não é bom. Além disso, qualquer programador que reclamar que não consegue entender o meu código por falta de comentários é um "Besta Lógica" (Engº. Manuel Meneses) que não sabe de nada. Eu não tenho  e não perco tempo de comenta-lo.
Estas são algumas reacções naturais alguns programadores têm sobre comentários. Comentários são parte essencial de um código coeso e reciclável. O que parece óbvio num dia fica totalmente obscuro em outro. Se o programa é um sucesso, outros programadores vão, eventualmente, continua-lo. Algumas partes do código não serão óbvias a eles, não interessa quanta experiência eles tenham. 

O equilíbrio é o segredo. Alguns programadores não põem comentários, outros põem comentários inúteis ou óbvios, outros ainda põe comentários demais. Estes últimos podem, as vezes, causar mais danos do que aqueles que nem comentam. Este tipo de código é cheio de comentários redundantes, decoração e linhas em branco que não acrescentam nada. 

'===============================
'"""""""""  COMENTÁRIO  """"""""
'===============================

O bloco acima pode ser um "neon" para chamar a atenção a um comentário, mas ele atrapalha. Ele gasta muito espaço na tela e acaba por fazer o código mais difícil de se ler. Comentários devem aparecer para comunicar informação que NÃO é óbvia. Eles não devem interferir com a legibilidade do código, mas devem ser fáceis de achar se o programador os procura. Eles não devem usar mais espaço que o necessário. Como regra geral, olhe para sua tela de código. Se você só vê comentários algo está errado, se você só vê código as chances são que você não está sabendo antecipar adequadamente o que outro programador (ou você mesmo) pode precisar saber no futuro. 

Longo Prazo: Muitos programas tiveram de ser completamente dilacerados ou até reescrito, quando passados a um novo cliente ou vendidos a uma companhia. O porquê? O programador não pensou a longo prazo. 

Quando programamos, a ênfase é basicamente em fazer o programa funcionar. Como se o EXE fosse a única coisa que conta. Assim pensamos em curto prazo. Nós assumimos que enquanto entendermos o código tudo bem. 

É bem mais importante pensar a longo prazo. O EXE não importa muito realmente, mas o código sim. Não deve ser suficiente que entendamos o código, mas que outros também possam entende-lo. Nós entregaremos e eles o pegarão e o modificarão com facilidade. 

Pensar a longo prazo significa fazer comentários que vão ajudar outros, mesmo que voce não precise deles (os comentários). Significa usar convenções padrão para nomes mesmo que prefiramos nossa própria maneira de nomear componentes. Significa declarar tudo explicitamente mesmo quando você conhece os defaults. Significa usar código simples e facilmente legível mesmo sendo capaz dos mais variados truques. Significa escrever nosso código, a pensar, e para os outros. 

Moral da história: A moral da história aqui é que um programa que é legível, mas não funciona direito, é bem melhor do que um que funciona, mas ninguém consegue entendê-lo. O primeiro programa pode ser consertado, mas o segundo, certamente terá que ser reescrito.