[Delphi] Orientações sobre a utilização de eventos de tela

Pensei em vários títulos para o artigo, mas o “melhorzinho” foi esse, rsrs.
Desenvolvedores Delphi, esse artigo é para vocês! O objetivo é compartilhar alguns cuidados com três eventos muito utilizados na programação: OnExit, OnChange e OnAfterScroll. Vocês já empregaram estes eventos para alguma finalidade, certo? Pois bem, confira o artigo e verifique se vocês os utiliza adequadamente.

Esse artigo é uma homenagem ao Luis Olivetti, um grande companheiro de trabalho que possui uma visão bastante crítica com relação à expressividade e desempenho do código-fonte. Ele é um verdadeiro Clean Coder!

Antes de iniciar o artigo, deixo claro que as recomendações abaixo não são uma regra, até pelo fato de que cada programador geralmente utiliza técnicas particulares para implementação, então, talvez, você possa discordar de alguns pontos.
Como forma didática, para cada evento, farei uma breve explicação, apresentarei um cenário e, por fim, uma sugestão, ok?

OnExit

Como sabemos, este evento é disparado quando saímos de um campo. Muitos desenvolvedores usam o OnExit para executar validações, como evitar valores nulos, valores zerados ou datas inválidas. Porém, em algumas ocasiões, o evento “prende” o usuário no campo e pode comprometer a usabilidade da tela. Como? Veja a seguir.

Suponha que uma tela tenha um componente TButton e um componente TEdit, como a imagem abaixo. O botão serve para fechá-la e o campo de texto é usado para digitar um nome qualquer.

Exemplo do evento OnExit

No evento OnExit do TEdit, temos o seguinte código:

Ótimo. Nossa validação está funcional. Se o usuário tentar sair do campo sem digitar o nome, a aplicação exibe uma mensagem e foca novamente o campo para que ele possa preenchê-lo. Agora, faça um teste: deixe o campo em branco e tente clicar no botão para fechar a tela. O que acontece?

Exemplo do evento OnExit

Ops, e agora? O usuário não consegue mais deixar a tela. A única saída é digitar o nome no campo, mas, e se não for obrigatório? E se o usuário quiser apenas cancelar a operação?

Sugestão: Procure implementar as validações em outros eventos, como o OnClose da tela. Se for uma inserção de registro, eu recomendo implementá-la no evento OnBeforePost do DataSet. Logo, todas as validações estarão centralizadas em um único evento, propiciando um ambiente menos “flexível” para o usuário.

OnChange

Já discuti bastante sobre o evento OnChange com outros desenvolvedores. Na maioria das vezes, o evento é utilizado para pesquisar registros em uma Grid conforme o usuário digita o texto. No entanto, lembre-se que essa pesquisa pode solicitar uma requisição ao banco de dados e afetar o desempenho da aplicação. Leia o código:

Já deu para notar o problema, não é? Para cada letra digitada pelo usuário, a aplicação fecha a Query (ou um DataSet), executa uma instrução SQL informando o texto como parâmetro, abre-a novamente e atualiza os registros na Grid. Isso significa que, ao digitar “Andre” (que demora, no máximo, 2 segundos), a aplicação faz 5 requisições ao banco de dados.

Imagine, então, se a aplicação for multiusuário ou cliente/servidor e 100 usuários estiverem na mesma tela pesquisando registros?

Sugestão: Considere adicionar um botão de pesquisa logo à direita do campo de busca e mover o código de consulta para o evento de clique. Dessa forma, a requisição ao banco de dados será realizada somente quando o usuário clicar no botão.

Exemplo do evento OnChange

Aproveitando o ensejo, há outra alternativa. Ao invés de solicitar uma consulta ao banco de dados, faça uso da propriedade Filter do DataSet, que permite filtrar os registros em memória na aplicação cliente. Além de reduzir o tráfego na rede, a pesquisa não irá sobrecarregar o banco de dados com requisições simultâneas.

OnAfterScroll

A advertência sobre esse evento é basicamente a mesma do evento OnChange, mas, mesmo assim, vou apresentar um cenário diferente.

No artigo sobre boas práticas de desenvolvimento de software, mencionei a inconveniência da barra de rolagem horizontal em uma Grid, principalmente quando dados importantes não ficam visíveis para o usuário. Como solução, sugeri a inserção de um painel abaixo da Grid para exibir dados adicionais conforme o usuário navega entre os registros.

Pois bem, a atualização desses dados pode ser feita no evento OnAfterScroll do DataSet, que é disparado quando a posição do cursor do DataSet é alterada. Porém, se estes dados estiverem em tabelas diferentes, cairemos na mesma questão: a aplicação executará uma consulta no banco de dados para cada movimentação do DataSet!

E tem mais: sabemos que com o botão de scroll do mouse, podemos navegar, por exemplo, em 10 registros da Grid em poucos segundos. O que isso significa? Dez requisições ao banco de dados!

Tudo bem, o cenário acima pode ser solucionado se utilizarmos um Inner Join para trazer os dados relacionados de diferentes tabelas e armazenarmos em memória, mas o evento OnAfterScroll também é utilizado para situações diferentes, como a exibição de dados agregados. Por exemplo, o desenvolvedor pode utilizá-lo para consultar a quantidade de compras do cliente selecionado na Grid e exibi-la em algum local da tela.

Para complicar, a instrução SQL contém um COUNT. Neste caso, para cada movimentação na Grid, o banco de dados terá que contar todas as compras do cliente e retornar para a aplicação! Eita!

Sugestão: Assim como recomendando para o evento OnChange, considere a possibilidade de reduzir as requisições ao banco de dados. Crie uma nova tela com as informações adicionais do registro, como a quantidade de compras exemplificada no código acima. Instrua o usuário para que, se desejar visualizar mais informações do registro selecionado na Grid, basta clicar no botão para abrir uma nova tela com os dados.

Informações adicionais em tela separada

 

Essas são as minhas recomendações, pessoal. Espero que sejam úteis.
Lembrem-se sempre de ponderar a utilização dos eventos acima, principalmente para atender requisitos não-funcionais, como a usabilidade e o desempenho da aplicação.

Até a próxima, leitores. Obrigado pela visita!


André Celestino