ConstructiCat Logo
CodeBust.
Browse section ▾

Ocultação de erros.

Deixar de relatar os detalhes de um erro

Na programação de computadores, a ocultação de erros (ou engolir erros) é a prática de capturar um erro ou exceção e então continuar sem registrar, processar ou relatar o erro às outras partes do software. Tratar erros dessa maneira é considerado uma má prática e um antipadrão na programação de computadores. Em linguagens com suporte a tratamento de exceções, essa prática é chamada de engolir exceções.

Erros e exceções têm várias finalidades:

  • Ajudar os mantenedores do software a localizar e entender problemas que ocorrem quando um usuário está executando o software, quando combinados com um sistema de registro (logging)
  • Fornecer informações úteis ao usuário do software, quando combinados com mensagens de erro significativas, códigos de erro ou tipos de erro exibidos em uma interface, como mensagens de console ou como dados retornados por uma API (dependendo do tipo de software e do tipo de usuário)
  • Indicar que a operação normal não pode continuar, de modo que o software possa recorrer a formas alternativas de executar a tarefa exigida ou abortar a operação.

Quando os erros são engolidos, essas finalidades não podem ser cumpridas. As informações sobre o erro são perdidas, o que torna muito difícil localizar problemas. Dependendo de como o software é implementado, isso pode causar efeitos colaterais não intencionais que se propagam em cascata para outros erros, desestabilizando o sistema. Sem informações sobre a causa raiz do problema, é muito difícil descobrir o que está dando errado ou como corrigi-lo.

Exemplos

Linguagens com tratamento de exceções

Neste exemplo em C#, mesmo que o código dentro do bloco try lance uma exceção, ela é capturada pela cláusula catch genérica. A exceção foi engolida e é considerada tratada, e o programa continua.

try {
  throw new Exception();
} catch {
  // não faz nada
}

Neste exemplo em PowerShell, a cláusula trap captura a exceção que está sendo lançada e a engole ao continuar a execução. A mensagem "I should not be here" é exibida como se nenhuma exceção tivesse ocorrido.

&{ 
  trap { continue }
  throw
  write-output "I should not be here"
}

Engolir exceções também pode acontecer se a exceção for tratada e relançada como uma exceção diferente, descartando a exceção original e todo o seu contexto.

Neste exemplo em C#, todas as exceções são capturadas independentemente do tipo, e uma nova exceção genérica é lançada, mantendo apenas a mensagem da exceção original. O stacktrace original é perdido, junto com o tipo da exceção original, qualquer exceção da qual a original fosse um invólucro e qualquer outra informação capturada no objeto da exceção.

try {
    // faz algo
} catch (Exception ex) {
    // talvez faça algum tratamento local da exceção
    throw new Exception(ex.Message);
}

Uma forma melhor de relançar exceções sem perder informações é lançar a exceção original a partir da cláusula catch:

try {
    // faz algo
} catch (Exception ex) {
    // faz algum tratamento local da exceção
    throw;
}

Como alternativa, é possível criar uma nova exceção que envolve a exceção original, de modo que quaisquer outros tratadores tenham acesso a ambas:

try {
    // faz algo
} catch(Exception ex) {
    // talvez faça algum tratamento local da exceção
    throw new CustomException(ex);
}

Outras linguagens

Em Go, os erros são propagados retornando um objeto Error junto com o valor de retorno normal da função. Ele pode ser ignorado, como neste exemplo.

f, _ := "I should not be here", errors.New("")
fmt.Print(f)

No caso das chamadas de sistema em C, os erros são indicados pelo valor de retorno da chamada ser NULL, e as informações de erro são armazenadas em uma variável global errno. Este código garante que o file seja válido antes de acessá-lo, mas, se fopen falhou, o erro é engolido.

FILE *file = fopen("", "r");
if (file) {
  // faz algo com o arquivo
}

Causas

A causa subjacente mais comum de engolir erros é a falta de boas ferramentas e processos de registro (logging) enquanto o desenvolvedor está construindo o software. Diante de um erro que não pode ser facilmente tratado, se o desenvolvedor tiver boas ferramentas de registro, registrar um erro inesperado não custa ao desenvolvedor tempo nem esforço algum. Registrar o erro deve ser simples (uma chamada de método), rápido (sem impacto no desempenho da aplicação), seguro (não levanta nenhum erro ou exceção) e garantir que todas as informações sejam salvas, registrando o tipo de erro e quaisquer dados relevantes associados a ele, o stacktrace do erro (para que o desenvolvedor possa identificar exatamente onde o erro ocorreu e quais instruções o antecederam) e o instante (timestamp) do erro.

Tratadores de exceção temporários

Em linguagens com exceções verificadas, todas as exceções levantadas em um método devem ser listadas na assinatura desse método. Ao prototipar e implementar software, o código muda com frequência, o que significa que o tipo de exceções que podem ser levantadas em um método também muda com frequência. Ter de ajustar a assinatura do método toda vez que algo muda torna o desenvolvimento mais lento e pode ser frustrante, de modo que engolir exceções como medida temporária ao fazer grandes alterações no código é tentador. Esse código temporário de tratamento de exceções pode acabar indo parar na base de código lançada.

Mesmo em linguagens sem exceções verificadas, pode acontecer de se adicionarem tratadores de exceção temporários durante grandes alterações no código para acelerar a prototipagem, o que pode levar a engolir erros.

Evitar travamentos

Em situações em que o software não pode travar por nenhum motivo, engolir erros é uma prática na qual um programador pode facilmente cair. Por exemplo, espera-se que um plugin em execução dentro de outra aplicação trate todos os erros e exceções de forma a não travar a aplicação na qual está incorporado. A captura indiscriminada de erros e exceções é um padrão no qual é fácil cair ao tentar evitar travamentos a todo custo e, quando se combina isso com ferramentas de registro ruins, engolir erros pode acontecer.

Ocultar a complexidade dos usuários

Ao mostrar erros aos usuários, é importante transformar erros técnicos crípticos em mensagens que expliquem o que aconteceu e quais ações o usuário pode tomar, se houver, para corrigir o problema. Ao realizar essa tradução de erros técnicos em mensagens significativas para o usuário, erros específicos são frequentemente agrupados em erros mais genéricos, e esse processo pode levar a mensagens de usuário tão inúteis que o usuário não sabe o que deu errado ou como corrigir. No que diz respeito ao usuário, o erro foi engolido.