Eu sei que VB6 não está mais “na moda”, mas esse assunto rendeu tanta polêmica
nos últimos anos que eu até acho merecido dedicar um artigo a ele. Aliás,
polêmica tem sido meu forte ultimamente... :)
Conceito:
Bom, vamos explicar rapidamente o que é late binding e o que é early binding.
Primeiro vou criar um ActiveX DLL no meu VB6, como na figura abaixo:

O que acontece quando eu compilo e registro essa dll? Se eu procurar no meu registry (meu registry ou minha registry? Alguém sabe o sexo do registry?) por “TesteMateus”, vou encontrar:

Isso significa que, se eu mandar o Windows pesquisar por “TesteMateus.Class1”, ele vai encontrar essa chave, explicando que o Clsid (o identificador da classe, ou class ID) é esse número enorme que aparece na imagem acima. Repare que até aí eu não sei onde está minha DLL, pode estar em qualquer lugar do computador, e para descobrir eu precisarei fazer nova busca, agora pelo Clsid:

Agora sim, encontrei uma chave que me explica onde está a dll que eu quero. Então posso concluir que, se eu não sei o código (o ID) do que eu preciso, eu sou obrigado a fazer uma pesquisa pelo nome para descobrir o código, e só depois fazer uma outra pesquisa para encontrar a dll que eu quero.
Resumidamente e sem muitos detalhes, chamamos de “Late Binding” quando, durante
a execução de um programa, ele precisa ficar descobrindo com base no nome, os
respectivos ID’s da classe e dos seus métodos, enquanto no “Early Binding” eu
já sei o ID ao compilar o programa, então não tenho o trabalho de ficar
pesquisando isso durante a execução.
Esse fato isoladamente fez com que durante anos diversos consultores fizessem a
seguinte recomendação: “Use early binding SEMPRE que possível, afinal, ele é
mais rápido!”
Muita gente acreditou nisso e embarcou no Early Binding. E uma parte
considerável desses se arrependeu.
Não quero aqui ficar criticando essa recomendação nem questionando os motivos
para ela, mas pretendo mostrar “o outro lado da moeda” que pouca gente conhece
e que pode ser de grande ajuda. É sempre importante ressaltar que existe uma
série de boas práticas que ajudam muito a trabalhar com Early Binding, e
contanto que sejam seguidas à risca, a maior parte dos problemas enfrentados
nessa opção tendem a se resolver. (é bom deixar isso bem claro, senão apanho de
alguns amigos que gostam muito do early binding!)
Testando na prática:
Quero simular um “cenário real”, com um cliente EXE chamando um componente ActiveX que instancia o ADO e faz um acesso ao SQL Server. Alguém vai dizer: “Ei! Mas aí muitos fatores são envolvidos! Quero um teste apenas do Early Binding contra o Late Binding!”.
A minha resposta é: Esses testes existem às dúzias, procure na internet. A
minha visão é que sua aplicação não tem apenas esse fator para influenciar a
performance, ela acessa banco de dados, instancia o ADO, chama componentes, faz
cálculos... Então eu quero testar o quão importante para uma aplicação comum é
a escolha do Early Binding, e não apenas o óbvio que todo mundo já sabe.
Bom, feitas as explicações, vamos preencher o método do meu ActiveX, colocando
uma chamada ao ADODB e fazendo um select num SQL Server:

Basicamente o que eu estou fazendo aqui é abrir uma conexão com meu banco de
dados e executar um select qualquer que retorne os dados. Nada de mais...
Agora vou criar um outro projeto, um EXE, que teste essa dll:

Escolhi instanciar 1000 vezes a classe, executar o método e testar, ao final, quantos segundos foram gastos.
Vamos testar:

Bom, nosso Early Binding levou 15 segundos para executar. Agora vamos alterar o código e torná-lo todo late binding. Primeiro, eu retiro as referências, tanto ao ADODB quanto ao meu projeto, e depois faço as seguintes alterações no código:
Na classe:

No executável:

Repare que agora eu não tenho mais referências aos meus tipos, então são todos
variant e chamo as instâncias com “CreateObject”, passando o nome do tipo entre
aspas.
Vamos testar:

