Programação - VISUAL BASIC arquivo - Sefaz-BA

Propaganda
SEFAZ-BA
SGF
DTI
GETEC
Secretaria da Fazenda do Estado da Bahia
Superintendência da Gestão Fazendária
Diretoria de Tecnologia da Informação
Gerência de Tecnologia
BOAS PRÁTICAS DE
PROGRAMAÇÃO
VISUAL BASIC
Versão 01.00.00
Salvador (Ba), Maio de 2002.
Secretaria da Fazenda do Estado da Bahia
29/05/2017
DTI - Diretoria de Tecnologia da Informação
ÍNDICE
1.
OBJETIVOS .............................................................................................................................. 3
2.
UTILIZAÇÃO DE COMPONENTES ..................................................................................... 3
2.1.
2.2.
2.3.
2.4.
INTERFACE ............................................................................................................................... 3
COMPATIBILIDADE BINÁRIA..................................................................................................... 3
EARLY BIND VERSUS LATE BIND .............................................................................................. 4
LIBERAÇÃO DE OBJETOS .......................................................................................................... 5
3.
ACESSO A DADOS .................................................................................................................. 5
4.
TRATAMENTO DE ERROS ................................................................................................... 7
5.
OBSERVAÇÕES GERAIS....................................................................................................... 8
Página 2
841073270
Secretaria da Fazenda do Estado da Bahia
29/05/2017
DTI - Diretoria de Tecnologia da Informação
1. OBJETIVOS
Este documento foi gerado com o intuito de alertar os desenvolvedores de sistemas sobre
algumas práticas que devem ser evitadas durante o processo de codificação e outras que
devem ser adotadas visando não só o incremento da performance dos sistemas, como também
a melhoria da qualidade do código fonte.
Vale ressaltar que algumas recomendações são flexíveis, devendo ser analisadas pela equipe
de CD da GETEC as situações em que elas não se aplicam.
2. UTILIZAÇÃO DE COMPONENTES
2.1.
Interface
Talvez a melhor definição para interface de um componente é que ele é um contrato assinado
entre duas partes, o componente e a aplicação cliente que irá utilizá-lo. A interface de um
componente é representada pela assinatura de todos os métodos públicos. Uma assinatura de
método é determinada pelo nome do método, o tipo de retorno e o nome e tipo dos parâmetros
do método.
Quando ocorre uma alteração na assinatura do método, diz–se que houve quebra de contrato,
ou melhor, quebra de interface. A exclusão de um método também provoca a quebra de
interface, entretanto a inclusão de um novo método, para o Visual Basic, não representa
quebra de interface. Vale salientar que alterações em métodos privados ou propriedades do
componente não interferem em sua interface, portanto não há quebra da mesma.
2.2.
Compatibilidade binária
Todas as classes possuem um identificador numérico denominado CLSID, quando o
componente é instalado e registrado no Windows, o CLSID é gravado no registro do
Windows e é usado para requisitar ao COM a criação de uma instância da classe.
No momento em que um projeto é compilado fazendo referencia a uma DLL, o CLSID das
classes desta DLL são armazenados na aplicação compilada, e quando é executado um New
<ObjectName> , o CLSID armazenado é utilizado para solicitar ao COM que crie o objeto.
Além do CLSID, as classes também possuem um identificador de programa ou PROGID,
diferente do CLSID, que é representado por uma sequência numérica, o PROGID é
representado pelo nome do componente (por exemplo, Excel.Application). Ele também é
armazenado no registro do Windows no momento em que o componente é instalado, e
permite que um componente possa ser criado utilizando a função CreateObject().
Exemplo utilizando o CLSID:
Dim objXL as Excel.Application
Set objXL = New Excel.Application
Exemplo utilizando o PROGID:
Dim objXL as Excel.Application
Set objXL = CreateObject(“Excel.Application”)
A diferença entre a criação de objetos utilizando o New/CLSID e CreatObject/PROGID é que
este último não precisa conhecer o CLSID em tempo de compilação, permitindo que e o
Página 3
841073270
Secretaria da Fazenda do Estado da Bahia
29/05/2017
DTI - Diretoria de Tecnologia da Informação
CLSID possa ser alterado. Será discutido no próximo tópico como isso pode ser feito (Early
bind versus late bind).
O CLSID de um componente é gerado no momento em quem ele é compilado. Entretanto
existe a possibilidade de recompilar um componente e manter o CLSID. No Visual Basic
existem duas opções para manter a compatibilidade de um componente com a versão anterior:
Compatibilidade binária e Compatibilidade de projeto, sendo que só nos interessa a primeira.
Na tela de propriedades do projeto, na aba Componets, encontra-se a caixa Version
Compatibility, contém as opções de compatibilidade.
No Compatibility: deve ser utilizada quando ocorre uma quebra de interface. Toda vez que
um componete é compilado com esta opção, uma nova type library é gerada, incluindo novos
CLSIDs.
Binary Compatibility: Quando um componente é compilado com esta opção, se nenhuma
quebra de interface for detectada, o componente irá manter a type library e os CLSIDs de
suas classes. Com isso, todas as aplicações que utilizam este componente, continuarão
funcionando com a nova versão, já que os CLSIDs foram mantidos.
2.3.
Early bind versus late bind
Quando falamos em utilização de componentes, sempre nos deparamos com a forma de
declarar os objetos. Existem duas formas distintas que se referem ao momento em que a
ligação (binding) é feita com a interface do componente, são elas: Early-bind e Late-bind.
- Exemplo de early bind:
Dim obj As New Project1.Class1
- Exemplo de late bind:
Dim obj As Object
Set obj = CreateObject(“Project1.Class1”)
No early-bind, ou ligação prévia, a ligação com a interface do componente é feita no
momento da declaração da variável. Neste momento o compilador já pode checar se todos os
métodos da interface estão sendo invocados corretamente (nome do método, tipo dos
parâmetros, tipo de retorno, etc.).
Já no late-bind, ou ligação tardia, a ligação é feita com uma interface padrão do VB (Dispatch
interface), com isso, a checagem dos métodos só pode ser feita em tempo de execução. Isto
gera um grande problema já que alguns erros que seriam capturados durante a compilação só
vão ocorrer durante a execução do programa, portanto aplicação deverá ser bem testada.
Os desenvolvedores VB foram habituados a utilizar o early-bind principalmente pelo fato de
que com o early-bind é possível ter o code-insight (aquela funcionalidade que mostra todos os
métodos e atributos de um determinado componente após digitar o “.”), mas o early-bind não
possui somente vantagens. Um grande problema é que, para utilizar o early-bind, devemos
adicionar o componente na lista de referências do projeto VB. Neste momento estamos
vinculando o projeto ao componente, mais especificamente, àquela versão do componente.
Como já foi dito, todo componente possui um identificador único, o CLSID e quando ocorre
uma quebra de interface do componente e o componente é novamente compilado, um novo
CLSID é gerado. No momento em que ele é redistribuído, as aplicações que não forem
recompiladas, apontando para o novo componente, e redistribuídas, não irão funcionar.
Agora, imagine o custo de redistribuição de aplicativos em uma organização de grande porte
se um componente que é utilizado por todas as aplicações tiver quebra de interface?
Vale ressaltar que se a nova interface alterar a assinatura de algum método que é utilizado por
uma aplicação, evidentemente esta aplicação precisa ser alterada para funcionar com o novo
método.
Página 4
841073270
Secretaria da Fazenda do Estado da Bahia
29/05/2017
DTI - Diretoria de Tecnologia da Informação
2.4.
Liberação de objetos
O Visual Basic tem o cuidado de liberar a memória utilizada por uma variável quando o
escopo em que ela foi criada deixa de existir. Entretanto, é melhor atribuir explicitamente as
variáveis que representam objetos com o valor “Nothing” pelas seguintes razões:
 É uma boa técnica de programação;
 É melhor liberar recursos quando você não precisa mais deles do que esperar a saída
