Existe sistemas sem erro?

O titulo desta seção inicia-se com uma pergunta geralmente feita por programadores que estão iniciando no mundo do desenvolvimento de software e ainda desconhece a complexidade do sistema em que estão atuando.Isso é uma pergunta normal, afinal estão começando e pretendem codificar da melhor forma possível, prever todos os erros de programação que irão ocorrer ou seja entregar um sistema “perfeito”.

Aqui vai uma frase chocante para os iniciantes que pensam dessa forma, “não existe sistema sem erro”, por mais que se tenha o cuidado de tratar as exceções mais comuns para determinada tarefa, o erro sempre vai existir, seja uma variável com problemas de conversão, referências nulas para o objeto, dados no formato inválido,banco de dados indisponível, recuperar dados de um arquivo(indiferente do formato) que não existe e etc..

Mesmo nas empresas que trabalham com processos de TI bem definidos, como uma equipe qualificada de desenvolvedores e testadores de software, ainda sim existem erros que são “mascarados” e despercebidos pela equipe. Geralmente esses tipos de exceções quem encontra é o usuário, uma pessoa que não tem conhecimento técnico do que está sendo executado em “background”, apenas do negócio que o sistema tem que englobar.

Partindo da premissa que erros são comuns e que nunca estaremos livres deles, o desenvolvedor precisa tratar as exceções de forma elegante, permitindo que uma mensagem amigável seja apresentada ao usuário, para que o mesmo tenha condições de saber quem pedir ajuda. Por exemplo: uma mensagem com telefone,email,endereço da empresa que presta o serviço. O grande segredo é evitar a “Yellow screen of death” ( tela amarela da morte), que é um tela padrão de erros em aplicações asp.net, esta tela só é apresentada quando nenhum dos tratamentos de exceções ativos tratam do erro em especifico.

OBSERVAÇÃO: Quando o sistema lança uma exceção e a mesma não é tratada, o asp.net possui uma tela padrão e fornece um detalhamento técnico do problema encontrado, isso para o usuário pode gerar uma sensação de desconforto, afinal ele não vai entender o erro transmitido pela página. Para uma boa qualidade de sistema é interessante que se construa uma tela especializada com mensagens uteis ao usuário final, do contrário o usuário achará a aplicação não estável e de pobre qualidade, pois não se teve nenhum cuidado em mostrar os caminhos alternativos para a resolução do problema .

Apresentando o erro ao usuário.

Página principal

Figura 1: Página principal

De acordo com a figura acima a página irá receber dois parâmetros, cujo o primeiro será dividido pelo segundo e então será disponibilizado o resultado final da divisão. O usuário pode digitar qualquer valor,neste caso foi atribuído o valor 10 ao primeiro fator e 0 ao segundo. O que irá acontecer? É possível dividir um número por 0? Se não for, o que o programador deveria ter previsto para esta aplicação em específico?

OBSERVAÇÃO: Por mais que saibamos que as aplicações nunca serão livre de erros, é nossa tarefa tratar os erros mais comuns para determinado tipo de tarefa.

Tela de erros padrão asp.net

Figura 2: Tela de erros padrão asp.net

Nenhum tratamento de exceção ativo conseguiu identificar este erro, sendo assim o .NET disponibilizou uma tela padrão e de difícil compreensão. Observe alguns detalhes nesta figura como: Detalhes de execução,Arquivo de origem e Rastreamento de pilha. Esta mensagem para o desenvolvedor é super útil, pois a tela relata a exceção lançada, destaca em cor vermelha a linha em que a execução foi parada ainda mostra o rastreamento na pilha por completo. No entanto no que ajuda esta mensagem ao usuário? Ele saberá a quem pedir ajuda? Neste caso é um exemplo simples, pensando em sistemas de grande porte e se fosse uma operação em caso ela não pudesse ser concluída impactasse negativamente em vários funcionários de uma empresa.

OBSERVAÇÃO: O sistema é um produto de confiança para o cliente, por isso o mesmo deve ser projetado e desenvolvido baseado no mesmo.

Mensagem customizada

Figura 3: Mensagem customizada

Agora uma mensagem retornou ao usuário informando que não é possível dividir um número por zero, ou seja o sistema mostrou um caminho alternativo para a resolução de um problema, livrando o usuário final de qualquer informação desnecessária.

OBSERVAÇÃO: As validações de campos em asp.net podem ser feitas a partir dos controles de validação localizados na toolbox. Se preferir pode se validar utilizando linguagens de programação que rodam no lado do cliente como o javascript. O importante é o resultado final, se as devidas validações são contempladas no sistema.

NullReferenceException, a exceção que anda do lado do programador!

É muito comum no desenvolvimento de sistemas nos depararmos com a exceção NullReferenceException, felizmente o nome desta é bastante intuitivo e isso ajuda bastante na resolução do erro. Geralmente é algum objeto que não foi instanciado e em algum momento no código existe uma rotina está tentando acessar e modificar as propriedades ou métodos do objeto.

OBSERVAÇÃO: Breakpoint é uma ferramenta integrada no Visual Studio com a finalidade de “congelar” a aplicação em determinado momento, permitindo que o desenvolvedor consiga navegar na aplicação em tempo de execução. Quando se usa o Breakpoint é possível visualizar o estado dos objetos em determinado momento, é muito útil para checarmos se determinado objeto está nulo.

Exception a mãe de todas as Exceptions!

