Técnicas de tratamento de exceções – Parte 1

Técnicas de tratamento de exceções - Parte 1Muito se fala sobre tratamento de exceções no desenvolvimento de software. Estes tratamentos são extremamente úteis para controlar a fluxo de execução do aplicativo quando algum erro ocorre, bem como servir como um bom recurso de rastreabilidade. Porém, em muitos casos, os tratamentos de exceções não são elaborados e utilizados como supostamente deveriam ser. Por esse motivo, o artigo de hoje apresenta algumas premissas relacionadas à exceções no código e algumas dicas para empregar o tratamento.

 

Antes de iniciar o artigo, vale realçar que a palavra reservada except do Delphi que utilizarei nos exemplos é o mesmo que o catch de outras linguagens, como Java e C#, portanto, a ideia é a mesma.

Em primeiro lugar, uma dica importante: quando você iniciar um bloco de tratamento de exceções, escreva todo a estrutura do tratamento antes de continuar a codificação. Essa dica é ainda mais importante para instruções finally, já que nos impede de esquecer de liberar um objeto da memória. Por exemplo, caso seja necessário instanciar um objeto em um método, a estrutura pode ser escrita dessa forma:

var
  Objeto: TClasse;
begin
  Objeto := TClasse.Create;
  try
 
  finally
    FreeAndNil(Objeto);
  end;
end;

Somente depois de escrever essa estrutura que a codificação dentro do try deve ser iniciada. Da mesma forma, se um objeto da classe estiver sendo instanciado no evento OnCreate de um formulário, o código para destruí-lo deve ser imediatamente escrito no evento OnDestroy. Se isso não for feito, haverá Memory Leaks na aplicação, comprometendo o desempenho e aumentando a probabilidade de erros consecutivos, também conhecidos como “efeito cascata”.

 

Em segundo lugar, é preciso entender que o except não deve ser empregado como uma condição If. Alguns desenvolvedores pensam da seguinte forma: “Vou tentar executar o plano A (try), se não der certo, executo o plano B (except)”. Isso não existe! O tratamento de exceções, como o próprio nome diz, deve ser utilizado apenas para exceções, e não para regras de negócio.
Como exemplo, considere o código:

try
  ConsultarPorCodigo;
except
  ConsultarPorDescricao;
end;

O desenvolvedor simplesmente está utilizando o try..except como uma condição. Este é o tipo de código que você olha e faz cara feia, rsrs.
O código acima deve ser ajustado com uma condição If, utilizando, por exemplo, um tipo enumerado, dispensando o except de tratar regras de negócio:

try
  if TipoConsulta = tcCodigo then
    ConsultarPorCodigo
  else if TipoConsulta = tcDescricao then
    ConsultarPorDescricao;
except
  ShowMessage('Erro ao realizar a consulta.');
end;

 

A terceira recomendação é utilizar a propriedade Message da classe Exception para apresentar o erro técnico na tela. Claro, o usuário provavelmente não vai entender a mensagem, mas, quando reportada, será muito útil para ajudar a equipe de suporte, ou até mesmo os desenvolvedores, a identificar a origem do erro. No código abaixo, a mensagem de erro é capturada e exibida na tela:

try
  StrToInt('A');
except
  On E: Exception do
    ShowMessage(
      'Ocorreu um erro.' + #13 +
      'Por favor, entre em contato com o administrador do sistema.' + #13 +
      'Mensagem de erro: ' + E.Message);
end;

A mensagem de erro será: ‘A’ is not a valid integer value. Essa descrição servirá de orientação para identificar quando ou como o erro foi produzido, agilizando o processo de manutenção.
Por outro lado, para evitar o “estouro” de erros técnicos na tela do usuário, outra alternativa é gravar a mensagem de erro em um arquivo de log, na qual eu acho bastante viável. Neste caso, basta substituir a última linha da mensagem de erro por um comando que acesse um arquivo de texto e grave a descrição:

try
  StrToInt('A');
except
  On E: Exception do
  begin
    ShowMessage(
      'Ocorreu um erro.' + #13 +
      'Por favor, entre em contato com o administrador do sistema.');
 
    GravarErroNoArquivoDeLog(E.Message);
  end;
end;

O método GravarErroNoArquivoDeLog, por sua vez, faz a seguinte operação:

procedure GravarErroNoArquivoDeLog(const sMensagem: string);
var
  sCaminhoLogErros: string;
  ArquivoLog: TextFile;
begin
  sCaminhoLogErros := 'C:\LogErros.txt';
  AssignFile(ArquivoLog, sCaminhoLogErros);
 
  // se o arquivo já existir, será aberto para modificação
  // caso contrário, o arquivo será criado
  if FileExists(sCaminhoLogErros) then
    Append(ArquivoLog)
  else
    Rewrite(ArquivoLog);
 
  WriteLn(ArquivoLog, 'Data: ' + DateTimeToStr(Now)); // escreve a data e hora
  WriteLn(ArquivoLog, 'Mensagem: ' + sMensagem); // escreve a mensagem
  WriteLn(ArquivoLog, EmptyStr); // pula uma linha
 
  CloseFile(ArquivoLog);
end;

Legal, não é?
Embora seja uma boa técnica, a segunda parte deste artigo irá apresentar uma forma mais “coordenada” de capturar exceções, criando classes herdadas de Exception.

 

Bom, pessoal, por hoje é só! Espero que as dicas acima sejam produtivas!
Até a próxima semana!


Confira as outras partes deste artigo:

Técnicas de tratamento de exceções – Parte 1
Técnicas de tratamento de exceções – Parte 2


 

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

5 comentários

  1. Excelente artigo, muito bem explicado… Eu já usava try..except da maneira adequada mas não sabia do E: Exception e da propriedade Message, bem útil. Legal;

  2. Muito bom o artigo, esclarece bem o conceito de exceções! Acompanho o blog há algum tempo e tem sido muito útil no meu dia-a-dia. Abraços!

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.