Dicas do OsmarJr

17 passos para melhorar código VBA


Codificar é fácil. Codificar bem é difícil. Mas o que é um código bem escrito? Geralmente ele deve ter os seguintes atributos:
O código funciona (sem bugs)
O código está documentado
O código é de fácil manutenção
O código executa com rapidez

Autor: Dan Haught

 

Introdução


Alcançar estas metas consome tempo e é difícil. Para ajudar neste processo compilamos uma lista de coisas usadas diariamemente - dicas e técnicas que nos ajudam a escrever código que se aproximam da meta gloriosa do código livre de defeitos e de fácil manutenção.

Estilos e práticas de codificação é um tópico "quente" entre desenvolvedores, chegando quase que a um fervor religioso. O conteúdo deste artigo não deve ser visto como a palavra final - na verdade é uma exposição dos padrões que nós da FMS achamos útil no trabalho de escrever código. O artigo contém conceitos com os quais você pode não concordar, o que é normal;não os siga. De qualquer forma, é importante entender os conceitos envolvidos, assim sendo, vamos mergulhar:


#1: Use Option Explicit
Isto não é uma dica, é uma necessidade para se escrever código VBA. Se você não usar o comando Option Explicit no início de cada módulo de seu projeto, vai estar chamando problemas ao depurar seu aplicativo. Ao explicitar Option Explicit você diz ao VBA que ele deve forçá-lo a declarar todas as variáveis que forem usadas. Isto torna fácil esvitar erros de programação por erro ao digitar nomes de variáveis. Por exemplo, o procedimento abaixo está em um módulo que não contém o comando Option Explicit. Você consegue achar o erro?

Sub ShowBugs ()
Dim intX As Integer
Dim intY As Integer
Dim intZ As Integer

intX = 1
imtY = 2
intZ = 3

Debug.Print intX + intY + intZ
End Sub


Ao executar este código, seria de se esperar que fossem assinalados os valores 1, 2 e 3 às variáveis intX, intY e intZ. e, ao imprimir o resultado da soma teríamos 6. Entretanto este procedimento mostra o valor 4 porque existe um erro de digitação. Em vez de setar intY para 2, o código está setando, na verdade, imtY (com "M") em 2. Como Option Explicit não está declarado, a primeira referência a imtY declara a variável automaticamente. Isto significa que o código compila sem problemas e não se torna um problema até que a rotina seja testada na execução real. Por outro lado se estiver especificado Option Explicit, o código acima iria gerar um erro de compilação, tornando fácil encontrar o erro antes de continuar nos esforços de desenvolvimento.

Para terminar, pense nisso: se o bug no exemplo acima foi fácil de encontrar, o que aconteceria se o mesmo bug estivesse enfiado no meio de centenas de libhas de código? O uso de Option Explicit é a coisa mais importante de todas para um bom código VBA.

À partir do Access 95, Option Explicit pode ser inserido automaticamente em todos os módulos criados. Procure no Help on-line por "Opções" (Options) para ter maiores informações.


#2: Declare Variáveis Corretamente
Existem vários pontos a serem considerados na declaração de variáveis usando a declaração Dim. Primeiro, organize suas declarações Dim para mantê-las sempre juntas dentro de um procedimento, ou na seção de declarações de um módulo. Ao colocar todas as declarações Dim no início de um procedimento, podemos fazer um inventário rápido das variáveis que pertencem a ele.

Também fica mais fácil fazer um controle de qualidade das variáveis verificando a lista toda de uma vez, sem ter que procurar declarações por todo o código.

Em segundo lugar, mantenha cada declaração Dim em uma linha. Veja o código abaixo:

Dim intX as Integer, intY, intZ As integer


Uma olhada rápida ao código pode nos levar a acreditar que estão sendo definidas três variáveis integer. Entretanto, uma olhada mais cuidadosa revela que intY não está sendo declarada como integer (na verdade é uma variant). Se cada uma destas variáveis estivesse declarada em uma linha, ficaria aparente que intY não estava tipada. Ao aplicar esta regra ao seu código, também será evitada as síndrome do Dim simples. Veja o código abaixo:

Dim a, b, c As String


A intenção deste código era declarar tres variáveis como string. Mas o VBA não travalha assim: apenas c é declarada como uma string - as outras são declaradas como variant. O VBA exige que cada variável seja declarada explicitamente. Se não, será criada como variant, o que é menos eficiente.

Saiba também que o VBA permite que se especifique tipos para constantes usando este tipo de sintaxe:

Const strCliente As String = "Cliente"



