Exceções são como são

sábado, 10 de outubro de 2009

O mecanismo de exceções comum em linguagens OO modernas como Java, C# e outras é talvez um dos mais incompreendidos.
Tamanho é o incômodo que traz aos desenvolvedores que em C# nenhuma exceção precisa obrigatoriamente ser tratada e frameworks são escritos para lidar com exceções de forma mais "transparente" possível.
Por transparente entende-se muitas vezes "não tratá-las" ou jogá-las a um limbo onde todas são "tratadas" da mesma forma (que geralmente é o mesmo que não tratar).
Mas se o desenvolvedor já ia ignorá-la de qualquer forma (deixando o bloco de captura em branco ou simplesmente imprimindo o trace na console onde nunca será lido), que diferença faz?

Exceções são como são para que possamos tratá-las onde soubermos como fazê-lo. É por isso que nos é dada a opção de relançar ou tratar.

É comum, entre as pessoas que estão aprendendo sobre este mecanismo a dúvida sobre o que fazer em que situação ou "onde tratar".

Tipicamente em um sistema OO, o usuário realiza uma ação que dispara um método buttonSaveAction() que chama um saveUserData(), depois um writeFormattedContentFile() e assim por diante, até que chegamos naquele método saveFile() que grava o conteúdo que o usuário forneceu a um determinado arquivo que o usuário indicou.

E aí entra o problema: o arquivo não existe no local indicado.

Há então algumas opções:
  1. Tratamento em branco / imprimir um erro na console:
  2. Embora seja muito fácil e muito comum, o usuário nunca saberá o que aconteceu. Claro, um erro na console é bom, se estamos olhando para a console. No caso de uma aplicação com interface gráfica ou rodando em um servidor, este erro passará despercebido. Em uma aplicação de linha de comando os desenvolvedores saberão o que aconteceu, mas o usuário nunca saberá o que o atingiu. Bastante desagradável.
  3. Registrar o ocorrido:
    Registre se precisar corrigi-lo posteriormente, mas o faça em um arquivo ao menos, para que as informações fiquem a salvo. E com informação que você julgue suficiente para corrigir. Infelizmente esta opção não ajuda nosso usuário, mas pelo menos ele não recebeu um golpe certeiro de um desenvolvedor descuidado, como um stack trace. Stack Trace real (4.40Mb, quase 46 MIL linhas - 45750 suprimidas - quem quiser ver tudo, me mande um e-mail):



  4. Avisar o usuário:
    Avisar o usuário parece ser uma boa idéia nesta situação. Se o arquivo não está no local indicado, pode ser que ele tenha informado o caminho errado, por exemplo. Uma forma de resolver o problema seria pedir o caminho novamente, informando o erro e ver se ele corrige. Claro, dependendo da situação, pode ser que sua aplicação resolva criar o arquivo ou salve em um arquivo padrão ou simplesmente não realize o salvamento. De qualquer forma, é sempre bom informar o usuário de que o que ele pediu não foi feito ou foi feito de forma diferente.
    Uma vez tomada a decisão de informar o usuário, que método você espera que fique responsável por isso?
    writeBytes(), o método onde o erro se originou é um método genérico demais. Pode ser usado para qualquer situação em qualquer aplicação. Resolver o que fazer com um erro irá acoplá-lo a uma regra daquela aplicação especificamente, impedindo seu reuso.
    writeFormattedContentFile(), o método que chamou writeBytes() não parece ser responsável por lidar com o usuário, assim como saveUserData(). Ainda que fossem, estando fora da camada de apresentação, como fazê-lo? É uma aplicação desktop em linha de comando, com interface gráfica ou Web? E mesmo que fosse, este era o caso de uso em que o usuário opta por um arquivo existente necessariamente ou é o caso de uso em que o arquivo pode ser criado caso não exista? Em outras palavras, qual era a ação presente no método buttonSaveAction()?
    Como se pode notar, conforme os métodos se aproximam do usuário, se tornam mais específicos da aplicação, com mais informação sobre o contexto de sua utilização. Conforme se afastam, se tornam mais genéricos e mais reutilizáveis.

Então, finalmente respondendo a pergunta:
As informações técnicas sobre o erro devem ser escondidas do usuário comum, mas salvas para que possam ser utilizadas para corrigir. O tratamento pode envolver tentar de outra forma, tentar novamente ou perguntar ao usuário o que fazer, mas de qualquer forma, o usuário deve ser avisado de que seu pedido não foi realizado da forma que se desejava. E sempre que a solução envolver o usuário (avisar do erro e/ou fornecer alternativas), o tratamento deve ser feito no método que tiver informação de contexto suficiente para não só saber quais são as alternativas viáveis, mas como avisar ao usuário.

Não raro, em aplicações com a camada de negócio e apresentação separadas, uma exceção técnica (como ArquivoNaoEncontrado) pode ser capturada na camada de negócio unicamente para que seja lançada outra em seu lugar, determinando apenas o curso de ação (como PerguntarCaminhoArquivo ou AvisarErroArquivoNaoEncontrado). Na camada de apresentação, então, determina-se como avisar ao usuário, de acordo com a ação decidida pelo lançamento da exceção específica na camada de negócio.

Se for bem utilizado, o mecanismo de exceções é seu amigo.

Abraço a todos!

Bookmark and Share

Nenhum comentário:

Postar um comentário

 
addthis_config = { data_ga_tracker: pageTracker }