do escopo, principalmente quando estes objetos mantêm conexões com o banco
abertas;
 Ainda existem alguns erros no ADO que causam alguns problemas (Ex. perda de
informação no objeto Err) se não for atribuído explicitamente para “Nothing”, antes
de levantar um erro;
 Fechar Recordsets e Connections antes de atribuir “Nothing” fazem com que pool de
conexões trabalhe corretamente.
3. ACESSO A DADOS
O modo como os dados são acessados e tratados no servidor de Banco de Dados, é um ponto
fundamental para a performance das aplicações. A seguir, seguem algumas recomendações
sobre o assunto:

Quando for usar o ADO para acessar dados do SQL Server, utilize o modelo
chamado “firehouse cursor”.
O “firehouse cursor” é a maneira mais eficiente para mover dados do SQL Server para a
aplicação cliente. Essencialmente, este método envia os dados requisitados para buffer de
output no SQL Server. Quando o buffer estiver cheio, o servidor aguarda até o cliente
retirar os dados e envia mais dados para o buffer. Este processo se repete até que todos os
dados requisitados sejam enviados ao cliente. Uma outra vantagem desse método é que
os registros selecionados só são bloqueados (lock) enquanto estiverem sendo movidos
para o buffer.
Quando um ADO Recordset é aberto e é utilizada sua configuração padrão, o método
“firehouse cursor” é usado. Para especificar manualmente, basta setar as seguintes
propriedades do Recordset:
CursorType = adForwadOnly
CursorLocation = adUseServer
LockType = adLockReadOnly
CacheSize = 1
Evidentemente, existem situações em que a utilização de “firehouse cursor” não é a
melhor opção, podemos citar quando o recordset precisa ser varrido inúmeras vezes,
neste caso o tipo de cursor (CursorType) deve ser adStatic.