#3: Evite Variants
Para facilitar a vida de desenvolvedores iniciantes, o VBA oferece o tipo de dados Variant. este tipo de dados é muito flexível pois pode representar quase todo tipo de dado, e o VBA trata todas as conversões de um tipo para outro automaticamente. Mas este poder também é uma fraqueza.

Como o tipo Variant pode conter qualquer tipo de dados, o overhead aumenta - sempre é mais eficiente armazenar os dados usando o tipo de específico do que usar o tipo variant. Além disso, como o VBA faz as conversões automaticamente não temos controle - os resultados podem ser bem diferentes do esperado.


#4: Não Use Caracteres de Declaração de Tipo
A maioria das variantes do Basic da microsoft oferece caracteres de declaração de tipo simples (e arcaicos). Colocando-se um destes caracteres no final do nome da variável ou função, definimos o tipo da variável ou o valor de retorno da função. Por exemplo, a linha de código abaixo:

Dim CName$


Declara uma variável chamada CName como string. O caracter cifrão ($) no final é um caracter de declaração de tipo, e o Access sabe que o sinal de cifrão significa uma variável string. O problema é que caracteres de declaração de tipo é uma coisa antiquada. Eles ainda existem no VBA principalmente para compatibilização com versões anteriores do Basic. Um bom código VBA deve evitar os caracteres de declaração de tipo pois são considerados obsoletos. Além disso, existem caracteres de declaração de tipos para apenas um pequeno subconjunto de tipos de dados que o VBA suporta.

Deve-se também evitar as declarações Def..., como DefInt A-Z. estas construções também são obsoletas e levam a código difícil de depurar e manter.
OsmarJr: Nas primeiras versões de Basic as declarações de variáveis eram feitas apenas com uma letra e o caracter de tipagem. A manutenção era "deliciosa": Dim A$, B$, C%, D% e tínhamos que lembrar exatamente o que queria dizer cada uma...


#5: Use Variáveis em Escopos Pequenos
Todas as variáveis e procedimentos do VBA estão contidos em escopos para ficarem disponíveis a diferentes partes do programa. Por exemplo, uma varável declarada como Pública em um módulo padrão do Access pode ser lida ou modificada por qualquer procedimento em qualquer módulo da base de dados. Este é o escopo mais amplo. Por outro lado, variáveis declaradas como Private dentro de um procedimento ou passadas como parâmetros de procedimentos têm o menor escopo - são vistas apenas pelo procedimento. Entre estes dois extremos, também temos o escopo do módulo. Ao decidir qual o escopo de uma varável, use o menor escopo possível. Se a variável vai ser usada apenas em um procedimento, faça com que seja Private naquele procedimento. Se a variável vai ser usada por diversos procedimentos dentro de um módulo, crie-a como uma variável a nívek de módulo. Apenas em muito raras ocasiões será necessária a criação de variáveis Public.

Código com escopo pequeno é muito mais fácil de manter e depurar. Também são bem mais fáceis de mover ou copiar.


#6: Converta Tipos de Dados Explicitamente
Existem momentos em que é necessário converter dados de um tipo para outro. O VBA faz com que isto seja enganadoramente simples ao fazer automaticamente estas conversões. Mas isto não é necessariamente uma boa coisa. Isto é especialmente verdadeiro ao converter números de integer para double. Além disso, a semântica e o comportamento da conversão automática de dados normalmente está mal documentada ou não documentada, e pode mudar entre versões da linguagem. Por estas razões use as funções de conversão explícitas do VBA no seu código (CInt, CDbl,CStr, etc). Aceitar simplesmente as conversões aitomáticas do VBA pode levar a problemas difíceis de localizar.


#7: Indicar Explicitamente o Tipo do Retorno de Funçoes
Uma das dicas mais importantes para variáveis é declarar explicitamente o seu tipo. A mesma regra se aplica às funções. Quando se cria um procedimento como uma função, está-se dizendo ao VBA que o procedimento retorna um valor. Se não declaramos explicitamente o tipo do retorno com a palavra chave As, o VBA sempre devolve o valor como Variant. Como com variáveis, isto pode levar a conversões estranhas e erros de lógica no seu código.

Isto também faz com que a compilação não consiga identificar a passagem incorreta de valores. Por exemplo, se a função está definida para devolver um resultado do tipo numérico e recebe uma variável do tipo string, ocorrerá um erro de compilação. Mas isto não ocorre se nada for especificado. Seu aplicativo vai travar ao atingir esta linha de código. Toda função deverá estar explicitamente tipada.


