Atualmente, estou fazendo uma revisão de código e uma das coisas que noto são o número de exceções em que a mensagem de exceção parece reiterar onde ocorreu a exceção. por exemplo
throw new Exception("BulletListControl: CreateChildControls failed.");
Todos os três itens desta mensagem eu posso resolver do resto da exceção. Conheço a classe e o método do rastreamento de pilha e sei que falhou (porque tenho uma exceção).
Isso me fez pensar em qual mensagem eu coloquei em mensagens de exceção. Primeiro, crio uma classe de exceção, se ainda não existir, pelo motivo geral (por exemplo PropertyNotFoundException
- o porquê ) e, quando a jogo, a mensagem indica o que deu errado (por exemplo, "Não é possível encontrar a propriedade 'IDontExist' no nó 1234 "- o que ). O onde está no StackTrace
. O quando pode terminar no log (se aplicável). O como é para o desenvolvedor trabalhar (e corrigir)
Você tem outras dicas para lançar exceções? Especificamente no que diz respeito à criação de novos tipos e à mensagem de exceção.
fonte
Respostas:
Vou direcionar minha resposta mais para o que vem depois de uma exceção: para que serve e como o software deve se comportar, o que seus usuários devem fazer com a exceção? Uma ótima técnica que me deparei no início de minha carreira foi sempre relatar problemas e erros em três partes: contexto, problema e solução. O uso dessa diciplina altera enormemente o tratamento de erros e torna o software muito melhor para os operadores usarem.
Aqui estão alguns exemplos.
Nesse caso, o operador sabe exatamente o que fazer e para qual arquivo deve ser afetado. Eles também sabem que as alterações no pool de conexões não foram necessárias e devem ser repetidas.
Eu escrevo sistemas do lado do servidor e meus operadores geralmente oferecem suporte técnico de primeira linha. Eu escreveria as mensagens de maneira diferente para o software de desktop que tem um público diferente, mas inclui as mesmas informações.
Várias coisas maravilhosas acontecem se alguém usa essa técnica. O desenvolvedor de software geralmente está em melhor posição para saber como resolver os problemas em seu próprio código, portanto, codificar soluções dessa maneira ao escrever o código é de grande benefício para os usuários finais que estão em desvantagem em encontrar soluções, pois geralmente faltam informações sobre o que exatamente o software estava fazendo. Quem já leu uma mensagem de erro do Oracle saberá o que quero dizer.
A segunda coisa maravilhosa que vem à mente é quando você se encontra tentando descrever uma solução em sua exceção e está escrevendo "Marque X e se A então B mais C". Este é um sinal muito claro e óbvio de que sua exceção está sendo verificada no lugar errado. Você programador tem a capacidade de comparar as coisas no código, de modo que as instruções "if" devem ser executadas no código, por que envolver o usuário em algo que pode ser automatizado? Provavelmente, isso é mais profundo no código e alguém fez a coisa preguiçosa e lançou o IOException de vários métodos e detectou possíveis erros de todos eles em um bloco de código de chamada que não pode descrever adequadamente o que deu errado, o que o específicocontexto é e como corrigi-lo. Isso o encoraja a escrever erros de granulação mais refinados, capturá-los e manipulá-los no lugar certo no seu código, para que você possa articular corretamente as etapas que o operador deve executar.
Em uma empresa, tínhamos operadores de primeira linha que conheciam muito bem o software e mantinham seu próprio "caderno de atividades" que aumentava nosso relatório de erros e soluções sugeridas. Para reconhecer isso, o software começou a incluir, em exceções, links wiki para o livro de execução, para que uma explicação básica estivesse disponível, bem como links para discussões e observações mais avançadas pelos operadores ao longo do tempo.
Se você teve a diciplina para tentar essa técnica, fica muito mais óbvio o que você deve nomear suas exceções no código ao criar a sua própria. NonRecoverableConfigurationReadFailedException se torna um pequeno atalho para o que você está prestes a descrever mais detalhadamente para o operador. Eu gosto de ser detalhado e acho que será mais fácil para o próximo desenvolvedor que tocar no meu código interpretar.
fonte
FileNotFound
ouConnectException
você sabe o que fazer))Em esta questão mais recente I fez o ponto que exceções não devem conter uma mensagem a todos. Na minha opinião, o fato de que eles fazem é um enorme equívoco. O que estou propondo é que
Uma exceção deve conter em suas próprias variáveis-membro o máximo de detalhes possível sobre o que exatamente aconteceu; por exemplo, um
IndexOutOfRangeException
deve conter o valor do índice considerado inválido, além dos valores superiores e inferiores válidos no momento em que a exceção foi lançada. Dessa forma, usando a reflexão, é possível criar automaticamente uma mensagem com a seguinte aparência:IndexOutOfRangeException: index = -1; min=0; max=5
e essa, juntamente com o rastreamento da pilha, deve ser todas as informações objetivas necessárias para solucionar o problema. A formatação em uma mensagem bonita como "índice -1 não estava entre 0 e 5" não adiciona nenhum valor.No seu exemplo específico, a
NodePropertyNotFoundException
classe conteria o nome da propriedade que não foi encontrada e uma referência ao nó que não continha a propriedade. Isto é importante: deve não conter o nome do nó; deve conter uma referência ao nó real. No seu caso particular, isso pode não ser necessário, mas é uma questão de princípio e uma maneira preferida de pensar: a principal preocupação ao construir uma exceção é que ela deve ser utilizável por código que possa capturá-la. A usabilidade pelos seres humanos é uma preocupação importante, mas apenas secundária.Isso cuida da situação muito frustrante que você pode ter testemunhado em algum momento de sua carreira, em que você pode ter capturado uma exceção que contém informações vitais sobre o que aconteceu no texto da mensagem, mas não nas variáveis de membro. teve que fazer uma análise de seqüência de caracteres do texto para descobrir o que aconteceu, esperando que o texto da mensagem permaneça o mesmo nas versões futuras da camada subjacente e rezando para que o texto da mensagem não fique em outro idioma quando o programa for executado em outros países.
Obviamente, como o nome da classe da exceção é a mensagem da exceção (e as variáveis de membro da exceção são os detalhes específicos), isso significa que você precisa de muitas e diferentes exceções para transmitir todas as mensagens diferentes, e está bem.
Agora, às vezes, enquanto escrevemos código, encontramos uma situação errônea para a qual queremos codificar rapidamente uma
throw
instrução e continuar escrevendo o código em vez de interromper o que estamos fazendo para criar uma nova classe de exceção para que possamos jogá-lo ali mesmo. Nesses casos, tenho umaGenericException
classe que de fato aceita uma mensagem de string como parâmetro de tempo de construção, mas o construtor dessa classe de exceção é adornado com um grandeFIXME XXX TODO
comentário roxo brilhante, afirmando que toda instanciação dessa classe deve ser substituído por uma instanciação de alguma classe de exceção mais especializada antes do lançamento do sistema de software, preferencialmente antes do código ser confirmado.fonte
node
objeto for protegido por uma cláusula using-descartable (em C #) ou try-with-resources (em Java): o objeto armazenado com a exceção seria descartado / fechado, tornando-o ilegal acessá-lo para obter informações úteis no local em que a exceção é tratada. Suponho que, nesses casos, algum tipo de resumo do objeto deva ser armazenado dentro da exceção, em vez do próprio objeto. Não consigo pensar em uma maneira infalível de lidar genericamente com isso em todos os casos.Como regra geral, uma exceção deve ajudar os desenvolvedores a identificar a causa , fornecendo informações úteis (valores esperados, valor real, possíveis causas / solução, etc.).
Novos tipos de exceção devem ser criados quando nenhum dos tipos internos fizer sentido . Um tipo específico permite que outros desenvolvedores capturem uma exceção específica e a tratem. Se o desenvolvedor souber como lidar com sua exceção, mas o tipo for
Exception
, ele não poderá lidar com isso corretamente.fonte
No .NET, nunca
throw new Exception("...")
(como o autor da pergunta mostrou). A exceção é o tipo de exceção raiz e nunca deve ser lançada diretamente. Em vez disso, lance um dos tipos de exceção .NET derivados ou crie sua própria exceção personalizada que deriva de Exception (ou outro tipo de exceção).Por que não lançar Exception? Porque lançar Exceção não faz nada para descrever sua exceção e força seu código de chamada a escrever um código como o
catch(Exception ex) { ... }
que geralmente não é uma coisa boa! :-).fonte
O que você deseja procurar para "adicionar" à exceção são os elementos de dados que não são inerentes à exceção ou ao rastreamento de pilha. Se isso faz parte da "mensagem" ou precisa ser anexado quando registrado é uma pergunta interessante.
Como você já observou, a exceção proativamente diz o que, o stacktrace provavelmente diz onde, mas o "porquê" pode estar mais envolvido (deveria ser, seria de se esperar) do que apenas olhar em uma linha ou duas e dizer " doh! Claro ". Isso é ainda mais verdadeiro ao registrar erros no código de produção - muitas vezes fui picado por dados ruins que chegaram a um sistema ativo que não existe em nossos sistemas de teste. Uma coisa tão simples quanto saber qual é o ID do registro no banco de dados que está causando (ou contribuindo) para o erro pode economizar uma quantidade significativa de tempo.
Então ... Listado ou, para .NET, adicionado à coleta de dados de exceções registradas (cf @Plip!):
Algumas coisas, é claro, você não saberá que precisa até não as ter em seu relatório / log inicial de erros. Algumas coisas que você não percebe que pode conseguir até achar que precisa delas.
fonte
Quais são exceções para ?
(1) Dizendo ao usuário que algo deu errado?
Esse deve ser o último recurso, porque seu código deve interceder e mostrar a eles algo "melhor" do que uma exceção.
A mensagem "erro" deve indicar clara e sucintamente o que deu errado e o que, se houver, o usuário pode fazer para se recuperar da condição de erro.
ex. "Por favor, não pressione este botão novamente"
(2) Dizendo a um desenvolvedor quando deu errado?
Esse é o tipo de coisa que você faz logon em um arquivo para análise subsequente.
O rastreamento de pilha informará ao desenvolvedor onde o código foi quebrado; a mensagem deve indicar novamente o que deu errado.
(3) Dizendo a um manipulador de exceção (código) que algo deu errado?
O Type of the Exception decidirá qual manipulador de exceções analisará e as propriedades definidas no objeto Exception permitirão que o manipulador lide com ele.
A mensagem da exceção é totalmente irrelevante .
fonte
Não crie novos tipos se puder ajudá-lo. Eles podem causar confusão, complexidade extra e levar a mais código a ser mantido. Eles podem fazer com que seu código precise ser estendido. Projetar uma hierarquia de exceção requer muito pensamento e teste. Não é um pensamento posterior. Geralmente, é melhor usar a hierarquia de exceção de idioma incorporada.
O conteúdo da mensagem de exceção depende do destinatário da mensagem - então você deve se colocar no lugar dessa pessoa.
Um engenheiro de suporte precisará identificar a fonte do erro o mais rápido possível. Inclua uma sequência descritiva curta, além de quaisquer dados que possam ajudar a solucionar o problema. Sempre inclua o rastreamento de pilha - se você puder - essa será a única fonte verdadeira de informações.
A apresentação de erros para usuários gerais do seu sistema depende do tipo de erro: se o usuário puder corrigir o problema, fornecendo entradas diferentes, por exemplo, será necessária uma mensagem descritiva concisa. Se o usuário não conseguir resolver o problema, é melhor declarar que ocorreu um erro e registrar / enviar um erro ao suporte (usando as diretrizes acima).
Além disso - não vomite um grande "HALT ERROR!" ícone. É um erro - não é o fim do mundo.
Então, em resumo: pense nos atores e casos de uso para o seu sistema. Coloque-se no lugar desses usuários. Seja útil. Seja legal. Pense nisso com antecedência no design do sistema. Da perspectiva de seus usuários - esses casos de exceção e como o sistema os trata, são tão importantes quanto os casos normais em seu sistema.
fonte