Procure minimizar o número de acessos ao servidor de banco.
Uma maneira de melhorar a performance das aplicações é tentar diminuir o número de
acessos que ela faz ao Banco de Dados. Muitas vezes, a mesma informação é utilizada
diversas vezes e em lugares distintos da aplicação, nestes casos procure manter esta
informação na aplicação e não ir busca-la, sempre que necessário, no Banco de Dados.
Evite também acessos ao banco de dados dentro de laços. O código a seguir deve ser
evitado:
Página 5
841073270
Secretaria da Fazenda do Estado da Bahia
29/05/2017
DTI - Diretoria de Tecnologia da Informação
For i = 1 to UBound(MyArray)
MySQL = “SELECT name from User Where UserId = ” & _
CSTR(MyArray[i])
SET MyRecordSet = MyConn.Execute(MySQL)
MyData[i] = MyRecordSet(0)
SET MyRecordSet =Nothing
Next
O código abaixo pode ser mais complexo, entretanto tem o mesmo efeito e faz um único
acesso ao banco de dados:
MyWhere = ””
For i = 1 to UBound(MyArray)
If (MyWhere = ””) Then
MyWhere = “Where UserId in (”
End If
MyWhere = MyWhere & CStr(MyArray[I]) & _
IIf(i < UBound(MyArray), “,”, “)”)
Next
MySQL = “SELECT name from User ” & MyWhere
SET MyRecordSet = MyConn.Execute(MySQL)
i = 1
While not MyRecordSet.EOF
MyData[i] = MyRecordSet(0)
i = i + 1
MyRecordSet.MoveNext
Loop
SET MyRecordSet =Nothing

Procure tirar vantagens das views.
Quando a aplicação faz uma consulta (Select) no banco de dados, o SQL Server precisa
compilar e gerar um plano de execução para a consulta. Quando a consulta é muito
complexa pode acabar gerando um overhead muito grande para a aplicação. Nestes casos
uma das soluções é criar uma view. Uma view, por já ter sido compilada, já tem seu plano
de execução gerado melhorando a performance das aplicações. Salientamos que a criação
de views deve ser discutida com a Administração de Dados e com a GETEC, evitando
que sejam criadas indiscriminadamente.

