Beruflich Dokumente
Kultur Dokumente
90
Greg Reddick
• Mais legível: para permitir que um leitor compreenda o significado do código com
menos esforço.
• Mais facilmente atualizado: O código pode ser alterado de forma mais confiável para
corrigir erros e aprimorar a sua funcionalidade.
• Mais confiável: O código desempenhará mais proximamente daquilo que é esperado.
• Mais eficiente: O código executa mais rápido ou consume menos recursos.
A versão atual destas Convenções sempre pode ser encontrada no website da Xoc
Software: http://www.xoc.net.
Arrays (Matrizes)
Por convenção, a variável de índice utilizada para acessar cada item de um Array deve
ser sempre um tipo de dados Long. Isto assegura que, se o tamanho da matriz chegar a
ultrapassar 32.767 elementos, teremos a certeza de que será possível acessar todos os
elementos desse Array. Ao acessar itens de um Array, use sempre as funções LBound
e UBound para determinar o início e fim do loop para acesso a cada item. Isso faz com
que tenhamos certeza de que cada item na matriz é acessível. Por exemplo:
Assertions
1
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
código continua. Se, ao contrário, a expressão for avaliada como False, o VBA entra
Modo de Interrupção, tal como se um ponto de interrupção estivesse definido nessa linha.
A linha mostrada no exemplo a seguir funciona como um ponto de interrupção codificado:
Debug.Assert False
Este código assume que o valor de intValue sempre estará entre 1 e 3. No entanto, se
por algum bug, intValue receba o valor de 0 ou 4, por exemplo, este código não
funcionará corretamente. O resultado é que a MsbBox não aparece em todas as
ocorrências de intValue. Debugar o código procurando a razão pela qual a MsgBox
não apareceu pode ser demorado. Em vez disso, o código poderia ser escrito de uma
destas duas maneiras:
…ou…
Em geral, cada bloco Select / End Select deve ter um Case Else funcionando
como uma arapuca para lidar com valores inesperados que, no caso, intValue possa
assumir. Se “temos a certeza” de que o Case Else nunca irá ocorrer, é boa prática de
programação colocar uma declaração Debug.Assert False nessa parte do bloco. Se
2
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
o código for corretamente escrito para lidar com a faixa de valores de 1 a 3, mas 0 e 4
também são permitidos, o código deve ser escrito com um comentário no bloco Case
Else para indicar que isto é esperado, como no exemplo:
Comentários
O comentário só deve ser colocado após o final de uma linha de comando em algumas
situações, tais como:
• No final de uma linha de declaração;
• Nas linhas Case de um Select/End Select, e
• Na linha que termina um bloco específico de código para indicar que esse bloco
terminou ali, naquele ponto como, por exemplo, num bloco If/End If que se estenda
por mais de uma página.
Exemplos de Comentários:
Todo comentário deve ser colocado em uma linha separada, e acima da linha a que ele
se refira, observando o mesmo nível de indentação. Um comentário desse tipo é
3
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
geralmente precedido por uma linha em branco, a menos que seja a primeira linha de um
bloco recuado:
vt = vti.VarType
Se o comentário é a primeira linha de um bloco recuado, não deve ser precedido por uma
linha em branco:
If mboolShowProperties Then
'Show properties for each member
For Each mi In ci.Members
Fica pior do que não possuir nenhum comentário. O comentário fica totalmente
descabido, se simplesmente alterarmos o nome da variável, de vt para vtCur. Ao se
deparar com um comentário que não corresponde ao que há no código, fica a questão:
“quem é que está certo e quem é que está errado?”. Nessa situação, normalmente o
comentário é que estará errado, mas pode levar algum tempo para se chegar a esta
conclusão. Um comentário inadequado é irremediavelmente pior do que não haver
nenhum comentário, como também é inútil um comentário que diga a mesma coisa que a
linha seguinte de código. Em geral, não escreva um comentário em que seja necessária
uma manutenção, porque no mundo real, com certeza, não será dada essa manutenção.
Por outro lado, um comentário que esclarece a intenção da execução do código pode ser
útil. Por exemplo:
Constantes
4
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
boa prática. Constantes globais são permitidas e devem ser utilizadas. Substitua
conjuntos de constantes do tipo de dados Long com o recurso Type tipos usando Enum:
Propriedades padrão
MsgBox txtValue
Isto exibe o valor da propriedate Text do TextBox txtValue. Traz muito mais clareza
ao código quando o escrevemos assim:
MsgBox txtValue.Text
Para ser ainda mais explícito, poderia até mesmo ser escrito assim:
MsgBox Me.txtValue.Text
Isso, no entanto, não acrescenta qualquer valor, pois todas as referências a um controle
em um módulo de um formulário são implicitamente relativas ao próprio formulário (Me). A
razão de se preferir o modo explícito de menção é a de evitar que o programador ter que
5
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
varValue = rst!strFirstName
varValue = rst.Fields.Item("strFirstName").Value
Este código não utiliza nenhuma das propriedades padrão dos objetos envolvidos, porém,
recupera o mesmo valor.
Evite o uso de recursos do Visual Basic ainda existentes somente para fazer face à
compatibilidade com suas versões anteriores. Evite o uso de características não
documentadas. Além disso, evite o uso de funcionalidade antiga, quando há outra, mais
moderna. Alguns exemplos destes tipos de recursos (antigos, e que devem ser evitados):
Desambiguação
bibliotecas>”. Por exemplo, se há referências tanto para o Access quanto para o Excel
nas bibliotecas de objeto de determinado projeto, então esta declaração se torna
ambígua:
Porque tanto a biblioteca de objetos do Access quanto a do Excel possuem uma classe
Application. A classe Application referenciada assumirá o objeto Application
daquela que estiver hospedando o código ou, na falta de um objeto Application, assumirá
o objeto Application daquela referência que primeiro aparecer na listagem. Para evitar
isto, a variável deve ser declarada assim:
A Microsoft refere-se a isso como um ato de "desambiguação". Com esta declaração, não
importa a ordem de listagem das bibliotecas na caixa de diálogo Referências, uma vez
que appObj, neste exemplo, sempre fará referência ao objeto Application do Excel.
Assim, tenha por padrão a declaração completa (nome da biblioteca + “.” + nome da
classe) para fins de desambiguação.
Outros exemplos que precisam ser explicitamente declarados para evitar a ambiguidade:
Excel.Range e Word.Range;
Excel.CommandBars e Word.CommandBars;
Excel.Chart e Word.Chart.
Este exemplo chama o LCase$ e funções Left$ em vez das funções LCase e Left,
porque o resultado será certamente utilizado como uma String. Se o resultado for
utilizado como uma Variant então, neste caso, deve-se chamar as funções padrão
LCase e Left.
A forma $ da função retorna o mesmo valor quando utilizada a versão Variant. Uma
exceção à regra é a função Date. A função Date deve ser sempre usada assim porque a
função Date com a forma $ não se comporta corretamente. Date$ sempre retorna
informações no formato “mm-dd-yyyy” independentemente das Configurações Regionais
do Windows, enquanto que a função Date as utiliza.
Tratamento de erros
7
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
Use os nomes de rótulo como mostrado no exemplo, embora tenham sido arbitrariamente
escolhidos. Perceba que os rótulos ExitProcedure e ErrorHandler são alinhados à
extrema esquerda, tornando-os mais visíveis. Quando do tratamento de determinado erro
previsto, deve-se exibir mensagem para o usuário contendo o número do erro e
respectivo comentário que auxilie na elucidação do procedimento incorreto, como no
exemplo:
8
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
Debug.Print "Case " & CStr(lngNumber) & " '" & strDescription
Debug.Assert False
End Sub
Na maioria das vezes a primeira linha executável de cada procedimento deve ser a linha
On Error GoTo ErrorHandler. A única exceção à regra é quando um procedimento
verifica os valores dos seus argumentos e propositadamente gera um erro de execução
(utilizando o comando Err.Raise) quando eles são inválidos. Neste caso, o código de
verificação vem antes do On Error GoTo linha. Por exemplo:
Sair de um Procedimento
9
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
O nome da variável índice utilizada no laço For / Next deve ser especificado na linha
do comando Next. Isto torna o código mais explícito e legível para fins de análise do laço
que está sendo executado. Por exemplo:
A variável de objeto usada para percorrer a coleção (array ou matriz coluna) deve ser
colocada na linha seguinte em um laço For Each / Next, como no exemplo:
Geralmente você consegue (e deve) evitar o uso de declarações GoTo num código VBA.
Utilize declarações GoTo apenas quando o código alternativo não ficar mais claro do que
como na instrução GoTo. Uma razão comum para usar uma instrução GoTo é a de
abandonar laços aninhados. Por exemplo:
For iastrOuterLoop = 1 To 10
For iastrInnerLoop = 1 To 100
'some other code
If astr(iastrOuterLoop, iastrInnerLoop) = "Done" Then
GoTo ExitNestedLoops
End If
'some other code
Next iastrInnerLoop
Next iastrOuterLoop
ExitNestedLoops:
'More code here
Cabeçalhos
Cada módulo deve começar com um código de cabeçalho que é algo parecido com isto:
'$Header: $
'*****************************************************************
Option Explicit
' Este módulo inclui definições de chamadas API do Windows
10
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
Variáveis de Leitura e/ou gravação permitidas são sinalizadas com [in], [out], e
[inout]. Procedimentos de evento não precisam de um cabeçalho, a menos que o seu
escopo seja alterado para Public. Procedimentos privados (Private Sub ou Private
Function, por exemplo) podem precisar de um cabeçalho, dependendo do seu
contexto. Note que o nome da rotina não é repetido no texto dos comentários, tornando
possível mudar o nome do procedimento, sem a necessidade (ou obrigatoriedade...) de
alterar quaisquer comentários. Preferencialmente não inclua observações de histórico de
alterações ou de versões da rotina. Históricos e afins devem ser mantidos por sistemas
de controle de versão, e não, por programadores, uma vez que raramente são
devidamente atualizados. Os comentários são essencialmente dirigidos à pessoa que
chama o procedimento, e devem incluir apenas as informações suficientes para dizer à
pessoa como chamar o procedimento e usar os possíveis valores retornados. Após a
declaração do comando On Error GoTo, outros comentários podem, se necessário, ser
colocados para descrever algoritmos, bem como outros detalhes de implementações
feitas no código (mas não deixe de rever a seção Comentários).
Um programa freeware muito útil para tanto (e para tantas outras coisas) é o MzTools:
http://www.mztools.com/v3/mztools3.aspx
Indentação
11
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
Indentações (Tab Stops) devem ser padronizadas em quatro espaços. Nenhum dos
membros de uma equipe de programação deve alterar esse padrão, pois tornará mais
difícil a edição de código por outros membros. Todo o código alojado dentro de um bloco
deve ser recuado em um nível de indentação a partir das linhas de limite desse bloco,
observadas algumas exceções contidas em outras partes destas Convenções. A
indentação facilita a visualização de início e fim do bloco. Um bloco é definido como o
trecho de código que esteja entre as seguintes palavras:
• Do/Loop
• Enum/End Enum
• For/Next
• For Each/Next
• Function/Exit Function/End Function
• If/Else/ElseIf/End If
• #If/#Else/#ElseIf/#End If
• Property/Exit Property/End Property
• Sub/Exit Sub/End Sub
• Type/End Type
• With/End With
Por exemplo:
{Alternativa:. A equipe de programação pode definir um outro número como padrão para
espaços}
{Alternativa: Declarações Exit Function, Exit Property e Exit Sub podem ser
recuadas para o mesmo nível das linhas delimitadoras do bloco.}
12
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
Instanciação
Uma variável de objeto não deve ser declarada com a cláusula New na mesma linha onde
é declarada, a menos que haja uma boa razão para fazê-lo. Ao contrário, essa
declaração deve ser dividida em duas linhas, como no exemplo:
Dividi-la em duas linhas faz com que cada referência à variável rst seja executada um
pouco mais rápido do que se tivesse sido declarada na forma desaconselhada. Além
disso, a variável de objeto pode ser testada para ver se contém o valor Nothing.
Exemplo:
Se o código fosse escrito em uma só linha, o código de verificação acima nunca iria exibir
a MsgBox, porque a referência à variável rst contida na instrução If faz com que o
objeto seja previamente instanciado antes que o operador Is consiga avaliá-la. Para
variáveis de objeto Public e Private, ocasionalmente há conveniência em se utilizar a
cláusula New, utilizando-se apenas uma linha para toda a declaração da variável, apesar
da aparente perda de benefício quanto ao desempenho.
ExitProcedure:
On Error Resume Next
Uma linha física de código não deve exceder a 80 caracteres. Se uma linha lógica de
código excede 80 caracteres, deverá ser dividida em duas ou mais linhas físicas usando
o sublinhado de continuação: um espaço seguido de um caractere conhecido por
underline ou underscore (“_”). Todas as linhas físicas seguintes, interligadas pelo
13
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
Quando quebrar uma linha que é uma expressão construída por operadores, quebre a
linha logo antes de um operador de expressão. Por exemplo, quando a expressão é
construída com operadores de concatenação de strings, quebre-a assim:
strValue = "This is a very, very long string that will cause " _
& "the code to wrap. Because of this, you will need to break it."
Nesses casos quebre-a antes do início da próxima palavra. Note que o VBA realiza a
concatenação de Strings em tempo de execução, o que influencia (negativamente) no
desempenho. Em muitos casos, textos que são padrão (não se alteram durante a
execução do código) devem ser atribuídos a variáveis do tipo Const (Constante), ou
armazenados em um campo de banco de dados (MsAccess, por exemplo) ou de células
(no caso do MsExce)l, e recuperados a partir daí. Comentários não são continuados por
quebra de linha e, quando excederem os 80 caracteres, serão continuados mediante a
inserção, na nova linha, de um novo apóstrofo seguido do texto de continuação. Veja a
seção sobre Comentários. Não utilize excessivamente a quebra de linhas dentro de um
bloco de código. Quando isso ocorre é sinal de que deve-se criar uma sub-rotina
contendo a parte excessivamente indentada e, então, executa-la mediante chamada feita
pela rotina principal. Como padrão, faça isto sempre que o bloco de código principal
estiver constituído de mais do que oito níveis de indentação.
Um programa freeware que acrescenta a rolagem vertical do código – o que não existe
na instalação padrão do MsOffice+WinXP – é o VBScroll, do Gazanov (obs.: não funciona
corretamente em dispositivos que utilizam TouchPad, como os Notebooks, gerando
conflitos): http://www.gasanov.net/Donation.asp?VBScroll.zip
Nothing
14
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
dimensionada. Isto tem especial valor quando essa variável de objeto foi declarada com a
palavra reservada Dim. Por exemplo:
Definir a variável de objeto como Nothing não é apenas uma boa prática de
programação. Se o objeto rst em questão possui alguma linha de código em seu evento
Class_Terminate, isto fará com que tal rotina seja executada, podendo possuir
comandos que vão modificar valores, atributos, etc. e, consequentemente, interferir no
resultado futuro do processamento . Além disso, deve-se definir uma variável de objeto
como Nothing sempre antes de sair do procedimento, caso esteja utilizando um
comando Err.Raise. Por exemplo:
No exemplo mostrado, se a variável de objeto rst não for definida como Nothing antes
de ser executado o comando Err.Raise, o evento Class_Terminate do objeto rst
provavelmente irá alterar valores das propriedades do objeto Err de tal sorte que não
mais refletirá o correto número do erro armazenado na variável lngcInvalidValue. O
código contido no evento Class_Terminate será executado antes da execução do
trecho da rotina de erro, resultando num fluxo anormal na execução do código, o que
provoca um bug muito difícil de ser rastreado.
• O VBA não permite que certos tipos de sejam passados por valor, tais como matrizes,
tipos definidos pelo usuário (UDT), e variáveis de objeto.
15
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
• Você deseja que o valor alterado desse parâmetro seja retornado para a rotina
chamadora.
• O parâmetro para passagem ao procedimento de evento é especificado como sendo
ByRef quando o VBA os criou.
• Os argumentos para uma declaração Declare de uma API do Windows devam coincidir
com a definição padronizada para a correta chamada da função da DLL.
Mesmo nos casos em que o argumento deva obrigatoriamente ser passado por
referência a outro procedimento, deve-se sempre prefixar o parâmetro com a cláusula
ByRef, embora este já seja o padrão de consideração do VBA. Isto torna mais explícito
que você quis passar esse parâmetro por referência. Quando duplo-clicamos em
determinado item da lista de eventos de um objeto (por exemplo, um evento MouseMove
de um Userform) o VBA insere, automaticamente, o código padrão de início e fim desse
procedimento de evento na janela de código. Mesmo aí devemos alterar o que foi escrito
- de forma automática pelo VBA – fazendo a adição da(s) cláusula(s) ByVal e/ou ByRef,
se necessário (diferentemente do comportamento do VB6, o VBA já as adiciona) devendo
também alterar os nomes de parâmetro sugeridos automaticamente, aplicando as regras
de Convenções de Nomenclatura adequadas. Por exemplo, o VBA insere estas linhas de
código ao procedimento de evento MouseMove de um Userform (a linha inicial aqui foi
quebrada em duas para perfeito entendimento):
End Sub
End Sub
Uso de Parênteses
Sempre utilize parênteses onde a leitura da linha pode não estar clara. Por exemplo,
suponha uma linha de código escrita assim:
Pode não ficar claro que o operador Is tem maior precedência que o operador Not nesta
linha. Altere a linha, utilizando parênteses, assim:
Isso deixa claro em que ordem de precedência os operadores são avaliados. A regra
geral é a de que, se houver qualquer dúvida quanto a precedência de operador, utilize
parênteses para deixar isto claro.
16
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
Escopo do procedimento
Quando você propositadamente gera um erro de execução dentro de uma rotina, a ser
tratado pelo código que a chamou, o número de erro que você provoca deve ter um
número de erro exclusivo. Para este fim, o VBA define uma constante denominada
vbObjectError que garante que os erros assim criados não gerarão conflitos com
aqueles predefinidos no VBA. No entanto, todas as bibliotecas que podem gerar esse tipo
de erro devem gera-los numa faixa maior do que a convencionada para a faixa de
vbObjectError. Assim, deve-se cuidar para diferenciar a faixa de numeração dos erros
customizados para uma dada biblioteca de código, daqueles gerados por outra biblioteca.
Não há nenhuma maneira de garantir a completa diferenciação, porém, as chances
podem ser otimizadas, iniciando uma faixa de números de erros de forma aleatória, no
intervalo de 512 a 32767 a mais do que a de vbObjectError. Como exemplo, nenhuma
biblioteca que uma Organização produza jamais deverá possuir números de erro em
conflito com outra biblioteca dessa mesma Organização. Por exemplo: A empresa XYZ
Soft pode iniciar a numeração de seus erros na faixa vbObjectError + 4096. Portanto,
a primeira biblioteca produzida pela XYZ Soft gerará erros na faixa de vbObjectError +
4096 e até vbObjectError + 4146 e, seguindo esse raciocínio, a segunda biblioteca o
fará a partir de vbObjectError + 4147 e até vbObjectError + 4196, etc
17
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
Case Else
Call UnexpectedError(Err.Number, _
Err.Description, _
Err.Source, _
Err.HelpFile, Err.HelpContext)
End Select
intValue = lngInput
Se o valor da variável lngInput é ou passa a ser, por exemplo, 90.000, esta linha irá
causar um erro de execução (estouro – Overflow). O fato de que os tipos de dados das
duas variáveis são diferentes é um sinal claro de que poderemos ter problemas. Se,
contudo, tivermos a certeza de que o valor em lngInput só poderá estar na faixa de 1 a
1000, por exemplo, pode ser razoável fazer uma atribuição como esta:
Declaração de variável
18
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
Cada variável deve ser declarada explicitamente, incluindo aí as variáveis do tipo Variant,
que são o padrão utilizado pelo VBA, quando não especificado um tipo para uma
determinada variável. Usando a palavra reservada Option Explicit como primeira
linha do módulo fará com que o VBA imponha essa condição ao programador, durante a
criação do código. O diálogo “Opções”, obtido a partir do menu Ferramentas > Opções
exibe uma série de itens configuráveis, dentre os quais, a possibilidade de inserção
automática dessa palavra reservada tão logo de adicione um módulo em branco. A
imagem mostra as diversas possibilidades de configuração da IDE. Explore-as.
19
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
A grade com 4 X 4 nos oferece maior precisão para aposição dos objetos por sobre o
formulário. A opção de “Notificar antes de perda de estado” assegura que receberemos a
informação de interrupção do código imediatamente antes que aconteça, embora não
possa ser evitado, caso o confirmemos. Desmarcar os itens de “Compilar” faz com que,
sempre que alterado, todo o código seja novamente compilado, assegurando que esteja
“sempre correto”.
Dim varValue
Cada variável deve ser declarada em uma linha. Isto impede que seja criado este bug:
Além disso, ao declarar cada variável em uma linha, você pode usar o atalho do teclado
Ctrl + Y para recortar-e-mover (eliminando o recorte do corpo de código e carregando-o
na Área de Transferência do Windows), independentemente de onde esteja o cursor –
desde que esteja em algum ponto dessa linha - para, em seguida, colá-lo em outro local
no código. No caso do exemplo bugado, como existem múltiplas declarações na mesma
linha, a edição não será tão fácil.
Inicialização de variáveis
20
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
Variáveis sempre devem ser declaradas com o menor nível de escopo, e com tempo de
vida o mais curto possível. Assim deve-se, preferencialmente, declarar variáveis com Dim
dentro do procedimento, e não, na seção de Declarações Gerais do módulo. Se for
necessário maior escopo para essa variável, pode usar a cláusula Static. Se, ainda
assim chegar-se à conclusão de que tal escopo ainda é insuficiente deve-se utilizar a
cláusula Public(*). Só utilize o escopo Public como último recurso. Variáveis Public
declaradas em um módulo padrão são globais e podem ser (inadvertidamente?) alteradas
por qualquer outro trecho de código, em todo o projeto. Isso faz com que a depuração do
código, por meio de observação das mudanças de seu valor se torne algo mais difícil
para se chegar a uma boa conclusão. Variáveis Public devem ser utilizadas apenas
com contexto de sua inicialização. Nenhuma outra parte do código deve alterá-las para
recupera-las em outro trecho do programa, conferindo-as uma característica estática no
restante da execução do programa. Nos casos em que isto se torne necessário, devem-
se utilizar parâmetros de procedimentos ou propriedades de formulários ou de objetos
para passar essa informação. Como regra geral, se houver mais de 20 variáveis Public
no programa, é um sinal de alerta de que a concepção do programa está errada. Criar
constantes Public (Public Const ctestrFixed as string = “1.0”, por
exemplo) é permitido e encorajado. Veja a seção sobre Constantes.
21
Regras Reddick VBA (RVBA) - Convenções de Codificação – v. 0.90
22