Como ensinar o tratamento de exceções para novos programadores? [fechadas]

21

Como você ensina o tratamento de exceções para programadores? Todas as outras coisas são ensinadas facilmente - Estruturas de Dados, ASP.NET, WinForms, WPF, WCF - você escolhe, tudo pode ser ensinado facilmente.

Com o tratamento de exceções, ensiná-los try-catch-finalmente é apenas a natureza sintática do tratamento de exceções.

O que deve ser ensinado, no entanto, é - Qual parte do seu código você coloca no bloco try ? O que você faz no bloco catch ?

Deixe-me ilustrar com um exemplo.

Você está trabalhando em um projeto Windows Forms (um pequeno utilitário) e o criou como abaixo com 3 projetos diferentes.

  1. UILayer
  2. BusinessLayer
  3. DataLayer

Se uma exceção (digamos que o carregamento de um XDocument lança uma exceção) é gerada no DataLayer (o UILayer chama BusinessLayer que, por sua vez, chama DataLayer), faça o seguinte

//In DataLayer
try {
    XDocument xd_XmlDocument = XDocument.Load("systems.xml");
} 
catch(Exception ex)
{
    throw ex;
}

que é lançado novamente no BusinessLayer e que é capturado no UILayer onde eu o gravo no arquivo de log?

É assim que você lida com o Exception Handling?

Kanini
fonte
15
Se você foram vai fazer isso, você não quer catch (Exception ex) {throw ex; } - em vez disso, basta pegar {throw; }
Steven Evers
4
Não vamos esquecer finalmente blocos?
Chris
1
Você deve especificar o idioma nas tags. Você está entrando em mais detalhes do que é comum na maioria das implementações de exceções e ignorando coisas fora dos blocos. Em C ++, por exemplo, a parte mais importante do tratamento de exceções é saber como escrever programas seguros para exceções.
David Thornley
Espero que você saiba que é uma má idéia capturar qualquer "Exceção". Você deve ter blocos de captura aninhados para capturar exceções específicas e manipulá-las de acordo (não apenas lançar a exceção).
minusSeven

Respostas:

29

Para explicar o tratamento de exceções, explique o conceito por trás dele: O código em que ocorre um erro freqüentemente não sabe como lidar adequadamente com esse erro. O código que sabe como manipulá-lo corretamente pode ser a função que chamou esse, ou pode estar mais acima na pilha de chamadas.

Ao escrever uma rotina que chama uma rotina que pode gerar uma exceção, se você souber como lidar com esse erro corretamente, coloque a chamada em um bloco try e coloque o código de tratamento de erros no bloco catch. Caso contrário, deixe em paz e deixe que algo acima de você na pilha de chamadas lide com o erro.

Dizer "catch ex, throw ex" não é uma boa maneira de lidar com exceções, pois na verdade não lida com nada. Além disso, dependendo de como o modelo de exceção no seu idioma funciona, isso pode ser realmente prejudicial se limpar as informações de rastreamento de pilha que você poderia ter usado para depurar o problema. Apenas deixe a exceção propagar a pilha de chamadas até atingir uma rotina que saiba como lidar com isso.

Mason Wheeler
fonte
4
+1 para "... desde que ele realmente não lidar com qualquer coisa", pessoas novas para manipulação de exceção tantas vezes pensam meios de manuseamento de captura e não percebem se você não fazer algo para reparar o problema, é não a manipulação de exceção, apenas codifique o inchaço.
Jimmy Hoffa
13

Como a maioria das coisas, as exceções e o tratamento de exceções provavelmente parecerão uma solução em busca de um problema para os novos programadores, até que você mostre por que a solução aparentemente mais simples (códigos de retorno no estilo C e errno) funciona tão mal. Eu começaria motivando o problema e colocando-o em contexto. Mostre como o tratamento de erros pode ser feito usando códigos de retorno ou variáveis ​​globais / estáticas. Em seguida, dê exemplos de por que não funciona bem. Então, e somente então, introduza exceções e explique que elas são uma forma de sinalização fora da banda e que o ponto principal é que o comportamento padrão, se você ignorar uma exceção, é passar o dinheiro da pilha de chamadas para alguém que possa lidar com isso.

Conclusão: mostrar como o tratamento de erros foi feito em C fará com que os alunos entendam para que servem realmente as exceções e por que capturar exceções que você realmente não consegue lidar é basicamente simular a maneira como as coisas foram feitas na Idade das Trevas.