Não utilize o DAO para acessar ao SQL Server.
A performance do DAO, ao acessar o SQL Server, é indiscutivelmente baixa. Utilize o
ADO.

Utilize o OLE DB Provider para criar conexões utilizando o ADO.
Quando for abrir uma conexão com banco, utilizando o ADO, utilize o OLE DB
Provider. Para isso, basta anexar à string de conexão o seguinte parâmetro:
Página 6
841073270
Secretaria da Fazenda do Estado da Bahia
29/05/2017
DTI - Diretoria de Tecnologia da Informação
“provider=sqloledb”. O OLE DB é
garantindo uma melhor performance.

muito mais eficiente que o ODBC Provider,
Procure utilizar “Stored Procedures” para agrupar comandos SQL.
Quando possível, tente agrupar comandos SQL em Stored Procedures. Esta prática, não
só reduz significativamente o tráfego de rede, como também melhora a velocidade de
execução do código SQL já que este código já foi compilado e já possui plano de
execução. Novamente, saliento que esta prática deve ser discutida com a Administração
de Dados e com a GETEC, evitando que sejam criadas stored procedures
indiscriminadamente.

Tente limitar a quantidade de linhas retornadas de uma consulta.
Quando for acessar ao SQL Server, evite fazer consultas que retornem dados que não são
necessários. Utilize cláusulas where que delimitem o subconjunto de linhas que
realmente são importantes para o escopo da aplicação.

Não use o ADO para criar, concluir ou abortar transações.
Procure encapsular as transações dentro de Stored Procedures. Evite utilizar os métodos
do ADO para manipular transações.

Não use o método “MoveFirst” em Recordsets que utilize cursor
“ForwardOnly”
do tipo
Na verdade, quando este método é ativado, ele re-executa a consulta e repopula o
Recordset, causando um overhead sem necessidade na aplicação e no servidor SQL.

Utilize, quando possível, Recordsets desconectados.
Essa é uma boa prática, já que contribui para a redução de carga no servidor SQL.

Utilize a opção “adExecuteNoRecords” quando for executar stored procedures
que não retornem linhas.
Quando uma Stored Procedure é executa utilizando o objeto Command, ele aguarda que
um conjunto de linhas seja retornado pela procedure. Para isso, uma boa quantidade de
código extra é executada, criando uma overhead. Quando uma procedure não retorna
linhas, tem-se a opção de sinalizar ao Command que a procedure não retorna linhas e
evitar que este código extra seja executado, para tal, basta setar a opção
adExecutenoRecords do Command:
Cmd.CommandType = adCmdStoredProc + adExecutenoRecords

Considere utilizar “output parameters” em stored procedures.
Quando for executar uma Stored Procedure que retorne uma única linha, prefira retornar
estes valores via parâmetros de saída da procedure. Esta prática elimina todo o código
extra que o ADO tem que executar para retornar um conjunto de linhas (vide tópico
anterior).
4. TRATAMENTO DE ERROS
Página 7
841073270
Secretaria da Fazenda do Estado da Bahia
29/05/2017
DTI - Diretoria de Tecnologia da Informação
Este tópico será acrescentado futuramente, quando o novo componente de tratamento de erros
estiver disponível.
5. OBSERVAÇÕES GERAIS
Neste tópico veremos algumas práticas, de âmbito geral, que devem ser adotadas:

Não utilizar SelectionFormula no Crystal Reports;
O SelelectionFormula do Crystal apresenta a peculiaridade de trazer todos os registros
da seleção e filtra-los no cliente. Essa prática deve ser abolida, ao invés disso utilize os
critérios de filtro na cláusula Where, ou stored procedure ou recordset desconectado
como fonte de dados para o relatório.

Não colocar Message Box dentro de escopos de transação;
Outra prática, não muito comum, e que geralmente ocorre acidentalmente, e que deve ser
evitada, é a existência de interação com o usuário dentro de escopos de transação. Antes
disso, deve ser concluída a transação, seja por commit ou rollback.
A situação típica ocorre quando algum erro precisa ser exibido ao usuário e esta exibição
é feita antes de finalizar a transação. Nestes casos a transação perdura, mantendo todos
os locks no banco de dados até que o usuário interaja com a aplicação e ela possa
continuar sua seqüência de execução.