Isso mesmo: O que era para ser mais lento executou mais rápido.
Você já deve estar pensando em mil explicações para isso, como cache do banco
de dados ou o fato de estar executando dentro do Visual Basic. Já lhe adianto
que nenhuma dessas duas explicações é válida, vamos provar:
Vou aumentar o loop para 10 mil, agora, e vou executar direto o EXE, e não pelo
Visual Basic. Também vou executar o Late Binding antes do Early Binding, assim
tiramos todas essas dúvidas.
Late Binding:

Early Binding:

É exatamente isso que você está vendo. Faça o teste, se não acreditar.
Vale ressaltar aqui que isso não é regra. Ou seja, dependendo do tipo de
processamento, da quantidade de chamadas a componentes e um monte de outros
fatores, essa diferença pode aumentar, diminuir ou mesmo se reverter, caindo na
regra geral onde o early binding é mais rápido.
Mas deixando por enquanto a questão da performance de lado, vamos a outro
argumento que considero muito mais importante:
Se você já colocou uma dúzia de componentes que se referenciam uns aos outros
por Early Binding, sabe o risco que representa fazer alterações em qualquer um
desses componentes. Qualquer pequena modificação pode quebrar a compatibilidade
binária do componente, fazendo com que todos os outros tenham que ser
recompilados por não encontrarem mais os respectivos ID’s.
É claro que existem ferramentas e recomendações para lidar com isso, como
trabalhar sempre como interfaces (isso é sempre bom), mas a questão é: Você
realmente quer correr o risco de ser obrigado a travar batalhas periódicas com
a compatibilidade binária dos seus componentes, só por causa de uma promessa de
performance que pode não ser real, ou muitas vezes é pouco relevante,
considerando a pequena diferença da performance total da aplicação?
Eu não quero colocar essa responsabilidade nos programadores e administradores
da rede, e duvido que eles também queiram ter que se preocupar com esse tipo de
coisa. No meu ultimo artigo (que gerou opiniões um tanto... fortes) eu falei
sobre simplicidade, estabilidade, suportabilidade... Essas coisas são
importantes para mim, então me chame de maluco, mas eu prefiro um Late Binding
por ser mais “rústico” e portanto mais “resistente” a falhas e erros
operacionais.
E digo mais: O COM acabou virando vilão para muitas pessoas que eu conheço,
única e exclusivamente por causa do Early Binding. Tenho alguns conhecidos que
têm uma visão de instabilidade a respeito do COM por terem passado por
problemas que não teriam ocorrido se usassem o Late Binding (quebra de
compatibilidade binária). Gostaria que esses reconsiderassem...
Minhas conclusões:
1-Nem sempre o Early Binding é mais rápido. Ao usar Late Binding, o COM faz
alguns caches que ajudam a compensar o prejuízo de ter que resolver nomes em
runtime.
2-Nem sempre o fato do Early Binding ser ou não mais rápido que o Late Binding
importa. A performance de uma aplicação sofre influência de diversos fatores,
como banco de dados, otimização do comando SQL, largura de banda, cálculos e
processamento... Isso significa que o tempo para encontrar o componente pelo
nome “Late Binding” acaba tendo uma participação pequena no todo.
3-Nem sempre eu tenho razão :)
4-Usar Late Binding não te impede de usar intellisense. Faça referência,
declare os tipos, programe, compile, teste, e depois remova as referências
tirando a declaração dos tipos.
5-Se seu front end é ASP, 99% de chance de você já estar usando late binding
mesmo, então por que não usá-lo nos seus componentes VB6 também?
6-Meus testes foram feitos num Windows 2003, com componentes e banco de dados
todos rodando localmente. Se eu distribuísse isso numa rede, um fator a mais
entraria no jogo, tornando mais irrelevante ainda a questão da performance.
7-Praticamente tudo o que eu falei acima não se aplica a .Net. É claro que é
possível usar .Net com COM, mas aí é uma questão particular. No .Net puro, o
mais próximo do Late Binding seria usar o Reflection. Aí as regras do jogo
(cenários, diferenças de performance, etc) mudam totalmente. Aliás, essa
discussão nem cabe por lá.
8-Faça logo um upgrade desse seu VB6 para .Net! :)
Aos amigos fãs do Early Binding, sintam-se livres para discordar.