#8: Implemente Tratamento de Erro Robusto
Quando ocorre um erro não tratado em seu aplicativo VBA, pode ocorrer um monte de coisas interessantes e indesejadas. Em primeiro lugar será mostrada uma caixa de diálogo, normalmente com os botões Ok, Cancelar e Encerrar. Se o seu usuário conhece o bastante para entender a mensagem apresentada, ele ou ela será apresentado sem a menor cerimônia ao código VBA, na linha onde ocorreu o erro. Tal comportamento dificilmente pode-se dizer que é a marca de um desenvolvimento profissional de um aplicativo. Para piorar as coisas, o código fonte pode estar protegido, fazendo com que mensagens ainda mais estranhas apareçam. Por estas razões o tratamento de erros deve ser parte crucial dos esforços de desenvolvimento de um bom aplicativo.
Cada procedimento, não importa quão pequeno ou insignificante, deve ter algum tipo de tratamento de erro. No nível mais rudimentar, deve haver um comando On Error GoTo que encaminha o VBA a um rótulo dentro do procedimento. Este rótulo deve conter código que, pelo menos, apresenta uma mensagem de erro inteligível.

Tambem deve ser considerada a criação de uma pilha (stack) de procedimentos. Uma pilha é simplesmente uma lista de procedimentos e a ordem em que estão sendo executados. Esta lista é útil quando o aplicativo encontra um erro inesperado. Quando tal erro ocorre, a pilha de procedimentos pode ser examinada para saber quais procedimentos estavam sendo executados e em que ordem. Uma pilha normalmente é implementada como uma matriz (array). Inicialize a matriz ao iniciar o aplicativo e, no início de cada procedimento, coloque o nome do procedimento como última entrada da matriz, empurrando todos os outros elementos uma casa. Imediatamente antes de sair do procedimento, remova seu nome da matriz. Ainda que esta forma exija um esforço extra de codificação, pode ser bastante útil ao tentar depurar um aplicativo instalado em um local remoto.

Para terminar, o Access suporta a função Erl. Esta função retorna o número da linha onde ocorreu o último erro. Podemos usar esta função como parte da rotina de tratamento de erros para indicar exatamente onde o erro ocorreu. Infelizmente esta técnica tem dois problemas: o número físico da linha deve ser digitado no código para que Erl devolva alguma coisa significativa e o Access 97 não suporta Erl corretamente, devolvendo, muitas vezes, resultados errados.


#9: Cuidado com o Fluxo do Programa
O VBA fornece vários caminhos para controlar o fluxo dos programas Por azar, alguns desses caminhos são vestígios dos dias iniciais do BASIC, quando os programas eram listas lineares e não modulares que exigiam a numeração de linhas. Estes caminhos, principalmente GoTo, GoSub e Return tem pouca validade em programas VBA modernos. Normalmente levam a saltos complicados e de lógica de difícil compreensão. Se você deseja escrever código bem estruturado, não deve usar os comandos GoSub/Return, e usar o comando GoTo apenas para o tratamento de erros.

Igualmente importante: nenhum procedimento deve ter mais de um ponto de saida (comandos Exit Sub ou Exit Function). Se um procedimento oferece mais de uma saida, erros de lógica, objetos não fechados e erros não tratados podem ocorrer.
Finalmente: pense na adoção da convenção onde todos os seus procedimentos tem um rótulo de tratamento de erro e um rótulo indicando a saida específicos e padronizados.


#10: Use Constantes
Valores inseridos no código do programa fazem com que ele se torne difíceis de entender e atualizar. Veja o código abaixo:

Dim intCusto As Integer
Dim intQuantidade As Integer
intCusto = intQuantidade * 1.712


O que faz o código? Isto é óbvio: multiplica uma quantidade por 1,712 para obter o custo. Mas o que é 1,712? este tipo de números mágicos não oferecem informações sobre o que está sendo obtido e fazem com que o programa seja difícil de decifrar. Se o número necessitar alteração, pode ser difícil encontrá-lo. É muito melhor declarar uma constante para o número. Considere o código:

If Err.Number = 2048 Then
MsgBox "Ocorreu erro 2048", 16, "Aplicativo ACME"
Else
MsgBox "Não ocorreu erro 2048", 16, "Aplicativo ACMO"
Endif


Neste exemplo, valores inseridos causam dois problemas. O primeiro é causado pelo número 16. O que representa 16? Que tipo de ícone é mostrado pela função MsgBox? Segundo, como "Aplicativo ACME" está inserido duas vezes fica fácil a ocorrência de erros de digitação, como mostrado no segundo comando MsgBox. Para terminar, inserindo literais por todo o programa fica difícil fazer alterações globais no aplicativo todo.