dsimcha
fonte
2
+1 para a prática de ensino de liderá-los nos códigos de retorno e números de erro tradicionais do estilo C e mostrar a eles que funciona mal e, portanto, ensiná-los como funcionará é brilhante!
Kanini
3
@ Kanini: Em geral, acho que a maioria das construções de nível relativamente novo / alto parece uma solução em busca de problemas e é fácil de usar de maneira errada se você não entende o problema que eles deveriam resolver e por que foram inventados.
dsimcha
Eu concordo que mostrar como isso seria feito sem exceções é bom, mas então vem o ônus de explicar quando usar exceções e quando usar outras técnicas (porque nem todas as situações são excepcionais)
Matthieu M.
@ Matthieu: Certo. Mas se você entende quais problemas históricos as exceções pretendem resolver, em vez de aprender sobre eles no vácuo, torna-se mais óbvio que é tolice usá-los para situações não excepcionais.
dsimcha
certo, é por isso que você recebeu meu +1. Eu apenas senti sua resposta poderia ser interpretado como "nunca use um outro mecanismo" :)
Matthieu M.
5

Eu começaria com as diretrizes de design para exceções, que são curtas e inclui DO, DO NOT e EVOID. Também fornece os motivos.

No seu caso de exemplo, a seção revelvent seria Wrapping Exceptions

E esperaria que fosse escrito dessa maneira. Observe que ele captura uma exceção específica e tenta adicionar informações para que uma mensagem mais significativa seja propagada. Observe também que a exceção interna ainda é mantida para fins de registro

//In DataLayer

try
{
XDocument xd_XmlDocument = XDocument.Load("systems.xml");
}
catch(FileNotFoundException ex)
{
        throw new TransactionFileMissingException(
                     "Cannot Access System Information",ex);
}

ATUALIZAÇÃO Kanini pergunta se é correto ter esse bloco de exceção na camada de dados ou se a verificação do arquivo está disponível para a camada de negócios.

Bem, primeiro eu gostaria de salientar que a lógica para Wrapping Exceptions é esta

Considere agrupar exceções específicas lançadas de uma camada inferior em uma exceção mais apropriada, se a exceção da camada inferior não fizer sentido no contexto da operação da camada superior.

Portanto, se você acha que uma camada superior deve saber sobre o arquivo, sua camada de dados deve ficar assim

//In DataLayer

XDocument xd_XmlDocument = XDocument.Load("systems.xml");

Não tente não pegar.

Pessoalmente, sinto que, a menos que sua camada de dados possa fazer algo útil, como usar um systems.xml padrão que é um recurso de montagem, não fazer nada ou ocultar a exceção é uma boa aposta, já que o log mostrará qual método e qual arquivo foi o problema. ( throw exnesse caso, ou o preferido throwtambém, mas não agrega valor). Isso significa que, uma vez identificado, você poderá resolver o problema rapidamente.

Como exemplo, este exemplo em particular também tem o seguinte problema em que XDocument.Load pode lançar quatro exceções

  • ArgumentNullException
  • Exceção de segurança
  • FileNotFoundException
  • UriFormatException

Não podemos garantir com segurança que o código a seguir não será lançado e FileNotFoundException, simplesmente porque ele pode estar lá quando verificamos a existência e desaparecemos quando carregamos. Ter isso disponível para a camada de negócios não ajudaria.

 if (File.Exists("systems.xml")) 
     XDocument.Load("systems.xml");

SecurityException é ainda pior, porque, entre outros motivos para isso ser lançado, se outro processo pegar um bloqueio de arquivo exclusivo, você não receberá o erro até tentar abri-lo para leitura, porque não existe o método File.CanIOpenThis (). E se esse método existir, você ainda terá o mesmo problema que o File.Exists

Conrad Frix
fonte
Correção: Obrigado! Mas é correto ter esse bloco de exceção na camada de dados? A coisa toda deve verificar se o arquivo está disponível ou não na camada de negócios? Caso contrário, concordo com o seu método de escrever o código.
Kanini 28/10/10
Fix: Na minha língua nativa, Kanini significa um computador enquanto Kani significa uma fruta ;-)
Kanini
Posso dizer que você não está muito chateado com o meu erro, mas lamento muito e o corrigi.
Conrad Frix
1
Correção: chateado? De modo nenhum. Em grande parte divertido. Meu irmão não parou de rir desde que eu disse isso a ele, principalmente porque, eu não se assemelham a uma fruta de qualquer maneira exceto talvez para o estranho em forma de ...
Kanini
4

Vamos fazer uma dramatização. (este não é um post de piada)

Você deve fazer um workshop em que atua na cadeia de chamadas. Cada pessoa é um objeto. Você precisará de alguns iniciantes e algumas pessoas que entendem o "jogo" ajudam.

Use um problema muito simples, como E / S de arquivo. gui-> modelo-> arquivo_io

A pessoa que é o leitor de arquivos precisa informar o próximo ....

Primeiro faça isso com códigos de retorno. (usar post-its?)

se as interações forem apenas "o que o código diz" em breve, você poderá fazer as pessoas perceberem que as exceções são excepcionais.

para códigos de retorno, passe uma nota de post-it.

para exceções, jogue as mãos para o alto e diga qual é o problema.