Até agora exploramos duas exceções bem comuns no dia a dia do desenvolvedor.No entanto existem varias outras que infelizmente não será possível descreve-las, contudo é importante conhecemos classe Exception, pois é dela que as exceções herdam. A classe Exception é localizada no namespace System.Exception e ela possui membros que identificam qualquer tipo de erro da aplicação, porém quando acontece algum problema de execução e o asp.net captura o error, não será criado uma instância do objeto Exception, ao invés disso será criada uma instância de um objeto específico, onde será possível extrair informações complementares sobre o erro.

Membro Descrição
HelpLink Propriedade que permite que seja atribuído uma URL. Esse membro não é utilizando no .NET pelas exceções ja existente, no entanto é possível manuseá-la através de exceções customizadas.
InnerException Quando uma exceção ocorre a partir de uma outra, esta propriedade permite que se tenha uma referência de todas as exceções que aconteceram, até a atual.
Message Representa uma mensagem de descrição do problema.
Source Indica o nome objeto ou a aplicação que foi gerado o erro.
StackTrace Um objeto do tipo string, que exibe a lista de todos os métodos invocados na pilha no momento da execução. É muito útil para rastrealização de erros.
TargetSite É um objeto que recupera a informação do método onde a aplicação gerou um error. Esses dados são recuperados da StackTrace, caso ela seja null, essa propriedade também será.

Tabela 1: Membros do Objeto Exception

Na tabela acima contempla alguns membros da classe Exception, muito úteis para a identificação de problemas e consquentemente na resolução dos mesmos.

Como saber quais exceções criar?

Isso pode ser uma pergunta difícil no começo, afinal de contas como prever todas as situações que um determinada tarefa pode gerar uma exceção?. Felizmente o Visual Studio possui uma maneira bastante simples de indicar quais exceções possam acontecer quando um determinado método for invocado.

Identificando possíveis exceções

Figura 4: Identificando possíveis exceções

A figura demonstra um objeto do tipo SqlConnection, que está tentando utilizar o seu método de abertura de conexão Open, a partir desta chamada passe o mouse por cima do método e será disponibilizada uma caixa de mensagem com uma seção “Exceptions”. O que vem descrita nessa seção são as exceções possíves para quando um método for chamado.

Não é preciso escrever um tratamento de exceções para todas as possíveis, uma boa prática é perceber aquelas que são mais propícias de acontecer e após está análise realizar o tratamento dos erros.

Tratamento de Exceções na prática

Após a identificação das exceções, faz se necessário criar o tratamento necessário para cada uma delas, lembrando que sempre da mais específica a mais genérica.

Tratamento de exceções tem a sua estrutura formada por três blocos de comando, os memos são apresentados a seguir:

  • Try: Neste bloco é inserido todo tipo de código propício a erros, caso nenhum erro seja apresentando, o bloco será executado até o fim.
  • Catch: Quando alguma exceção for lançada e um bloco Catch estiver implementado é a partir dele que será possível extrari informações do objeto de exceção como: Message,StackTrace,HelpLink e outras propriedades.
  • Finally: Como o próprio nome já diz será o último bloco a ser executado, uma observação importante é que este bloco é executado independente se houve um erro no Try ou o Catch tratou o erro. É um ótimo momento para liberar a memória que está sendo consumida pelos objetos, realizar a limpeza dos campos e outras tarefas que sejam relacionadas a liberação de recursos do sistema.

Listagem 1: Try/Catch/Finally


  try
            {
                /*
                 
                 Insira códigos que demonstrem alguma possibilidade de erro.
                 
                 
                 */


            }
            catch (Exception)
            {
                //OPA!!!! O erro foi lançado vamos descobrir o que aconteceu.
                throw; // Reponsável por lançar a exceção
            }

            finally
            {
                /*
                 Nesse caso temos duas respostas:
             
                 * Melhor caso: Poxa conseguir realizar manutenção no banco de dados,
                 * manipulação de arquivos, cálculos complexos... Nenhum erro foi apresentado!!!!
             
                 * Caso Interessante: Poxa meu código não funcionou, verificarei a partir do bloco
                 * Try porque o bloco catch foi executado.
             
                 */

            }

Veja como é simples criarmos uma estrutura de exceção completa, agora é só customizar de acordo com as necessidades.

Listagem 2: Try/Catch/Finally Alinhados


  try
            {
                //Try Pai
                try
                {//Try filho 1
                    try
                    {//Try  filho 2

                    }
                    catch (FileNotFoundException arquivo)
                    {// Catch filho 2

                        throw; 
                    }
                }
                catch (NullReferenceException nulo)
                {
                    //Catch Filho 1
                    throw;
                }
            }
            catch (DivideByZeroException divisor)
            {
                //Catch Pai
                throw;
            }

            finally
            {
                //Finally Pai
            } 

Foi criado vários blocos de exceções encadeados, isso é perfeitamente possível e ilimitado. Também é possível criar um bloco Try com múltiplos blocos Catch.

Neste artigo discutimos o que vem a ser um objeto do tipo Exception, exploramos as suas propriedades e enfatizamos as mais úteis para a identificação de um exceção. Foi apresentado dicas de como tratar os erros de forma mais profissional, dando uma segurança para o usuário e por fim foi desenvolvido dois exemplos com Try/Catch, afim de consolidar a teoria.

Espero que tenham gostado e até a próxima.