Dicas para o desenvolvimento de um software – Parte 7

Dicas para o desenvolvimento de um software - Parte 7Opa! Estou de volta com a sétima parte sobre dicas de desenvolvimento de software! Nesse artigo, continuo tratando de alguns pequenos “ajustes” no software, mas que fazem diferença para o usuário. Afinal, é ele quem convive diariamente com o produto do nosso trabalho. Lembre-se de que um bom desenvolvimento certamente garante uma boa satisfação.

 

Submenus infinitos
Imagine que o usuário tenha que acessar 5 submenus para emitir um relatório?

Submenus infinitos

Até ele chegar no último submenu já acabou o expediente, rsrs.
Recomenda-se que um menu tenha, no máximo, 2 submenus. Mais do que isso pode atrapalhar o acesso à tela ou funcionalidade, além de confundir as opções em meio a tantos itens. É comum encontrar também submenus desnecessários, como a seleção da impressora para imprimir um relatório. No meu ponto de vista, essa opção pode ser adequadamente incluída na própria tela de visualização do relatório ou no diálogo de impressão.
Uma alternativa é criar uma barra de ferramentas com botões de acesso para as telas mais utilizadas, evitando que o usuário tenha que percorrer vários submenus para abri-las. Essa alternativa torna-se ainda melhor se a barra de ferramentas for personalizável, ou seja, permitir que o próprio usuário escolha os botões que ficarão disponíveis na barra. Estes atalhos são muito úteis em sistemas que integram dois ou mais departamentos de uma empresa, já que em cada departamento as telas acessadas com mais frequência são diferentes.
Assim como comentei na primeira parte dessa série de artigos, alguns softwares mais modernos apresentam menus do tipo Ribbon, parecidos com as versões mais recentes do Microsoft Office. Esse tipo de menu, por possuir abas e botões de opção, podem facilmente substituir os menus tradicionais de um sistema e apresentar uma navegação mais intuitiva.

 

Formato da data e valores
Essa é clássica! Há muitos softwares por aí que exibem datas no formato americano (mês/dia/ano) e confundem a cabeça do pobre cidadão. Quando o usuário encontra a data “12/15/2013”, além de tentar interpretá-la, normalmente ele toma uma atitude: reclama do sistema ou liga para o suporte.
Há um grande risco quando a data se parece comum, como, por exemplo, o dia “03/06/2013” ser exibido como “06/03/2013”. Embora esteja errada, o usuário pode interpretá-la como o dia 06 de março. Se o sistema trabalhar com históricos, movimentações ou agendamentos, essas datas podem trazer sérios problemas!
Isso também vale para formatos de valores monetários. Procure sempre manter o ponto como separador de milhares e a vírgula como separador decimal. Caso o banco de dados exija que o armazenamento seja no formato americano, cabe ao software realizar a conversão necessária para gravar e exibir corretamente os valores.
No Delphi, pode-se adicionar as linhas abaixo no arquivo DPROJ (ou DPR, nas versões antigas) para garantir essa padronização em qualquer ambiente Windows em que o software for executado:

FormatSettings.ThousandSeparator := '.';
FormatSettings.CurrencyFormat    := 2;
FormatSettings.DecimalSeparator  := ',';
FormatSettings.ShortDateFormat   := 'dd/mm/yyyy';
FormatSettings.DateSeparator     := '/';

 


Mensagens em excesso

Excesso de Mensagens

As mensagens acima são irônicas, mas na realidade alguns sistemas parecem fazer uma entrevista com o usuário: para qualquer operação existe uma tela de confirmação, até para as operações mais rotineiras. Mensagens são necessárias, mas não em excesso. Há operações que são óbvias, e não precisam ter uma mensagem de informação ou confirmação para serem realizadas. É claro que isso não irá afetar o desempenho do software, mas já me deparei com muitos usuários que solicitaram a remoção de algumas mensagens pelo motivo de atrapalhar a usabilidade.
Se a intenção é exibir uma mensagem informativa, considere exibi-la no formulário de forma estática, utilizando uma Label, por exemplo. Mensagens de validação também podem ser substituídas por balões com hints (hint balloons) que, além de não exigir interação do usuário (para pressionar o OK), também são bem modernos.

Só para complementar, já trabalhei com sistemas que não exibem mensagem alguma ao gravar um registro, apenas limpam os campos para a inserção de novos dados. Se for uma tela que permite inserções sucessivas, essa modalidade pode ser bem adequada. Basta orientar o usuário de que, se o sistema “limpar” o conteúdo dos campos ao gravar o registro, significa que foi gravado com sucesso.

 