depois faça com que eles "capturem x, joguem x" e vejam muito pior o diagnóstico é o que a GUI obtém "o modelo teve uma exceção".

Acho que isso funcionará para treinar as pessoas que você tem, porque elas entendem muito bem as interações com outras pessoas.

Tim Williscroft
fonte
+1 para a ideia de dramatização. Nunca pensamos nisso antes. Quem poderia pensar que o ensino de programação poderia ser feito através do Role Play?
Kanini 3/11/10
1

Eu imaginaria entender as exceções que você primeiro precisa entender, por exemplo, o relacionamento filho / pai das classes. Se você entender que um filho pode herdar a funcionalidade de um pai, ele poderá, em nível elementar, entender que, se um filho tem um problema que não pode lidar, ele passará esse problema (exceção) para o pai e permitirá que o pai lide. com isso.

Isso se torna uma relação encadeada até você terminar em um lugar onde algo sabe como lidar com a exceção.

E, no que diz respeito finalmente, esta é a parte trivial ... quando ocorre um problema, algo tem que lidar com isso, para que o programa não saia fatalmente, depois que essa exceção é manipulada, o bloco finalmente está lá, que sempre será executado independentemente da tentativa de captura .

Um bom exemplo disso pode ser com redes:

  • nós fazemos a conexão
  • conexão está ok, então nós a usamos
  • quando terminamos, fechamos e liberamos recursos

ou em caso de exceção:

  • faça uma conexão
  • ocorre uma exceção com a qual algo lida
  • momento em que liberamos conexão e recursos associados
Chris
fonte
1

Dê um Aplicativo ao novato que possua muito bom tratamento de exceções. Lance alguma exceção em algum lugar e permita que eles a depurem com a ajuda do Logs. Ao rastrear a propagação da exceção, eles devem poder depurá-la. Faça este exercício 3 ou 4 vezes. Agora basta remover todo o tratamento de exceção do código e permitir que eles tentem rastrear a mesma exceção.

Acredito que a apreciação pelo código de Tratamento de exceções será instantaneamente apreciada.

Nerd
fonte
Soa como um plano. Você tem algum código de amostra disponível na Internet (por exemplo, sourceforge.net) que você recomendaria?
Kanini
0

Na IMO, você deve pensar que as instruções de tratamento de exceção e controle de fluxo são basicamente as mesmas. Você os utiliza para controlar o fluxo de seus programas com base em quais condições eles estão atualmente. A diferença é que o tratamento de exceções só reagirá quando ocorrer um erro (ou exceção).


fonte
@denny: Embora eu concorde com o "tratamento de exceções só reagirá quando ocorrer um erro (ou exceção)", não tenho muita certeza sobre a afirmação de que "o tratamento de exceções e as instruções de controle de fluxo são basicamente as mesmas". Eu discordo respeitosamente lá. O bloco catch efetivamente faz o que deve fazer sob essa condição. O bloco try, no entanto, não tem nada a ver com fluxo ou controle. O bloco finalmente, novamente, não tem nada a ver com fluxo ou controle. Talvez eu tenha entendido mal sua resposta, mas você pode esclarecer em benefício de mim e de outras pessoas?
Kanini
0

Provavelmente não ajudaria um novo programador, mas descobri que compreendi muito melhor o conceito de exceções quando comecei a usar mônadas na programação funcional. Uma mônada obriga a considerar todos os "canais" pelos quais os dados podem entrar ou sair de um programa, pois tudo isso fornece uma abstração conveniente para "ocultar" parte desse fluxo de dados.

A idéia de que uma função pode ter diferentes tipos de saída e uma exceção é como um tipo de retorno de prioridade mais alta da função é bastante clara.

Entenda, eu entendo que não é assim que as exceções funcionam na maioria dos idiomas (detalhes da implementação), mas em um sentido abstrato, é isso que está acontecendo.

CodexArcanum
fonte
0

Finja que um macaco está usando o teclado

Eu costumava dizer aos meus colegas quando eles estavam escrevendo um código para fingir que um macaco estava sentado no teclado e usando esse aplicativo.

Isso os ensinou a antecipar todos os tipos de coisas:

  • Dados ausentes
  • Arquivos ausentes
  • Caracteres alfa quando você espera números
  • Divisão por zero

Eu acho que foi a imagem da palavra de ter um macaco apenas apertando teclas e fazendo o que quisesse, em vez de seguir bem o que fez o truque. Funcionou para mim.

Michael Riley - também conhecido por Gunny
fonte
Macacos? Suponho, seus usuários de negócios nunca ouvi isso ;-)
Kanini
@ Kanan - Boa. Isso foi nos meus dias no Corpo de Fuzileiros Navais. Eu só queria que meu pessoal pensasse fora da caixa quando se tratava de captura de erros. Acabei de dizer erro de interceptação ... Eu quis dizer manipulação de exceção.
Michael Riley - AKA Gunny