Estes problemas podem ser evitados substituindo valores inseridos por constantes ou variáveis centralizadas ou pela colocação destes valores em uma tabela. No início do aplicativo, todos estes valores de texto e números mágicos são lidos da tabela para a memória, ficando disponíveis para o programa. Ao remover todos os valores inseridos, reduzimos o potencial de erros e tornamos mais fácil a manutenção do programa. Este último ponto pode ser crucial se o aplicativo for internacionalizado. Ao traduzir o aplicativo para outra língua vemos quanto vale ter código que tenha todos os valores e textos armazenados em um local centralizado.


#11: Use Convenções de Nomeação de Variáveis
Ainda que os méritos relativos de diferentes conveções de nomeação de variáveis possam causar discussões acaloradas entre desenvolvedores, o uso de convenções de nomeação noemalmente é aceito como boa prática de programação. Convenções de nomeação acrescentam informações a variáveis, objetos e nomes de procedimentos, geralmente usando algum tipo de prefixo ou sufixo. Este tipo de notação exige que se digite alguns caracteres no início ou fim do nome da variável para indicar seu tipo. Por exemplo, cada variável string seria criada com o prefixo "str", indicando que tais variáveis são do tipo string. Existem diversas convenções de nomeação para o VBA, divididas entre desenvolvedores Visual Basic e Access. Além do código, também são usadas convenções para nomear objetos do Access (por exemplo: tabelas começam com "tbl", consultas com "qry", formulários com "frm", botões de comando com "cmd", etc).

A convenção de nomeação usada não é tão importante quanto seu comprometimento em usá-la consistentemente e constantemente. Convenções de nomeação não funcionam se não forem usadas em todo o código. Assim sendo, escolha uma convenção e use-a sempre.


#12: Escolha Nomes Significativos para Variáveis
Pode parecer óbvio que um desenvolvedor escolha nomes para procedimentos e variáveis que indiquem o propósito de cada objeto. Mas, muitas vezes, no calor da programação, fica muito fácil descambar para nomes de variáveis com uma letra, como x ou y. Para facilitar a leitura esta tentação deve ser evitada. Geralmente variáveis com uma letra para identificação são usadas para variáveis descartáveis, como contadores de laço; fora isso, deve-se evitar nomes que não carreguem alguma informação.

Muita vezes a nomeação de objetos bate de frente com a meta de manter um código compacto - para documentação. desejamos nomes que sejam longos o bastante para descrever adequadamente a variável ou o procedimento, mas não queremos nomes que sejam tão longos que tornem nosso cógigo ilegível ou difícil de digitar. Entre os dois extremos temos uma boa média: usar nomes que sejam longos o suficiente para identificar seu propósito mas não tão longos que tornem o código inadministrável.


#13: Comente
Se você já tentou decifrar códigos escritos por outro programador (ou até seu próprio código), não importando a linguagem, sem dúvida você já sabe o valor do bom comentário. Muitas vezes o propósito de uma parte qualquer do código não fica aparente ao se ler. Comentários auxiliam muito fazendo com que o processo de entender, melhorar e depurar se torne muito mais fácil e rápido.
Existem váris níveis de comentários na codificação VBA. Estes níveis seguem de perto os níveis de escopo:

Comentários do aplicativo (globais)
Comentários a este nível explicam o fluxo de todo o aplicativo e cobrem a interação entre diferentes módulos e componentes. Tipicamente, estes comentários são mantidos fora da base de dados do projeto, mas podem ser incluídos em um módulo global como texto de comentário.

Comentários de Módulos
Comentários a nível de módulo esplicam o propósito e conteúdo de um módulo,. As informações normalmente incluem uma lista de procedimentos contidos no módulo, seu propósito e relacionamentos, e comentários de revisão do módulo como um todo.

Comentários de Procedimentos
Comentários para cada procedimento normalmente incluem uma breve descrição do que o procedimento faz, uma definição de seus parâmetros e valor de retorno, informações sobre revisões, e qualquer outra situação especial que ocorra dentro dele.

Comentários de linha
Comentários na ou acima de uma linha específica explicam o propósito de uma variável ou de uma seqüência particular de operações. Tipicamente, é melhor incluir um comentário de linha imediatamente acima dela. Comentários na mesma linha podem tornar o código difícil de ser visualizado.


#14: Use Identação Padrão
Estruturas de controle devem ser identadas para melhorar a legibilidade e reduzir os erros de programação. Estruturas emparelhadas como If...End If, Do...Loop, For...Next, With...End With, While...Wend, Select Case...End Select, Type...End Type, etc., devem ser identadas para mostrar claramente onde começam e terminam. Além disso, procure manter um padrão de tabulação - não há nada pior que tentar trabalhar em um aplicativo que tenha diversos padrões de tabulação. Por padrão, o Acces usa quatro espaços, mas se seu código tem muitos aninhamentos, dois espaços podem se mostrar melhor. Isto pode ser setado na seção Ferramentas -> Opções -> Módulos do menu do Access.