Gravação de imagens no banco de dados
Nos fóruns de programação é comum encontrar dúvidas relacionadas à gravação de imagens em tabelas no banco de dados. Bom, antes de implementar essa função no seu sistema, lembre-se de que os dados binários das imagens são extensos e podem sobrecarregar o banco de dados. Para compreender melhor, acompanhe a prática: imagine que você tenha um cadastro de clientes que permita associar uma foto do cliente ao registro. Em um dos cadastros, o usuário carrega uma imagem no formato BMP de 2MB. Imagem grande, não é? Pois bem, ao gravá-la no banco de dados, significa que estes 2MB serão inseridos na tabela. Portanto, se o usuário repetir essa operação para os próximos 100 clientes, o banco de dados armazenará 200MB somente com as imagens! Além de pesar o banco de dados, isso pode afetar o tempo de retorno dos dados ao consultar o registro, já que o banco de dados irá selecionar todo o conjunto binário referente à imagem e trazer para a aplicação. Considere também que no caso de uma aplicação cliente/servidor, essa consulta pode ainda congestionar o tráfego na rede.

Oras, basta controlar o tamanho da imagem a ser carregada, como por exemplo, somente imagens JPG com tamanho menor que 50KB!
Certo, essa é uma alternativa, mas mesmo assim ainda tenho três argumentos:
1) Não deixa de ser uma imagem, então ela terá que ser gravada em um campo de um tipo especial na tabela, como o BLOB do Firebird;
2) Você terá que implementar um código específico tanto para a gravação quanto para a leitura da imagem;
3) E o mais impactante: o usuário terá que utilizar um aplicativo externo para redimensionar e converter a imagem para que atenda os requisitos da sua aplicação. Para muitos, isso pode se tornar entediante.

O que você sugere então, infeliz?
Na verdade, eu já me deparei com a necessidade de armazenar imagens no banco de dados e realmente fui infeliz, rsrs. A solução que encontrei (na qual é a solução que muitos desenvolvedores adotam) é copiar a imagem para uma subpasta dentro do diretório da aplicação. Por exemplo, pode-se criar uma pasta chamada “Imagens” e ao carregar uma foto do cliente na aplicação, você simplesmente copia o arquivo para dentro dessa pasta ao invés de gravar a imagem no banco de dados. Para ler a imagem é ainda mais simples: basta carregar o arquivo que está na pasta!

Mas… e se o arquivo já existir nessa pasta?
Simples! Durante a cópia, você pode renomear o arquivo conforme algum dado que identifique o cliente, como o próprio código. Por exemplo, no cadastro do cliente nº 10, o usuário irá carregar o arquivo “Andre.jpg” na aplicação, mas este arquivo será salvo como “00010.jpg” dentro da pasta de imagens. Bom, então já deu pra perceber que pra fazer a leitura será bem fácil, não é? Basta carregar a imagem que tenha o nome igual ao código do cliente selecionado.
No Delphi, é possível copiar o arquivo da seguinte forma:

var
  ImagemOrigem: string;
  ImagemDestino: string;
begin
  // este arquivo pode ser selecionado com um TOpenDialog
  ImagemOrigem := 'C:\Clientes\Fotos\Andre.jpg';
 
  // o nome da imagem de destino será "00010.jpg"
  ImagemDestino := 'C:\Aplicativo\Imagens\' + CodigoCliente + '.jpg';
 
  CopyFile(PChar(ImagemOrigem), PChar(ImagemDestino), False);
end;

 

E por fim, para carregar:

Image1.Picture.LoadFromFile('C:\Aplicativo\Imagens\' + CodigoCliente + '.jpg');

 

Pessoal, caso queiram sugerir ideias ou discutir algo, deixe um comentário ou entre em contato.
Obrigado novamente!


Confira também as outras partes deste artigo:

Dicas para o desenvolvimento de um software – Parte 1
Dicas para o desenvolvimento de um software – Parte 2
Dicas para o desenvolvimento de um software – Parte 3
Dicas para o desenvolvimento de um software – Parte 4
Dicas para o desenvolvimento de um software – Parte 5
Dicas para o desenvolvimento de um software – Parte 6
Dicas para o desenvolvimento de um software – Parte 7
Dicas para o desenvolvimento de um software – Parte 8
Dicas para o desenvolvimento de um software – Parte 9
Dicas para o desenvolvimento de um software – Parte 10
Dicas para o desenvolvimento de um software – Parte 11


 

Compartilhe!
Share on FacebookTweet about this on TwitterShare on LinkedInShare on Google+Pin on PinterestEmail this to someone

9 comentários

  1. Uma boa dica para imagens é criar uma base exclusivamente para elas. Trabalhei muitos anos com o Firebird e muitas vezes precisávamos salvar e utilizar imagens no sistema onde o servidor não permitia compartilhamento (vezes por regras do proprietário, vezes por limitações em configuração de rede). A solução mais sensata foi gravar as imagens em uma base separada para não “pesar” o backup.

  2. Bom dia, acompanho seu site, e gostaria de exemplo do balloonhint na validação de campos, tentei faze-lo mas só funciona quando passo o mouse, tem alguma maneira de ativar os balloonHint quando eu clicar em
    um botão?

  3. Esse cenário não seria funcional para aplicações multicamadas.
    Imagine gravar uma imagem do produto localmente, isso ficaria restrito apenas para o computador onde foi alterado/inserido o registro, se acessado de outro, a imagem não estaria disponível.
    Sei que existe a possibilidade de gravar isso no servidor local, mas isso implicaria em compartilhar uma pasta e dar acesso irrestrito a ela, ou então ter um segundo servidor de aplicação nesse servidor, e de qualquer forma isso seria funcional apenas para uma rede local.

    Se analisarmos um cenário em que a base de dados está online, o tráfego se dará da mesma forma, tanto em arquivo quanto no retorno da instrução sql.

    Quanto à dimensionar a imagem, não precisa o usuário ter acesso a softwares externos, tenho implementado no meu sistema uma rotina onde ele seleciona uma imagem de qualquer tamanho e de qualquer formato, a rotina cria uma miniatura dessa imagem (png), que é convertida para texto, compactada é gravada numa segunda tabela na base de dados e também cria uma segunda imagem com uma tamanho que no meu caso foi determinado de 480×640 (dependendo da necessidade), também em png, onde esse segundo arquivo também é convertido em texto (base64), é compactado e gravado numa segunda base de dados no servidor.

    Sei que implica em mais codificação, mas nada tão excepcional, lembro que na época que criei essa forma, encontrei na internet vários exemplos de como implementar.

    Dessa forma fica tudo centralizado e disponibilizado para qualquer acesso a base de dados.

    Acha que a forma que apresentei pode ser melhorada ou o que você sugere num cenário desses?

    1. Olá, Ivan!

      O seu comentário foi muito bem colocado! Parabéns!
      Isso mesmo, Ivan, a dica sobre as imagens não é direcionada para um sistema multicamadas, tanto é que utilizo caminhos locais para exemplificar a minha sugestão. No caso de aplicações multicamadas, uma análise sobre a viabilidade de gravação de imagens em diretórios ou no banco de dados deve ser realizada visando o desempenho da consulta.

      Só tenho duas objeções quanto ao seu comentário. Primeiramente, você mencionou que o tráfego se dará da mesma forma quando, na verdade, há uma diferença. Quando a imagem está gravada em uma tabela e é necessário realizar uma consulta, uma solicitação deverá ser feita ao engine do banco de dados para trazer os dados binários da imagem. Por outro lado, ao gravá-la em um diretório, apenas a leitura do ID do registro seria necessário para buscar a imagem pelo nome, evitando o processamento no banco de dados. Se a busca de imagens for constante como, por exemplo, em um sistema de catálogo de produtos, talvez essa opção seja mais factível. A respeito do diretório da gravação, bastaria configurá-lo como somente leitura e compartilhá-lo somente com os usuários do sistema.

      A minha segunda objeção é voltada para o tamanho de imagens. Possuo um sistema para representações comerciais e, para esse segmento, a imagem dos produtos devem ser em alta resolução para apresentá-las aos clientes. Uma dimensão de 640×480 não seria suficiente, portanto, imagens com dimensões maiores (e, consequentemente, tamanhos maiores) devem ser consideradas. Agora, imagine que a tela de consulta de produtos permita a visualização das respectivas fotos conforme o usuário navega entre os registros. Se elas estiverem gravadas em tabelas, uma solicitação de busca dos binários e o processamento da conversão seria necessário para cada registro. Temos um impasse! Se o usuário rolar os registros com o scroll do mouse, ele pode acessar 10 registros em poucos segundos. Isso poderia comprometer um pouco do desempenho da aplicação.

      Ivan, de qualquer forma, o seu comentário foi muito bem elaborado e suas dicas agregaram bastante para esse artigo!
      Agradeço fortemente pela visita e pelo tempo dedicado para escrever o comentário!

      Grande abraço!

  4. Como eu disse no comentário anterior, existe uma miniatura da imagem que serve exatamente para que o usuário visualize em uma navegação via registros em uma grid.
    Como também coloquei, o tamanho da imagem pode ser configurável, usei esse tamanho nesse caso em específico.

    Acredito que no caso de um catálogo, o usuário não vai precisar pré-visualizar imagem por imagem no seu tamanho real, pra isso a miniatura da mesma resolveria e somente na montagem do catálogo propriamente dita, após ele escolher todos os produtos que deseja apresentar, é que as imagens precisariam ser acessadas no servidor.

    Quando eu disse que que independe de ser no banco de dados ou em arquivos que o tráfego seria o mesmo, me referi exatamente a isso, o “tráfego” na rede, como você citou no post, e não ao processamento necessário para o mesmo, pois de qualquer forma o tráfego vai existir, e se formos mais a fundo disso, poderíamos ( e deveríamos, no caso de arquivos ) aplicar uma compactação ao mesmo.

    Uma instrução de sql solicitada ao banco para trazer um registro de uma tabela tem o mesmo peso de processamento se esse campo contém um texto com 100 ou com 5000 caracteres, e saliento que me refiro ao peso de processamento necessário pela engine do banco, então se temos um select no registro, essa imagem em miniatura já está no pacote de dados.

    Quando falamos em cenário como o apresentado, onde o banco de dados bem como os arquivos estariam em lados opostos, sendo acessados pela internet, levamos em conta de que quem acessaria o arquivo para devolver ao cliente seria unicamente o servidor de aplicação ( pois não cabe ao cliente conhecer nada da estrutura de onde está o banco de dados nem, se for o caso, os arquivos ), então se for pesarmos realmente, veremos que uma solicitação ao banco de dados ( nesse caso em específico, e com instrução sql bem elaborada ), é mais rápida do que uma busca num diretório para localizar um arquivo entre, digamos 30.000 deles ou o mesmo números de registros na tabela, pois não depende fisicamente de varrer o disco, o que também depende de manter uma indexação no diretório e uma manutenção no SO em relação ao disco ( coisa que não é usual na maioria dos casos ).

    Sem contar que se temos um único arquivo de banco de dados fica mais fácil de fazermos manutenção física no disco, como backups ou outros ( em casos específicos ) do que termos que salvar vários diretórios ( no caso de separarmos as imagens por categorias, por exemplo ).

    Então sintetizando, o tráfego sim existirá em ambos os casos, sendo que no caso de arquivos o desenvolvedor precisa tratar isso de forma mais elaborada, e no caso de banco de dados, além da própria VCL aplicar a sua compactação no pacote de dados ( e isso ela faz sempre ), podem ser utilizados além dos filtros de compactação extras disponibilizados pela própria VCL, suas próprias rotinas de compactação, ficando assim a informação centralizada.

    Mas apenas expressei minhas experiências nesse ambiente, não que eu detenha a verdade absoluta nessa questão.

    Agradeço.

    1. Olá, novamente, Ivan.

      Como também salientei no meu comentário, depende muito de uma prévia análise dessa viabilidade.
      No entanto, discordo quando você alega que um texto de 100 e um de 5000 caracteres têm o mesmo peso de processamento. Isso não é verdade. Se você trouxer 1000 campos com 100 caracteres e depois 1000 campos com 5000 caracteres, observará que a primeira consulta será mais rápida em função de um menor pacote de dados.

      Bom, quando mencionei sobre o tráfego na rede, me referi, na realidade, ao tráfego que ocorre na engine do banco de dados em um ambiente cliente/servidor, ou seja, nos dados oriundos das tabelas que trafegam pela rede. Pensando assim, o tráfego na rede pode ser o mesmo, mas o processamento no banco de dados, não. Mil usuários podem solicitar a leitura de imagens ao mesmo tempo. Se elas estiverem em um diretório, a responsabilidade de encontrá-las será delegada ao SO, ao invés de “sobrecarregar” a engine do banco de dados com a leitura dos binários das 1000 imagens.

      Apenas uma observação que achei relevante: você mencionou que gravar as imagens em diretórios depende posteriormente de uma varredura no disco. Não se esqueça também que para ler os dados de uma tabela, há também um varredura, embora menor, já que o banco de dados não deixa de ser um arquivo físico. Mais uma vez: a única diferença é a engine. Enquanto a primeira alternativa gera um SELECT na tabela, exigindo processamento do banco de dados, a outra faz uma varredura em disco, exigindo processamento do disco. É por isso que volto a dizer que depende de uma análise de viabilidade.

      Outro ponto que deixei de concordar é a questão de que, no caso de arquivos, o desenvolvedor precisa “tratar de forma mais elaborada”. Ao meu ver, os únicos comandos necessários são o CopyFile (para copiar a imagem para o diretório) e o LoadFromFile (para carregá-la).

      Bom, Ivan, agradeço novamente e vejo sentido na sua defesa. Ainda acredito que isso seja uma questão que depende do ambiente, segmento de negócio e infraestrutura do cliente.

      Abraço!

  5. Bom dia, André.

    Já vi aberrações desse sentido, para fazer uma consulta, alterar um orçamento/pedido ou emitir um relatório, o usuário passa por tantas telas, que cansa de esperar. Acho o Ribbon bonito, mas ainda não uso. Tento colocar na tela em foco tudo que é necessário para o trabalho relacionado(consultas, relatórios,…), nada mais.
    Converto todas as datas e valores para o padrão usado no Windows, se mudar nele o programa se ajusta.
    Tento só apresentar mensagens obrigatórias, realmente os clientes reclamam por dar um clique a mais. Sou obrigado a concordar, mas uso parâmetros para isso.
    Implementei o uso de imagens no programa há bastante tempo, exatamente como vc orientou, mas ninguém fez uso. Tudo bem que poderia captar a imagem de uma webcam, ou selecionar de um arquivo, mas não adianta, hoje os clientes querem a base pronta com tudo cadastrado. Às vezes eu forneço, mas como o cliente vai aprender a usar, sem trabalhar nele?
    Bom, estou comentando na medida da leitura. Quando implementei o uso de imagens de produtos, não achei viável sobrecarregar o BD com elas. Uso o código do produto para buscar a imagem, uma miniatura inicialmente. Se quiser detalhes, visualiza em outra tela a imagem melhor. Também uso parâmetros pra utilizar ou não imagens e gravo elas em uma pasta no servidor. Uso o LoadFromFile para carregar, se existe, ou apresento uma defalt local com texto sem imagem.
    Um BD como tenho em alguns clientes estão com 900MB até 1,8GB. Se acrescentar imagens nele, tipo, para 30,000 itens (miniatura 15kb e detalhe 180kb), acredito que seriam 5,8Gb só de imagens, que vão ser paginadas em cada consulta. É muita coisa. Já estou retirando da base principal o CEP (Brasil inteiro ocupa 120MB), NCM e outras complementares para reduzir o tamanho e melhorar a performance.
    Tenho como preferência, carregar o mínimo de dados em uma consulta e os detalhes dela quando necessário. Por exemplo, uma das funções do meu programa é compilar um relatório de todas as compras de um cliente, no período selecionado para cobrança, detalhar os pedidos e os itens coloco como opção na visualização, pra não sobrecarregar.
    Não acho viável colocar imagens em um BD, um exemplo disso podemos ver em sites, onde as imagens estão separadas da base. O site da Americanas tem 80,000 produtos pelo menos, com várias imagens do mesmo produto, que estão armazenadas em pastas.
    Essa é minha opinião, baseada em testes e observação de trabalhos bem sucedidos.
    Os artigos e a discussão de pontos de vista diferentes, acho proveitosa, mas no final cada um aplica o que acha melhor.
    Abraço.

    1. Boa noite, Gerson!
      Concordo com você a respeito das imagens. Claro, como disse nos comentários acima, é uma questão que depende do ambiente, infraestrutura do cliente e também de uma análise de viabilidade, mas, na maioria das vezes, sugiro que sejam gravadas em disco, e não no banco de dados. Imagino que, quando imagens são gravadas em tabelas, o tamanho do banco de dados inevitavelmente fica maior, impactando até mesmo nos processos de backup.

      Você também comentou algo muito interessante, sobre a separação de dados principais e detalhes. Isso colabora, e muito, para o desempenho da aplicação, já que nem sempre os detalhes são relevantes para uma consulta. Considere uma Nota Fiscal, por exemplo. Talvez o usuário deseja apenas conferir a data, cliente, ou o valor da nota, e não os itens. Sendo assim, por que inclui-los na mesma consulta? Talvez seja melhor separá-los em uma tela exclusiva.

      Obrigado, Gerson! Abraço!

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Preencha o campo abaixo * Time limit is exhausted. Please reload CAPTCHA.