Evitar criação de tabela temporária dentro de transações;
A criação de tabelas temporárias bloqueia alguns recursos do TEMPDB do SQL Server.
Se a criação for feita em estado de transação, estes bloqueios irão persistir enquanto
durar a mesma. O problema ocorre quando existem muitas transações que tentam criar
tabelas temporárias, isso pode gerar não só o bloqueio destas transações como também
afetar a performance do Banco, já que o TEMPDB é um banco compartilhado para todo
o servidor SQL.

Tipificar as variáveis declaradas, não use o tipo “Variant” indiscriminadamente;
Quando você declara uma variável, você pode dar-lhe um tipo de dados específico, tal
como String ou Double. Entretanto, você não é obrigado a fazer isto, se você não fizer, o
VB irá declará-lo como do tipo Variant. Para o exemplo, as seguintes declarações são
equivalentes:
DIM MyVar
DIM MyVar as Variant
Um variável do tipo Variant pode armazenar qualquer tipo de dados. Isto pode parecer
útil, mas possui algumas desvantagens. A maior delas é desempenho, em run time o VB
terá de executar uma quantidade extra de código cada vez que você acessa à variável para
determinar que tipo de dados ela está armazenando, e que tipo de dados você está
atribuindo a ela.
Podem existir casos onde será necessária a utilização de variáveis do tipo Variant, nesses
casos declare-a explicitamente. Isto fará com que o código fique mais fácil de interpretar
e eliminar erros no futuro (depuração).

Acrescentar diretiva “Option Explicit” no início dos módulos;
Página 8
841073270
Secretaria da Fazenda do Estado da Bahia
29/05/2017
DTI - Diretoria de Tecnologia da Informação
Além de ser uma boa técnica de programação, forçar a declaração das variáveis acaba
forçando também a tipificação. Se uma variável não é declarada explicitamente, o tipo
que ela assumirá é Variant (vide observação anterior).
Essa prática acaba prevenindo que ocorra o seguinte erro: o programador inicializa uma
variável (não declarada) e, algumas linhas depois, a utiliza novamente, mas escreve o
nome da variável errado. Neste caso, ao compilar o programa, não será apresentado
nenhum erro, entretanto ele poderá não funcionar corretamente. Utilizando a diretiva
“Option Explicit”, este problema é evitado, já que o compilador informará a tentativa de
utilização de variáveis não declaradas.

Procure centralizar a lógica de acesso a dados;
Modularização sempre foi uma boa técnica de programação, e porque não modularizar o
acesso a dados? Esta técnica acaba trazendo muitos benefícios, entre eles (o principal)
facilita a troca dos componentes de acesso a dados. Muito esforço foi gasto para alterar o
código das aplicações quando foi trocado o RDO pelo ADO, se o acesso a dados de todas
aplicações estivessem centralizados, esse esforço seria minimizado. Outro benefício seria
a facilidade de depuração e padronização dos sistemas, já que todos usariam o mesmo
módulo (componente) de acesso a dados.

Elimine o código fonte sem uso;
Não deixe código “morto” em sua aplicação. Todo código comentado e que não será
mais utilizado deve ser eliminado, isto facilita a leitura e entendimento do código pela
equipe de manutenção e evita que erros antigos voltem a acontecer em caso de
eliminação acidental do caractere que delimita o comentário, ocasionando a inclusão de
código indevido na aplicação.

Não instancie ou destrua objetos dentro de um loop;
Outra pratica que deve ser abolida é instanciar ou destruir objetos dentro de laços. O VB
executa uma boa quantidade de código interno para instanciar ou destruir objetos,
portanto fazer isso dentro de laços acaba gerando uma sobrecarga muito grande para a
aplicação.
Página 9
841073270
Download