A identação também pode auxiliar no agrupamento visual de operações relacionadas, não apenas de estruturas de controle. Por exemplo, imagine fazer a identação para agrupar operações AddNew...Update, Set...Close, BeginTrans...CommitTrans. Isto torna mais fácil visualizar quando o código "entra" e "sai" destas operações "emparelhadas".


#15: Evite o Uso de Ifs em uma Única Linha
A colocação de uma condição If e sua ação na mesma linha leva a código difícil de ler e manter.
Em vez de

If fInitialized Then DoCmd.OpenForm "frmOpen"


faça:


If fInitialized Then
DoCmd.OpenForm "frmOpen"
End If



#16: Use Select Case Corretamente
A construção Select Case torna fácil o programa se ramificar em múltiplos valores possíveis para uma variável ou expressão. Duas coisas devem ser vistas quando se usa Select Case. A primeira é uma questão de estilo. Evite colocar uma ação na mesma linha do Case. O código abaixo demonstra isto:

Select Case intType
Case acTable : strType = "Table"
Case acQuery: strType = "Query"
End Select


Estilo ruim: difícil de ler e manter


Select Case intType
Case acTable
strType = "Table"
Case acQuery
strType = "Query"
End Select


Uma forma melhor: fácil leitura e expansão no futuro

No primeiro exemplo, é difícil ver rapidamente qual é a condição e qual é a ação. Além disso, ao voltar ao código para acrescentar algo à cláusula de ação, será necessário formatá-la corretamente mesmo - multiplas ações não podem mais ser usadas em uma única linha! Evite futuros problemas formatando os blocos Select Case já no início.

Outa dica que pode economizar horas de frustração ao tentar depurar um aplicativo complexo. A menos que você tenha definido uma cláusula Case Else no seu bloco Select Case, valores não antecipados não serão usados.

Por exemplo, assuma que seu aplicativo permita ao usuário acrescentar novas categorias de empregados. Seu aplicativo também tem um código VBA que dá um reajuste a cada funcionário baseado no tipo de trabalho. O usuário acrescenta "Programador de Computador" como nova categoria e algumas pessoas são contratadas para o trabalho. O seu bloco Select Case para tratar dos reajustes seria mais ou menos assim:


Select Case intTipoEmpregado
Case EmpTipo_Gerente
intReajuste =10
Case EmpTipo_Vendedor
intReajuste = 5
Case EmpTipo_Motorista
intReajuste = 2
End Select



Adivinha quem não vai receber um reajuste? Se você seguir a prática de sempre incluir uma cláusula Case Else, problemas como o acima se tornam fáceis de trabalhar. Por exemplo, o código acima poderia ser reescrito para pedir que o usuário entre com o valor do reajuste no caso de novos tipos de empregados:

Select Case intTipoEmpregado
Case EmpTipo_Gerente
intReajuste =10
Case EmpTipo_Vendedor
intReajuste = 5
Case EmpTipo_Motorista
intReajuste = 2
Case Else
Beep
intReajuste = InputBox ("Entre com o valor do reajuste.")
End Select



#17: Não use comandos STOP para depurar
À primeira vista, o comando Stop parece ser a melhor opção para a depuração. Você insere a palavra chave Stop no seu código, no lugar desejado, executa-o e o VBA para a execução quando chega àquela linha. O problema é que você pode esquecer de excluir todos os comandos Stop antes de colocar seu código para uso na produção. Não há nada mais embaraçoso que ver seu código abrir em um comando Stop enquanto o usuário está usando seu aplicativo - tudo poque você esqueceu de remover um comando sem importância. Uma alternativa melhor é a utilização de pontos de parada (breakpoints). Eles executam a mesma função do comando Stop mas não são salvos com o código. Ao sair do Access, todos os pontos de parada são descartados, assegurando que seu código não vai parar inesperadamente.

Conclusão
Escrever código robusto, de fácil manutenção e sem bugs é uma tarefa difícil. As liguagens de desenvolvimento são inerentemente dífíceis de usar, fazendo com que seja muito fácil o aparecimento de problemas. Entretanto, com uma visão disciplinada e um bom conjunto de normas, seus esforços serão recompensados por programas que funcionam, e funcionam bem.

Links relacionados:

Home

Contato | Copyright©Osmar José Correia Júnior | 24-Nov-2005 18:23