Como posso melhorar minha verificação e tratamento de erros?

13

Ultimamente, tenho me esforçado para entender qual é a quantidade certa de verificação e quais são os métodos adequados.

Eu tenho algumas perguntas sobre isso:

Qual é a maneira correta de verificar se há erros (entrada incorreta, estados incorretos etc.)? É melhor verificar explicitamente se há erros ou usar funções como declarações que podem ser otimizadas em seu código final? Sinto que a verificação explícita desorganiza um programa com muito código extra que não deve ser executado na maioria das situações - e sem mencionar que a maioria dos erros acaba com uma falha de abortar / sair. Por que desorganizar uma função com verificações explícitas apenas para abortar? Procurei afirmações versus verificação explícita de erros e encontrei pouco para realmente explicar quando fazê-lo.

A maioria diz 'use asserts para verificar erros de lógica e use verificações explícitas para verificar outras falhas'. Isso não parece nos levar muito longe. Diríamos que isso é possível:

Malloc returning null, check explictly
API user inserting odd input for functions, use asserts

Isso me tornaria melhor na verificação de erros? O que mais eu posso fazer? Eu realmente quero melhorar e escrever melhor, código 'profissional'.

Anon
fonte
3
Boa pergunta, mas acho que pode ser mais adequado para um dos sites irmãos (programadores?).
Obrigado, eu não tinha certeza. Eu pensei que, uma vez que era bastante relacionado ao código, tudo ficaria bem.
Anon
3
A resposta simples é "É por isso que as exceções foram inventadas. Obtenha um idioma melhor".
DeadMG
1
@DeadMG: setjmp/ longjmpestão disponíveis em C, então você não precisa de um novo idioma.
user786653
3
@DeadMG: Alguém que não pode ficar de erro C verificando direito tem a chance bolas de neve no inferno recebendo exceção C ++ manipulação certo ...
Coder

Respostas:

4

A maneira mais fácil de dizer a diferença é determinar se a condição de erro é introduzida no tempo de compilação ou no tempo de execução. Se o problema for um programador que está usando a função de alguma maneira errada, faça com que seja necessário chamar a atenção para o problema, mas depois que a correção for compilada no código de chamada, você não precisará mais se preocupar em procurar por ela. Problemas como falta de memória ou entrada incorreta do usuário final não podem ser resolvidos em tempo de compilação; portanto, você deixa as verificações.

Karl Bielefeldt
fonte
2

Verifique qualquer coisa a qualquer momento (pode ter sido alterada após sua última verificação) que não esteja 100% sob seu comando. E também: Durante o desenvolvimento, mesmo não confie em si mesmo! ;-)

Okokok ... "qualquer coisa" deve ser lido como uma verificação de coisas que causariam um cancelamento anormal ou qualquer coisa que pudesse fazer seu aplicativo / sistema fazer coisas que não deveria .

Para ser sério, a última parte da última frase é essencial porque aponta para a questão principal:

Se você quer construir um sistema estável a preocupação principal não sobre o que o sistema deve fazer, mas para que seja capaz de fazer tais coisas obrigatórias, é preciso tomar cuidado com o que ele deve não fazer, mesmo se ele "tumultua o seu código".

alk
fonte
1
+1 para 'verificar tudo'. Não compreendo o argumento da desordem de código: qualquer programador deve ser capaz de distinguir entre verificação de erro e lógica real de qualquer maneira.
stijn 27/10/11
2

O cerne da manipulação de erros não é se e como você captura o problema. É mais do que você faz depois de aprender sobre isso .

Primeiramente - eu diria que não há razão para que um único erro retornado pelo método subordinado esteja retornando não deva ser tratado. E erros e exceções são apenas mais do que os valores de retorno ou todos try / catch.

  1. Apenas jogar e pegar não é suficiente.
    Veja isto : onde o autor explica que apenas capturar mas não fazer nada potencialmente suprime a exceção e, a menos que seja feito o suficiente para desfazer o dano - é pior do que deixar o código continuar assim. Da mesma forma, apenas escrever a instrução "log" quando houver um erro de abertura ou leitura de arquivo pode ajudar a encontrar o motivo - mas quando o programa termina, isso pode causar danos aos dados! Não basta dizer que tenho muitas tentativas / capturas - é mais importante saber o que elas realmente fazem!

  2. Não abuse da tentativa e captura.
    Algumas vezes - programadores preguiçosos ou ingênuos pensam que, depois de escrever try / catch suficiente, seu trabalho acaba e é fácil. Muitas vezes, é melhor aplicar a ação corretiva e retomar, em vez de simplesmente despejar tudo. Se isso não puder ser feito, é preciso decidir em que nível você precisa voltar. Dependendo do contexto e da gravidade, tente criar um aninhamento preciso de um design cuidadoso. Por exemplo - Veja isto e isto

  3. Defina quem é responsável:
    Uma das primeiras coisas que você deve fazer é definir se a entrada fornecida à rotina em si é apenas um cenário inaceitável (ou não tratado até o momento) ou se é a exceção devido ao ambiente (como problema no sistema, problema de memória) ou essa situação é um resultado completamente interno do resultado do algoritmo. Em todos os casos - o nível em que você pode querer voltar ou a ação que deseja executar difere significativamente. Sob essa luz, eu gostaria de dizer - que quando você executa o código em produção - fazer abort () para sair do programa é bom - mas não para todas as pequenas coisas. Se você detectar corrupção ou falta de memória, é definitivo que, mesmo depois de fazer o seu melhor - as coisas vão morrer. Mas se você receber um ponteiro NULL na entrada - eu não

  4. Defina qual é o melhor resultado possível:
    tudo o que deve ser feito com exceção é muito crítico. Por exemplo, se em um de nossos casos - um media player descobre que não possui dados completos a serem reproduzidos pelo usuário - o que deve fazer?

    • pule alguma parte ruim e veja se ela consegue avançar com coisas boas.
    • se isso acontecer demais, considere se pode pular para a próxima música.
    • se achar que não é capaz de ler nenhum arquivo - pare e mostre algo.
    • enquanto isso
    • em qual estado um jogador deve fazer o POP-UP para o usuário e
    • quando deve levar por conta própria?
    • Ele deve "interromper" as coisas para solicitar feedback do usuário
    • ou deve colocar uma pequena nota de erro discreta em algum canto?

    Tudo isso é subjetivo - e talvez haja mais maneiras de lidar com problemas do que pensamos trivialmente. Tudo o que foi dito acima exige que você crie e compreenda a profundidade da exceção e que também faça com que diferentes cenários possam evoluir.

  5. Às vezes, precisamos verificar as exceções antes que elas surjam. O exemplo mais comum é o erro de divisão por zero. Idealmente, é preciso testar isso antes que essa exceção seja lançada - e se for esse o caso - tente colocar o valor diferente de zero mais apropriado e seguir em frente, em vez de se suicidar!

  6. Limpar. Pelo menos é isso que você deve fazer! Se uma função abrir 3 arquivos e o quarto não abrir - é desnecessário dizer que os 3 primeiros deveriam ter sido fechados. Delegar esse trabalho para uma camada acima é uma má ideia. se você decidir não sair sem limpar a memória. E o mais importante - mesmo que você tenha sobrevivido à exceção, informe ao mais alto que as coisas não seguiram o curso normal.

A maneira como vemos a funcionalidade (normal) do software em termos de várias hierarquias ou camadas ou abstrações, da mesma forma que devemos categorizar as exceções com base em sua gravidade, bem como no escopo em que elas surgem e estão afetando outras partes do sistema - que define como lidar com exceções tão diferentes da melhor maneira possível.

Melhor referência: Code Craft capítulo 6 - disponível para download

Dipan Mehta
fonte
1

A verificação de erros apenas nas compilações de depuração é uma BAD IDEA (tm), compilando sob sobreposições de variáveis ​​reutilizáveis ​​na pilha, remove páginas de proteção, faz truques duvidosos com cálculos, substitui artríticas pesadas por turnos pré-computados e assim por diante.

Use a verificação de erros na versão também, você pode recorrer a algo tão simples como:

if(somethinghitthefan)
     abort();

Isso também tem um efeito colateral muito bom, que você definitivamente não ignorará o bug quando o aplicativo começar a falhar no PC dos betta testers.

Os visualizadores e logs de eventos são completamente inúteis em comparação com abort()quem os verifica mesmo assim?

Codificador
fonte
exit / abort == pior experiência do usuário sempre: o aplicativo simplesmente desaparece sem dizer por que ..
stijn
@stijn: abortinvade o depurador / cria um despejo. exité ruim sim Embora eu prefira __asm int 3mais.
Coder
isso é verdade, e em C / C ++ eu costumo escrever declarações usando __asm ​​int 3 também, mas nunca sem mostrar pelo menos uma descrição do porquê e, de preferência, também linha e arquivo. Então, pelo menos, o cliente pode fornecer informações sobre o que aconteceu exatamente.
stijn
0

As várias coisas que você pode fazer são:
1.Ler e assimilar muito código on-line e ver como isso é feito;
2.Utilizar algumas ferramentas de depuração para ajudá-lo a localizar regiões de erros
; erros de sintaxe.
4. Alguns erros piores aparecem devido a erros lógicos no programa que são mais difíceis de encontrar. Para isso, você pode descobrir e encontrar ou, para os mais complicados, tentar falar com pessoas ou usar recursos como Stackoverflow , Wikipedia , google para obter ajuda de pessoas.

DCV
fonte