---
title: "Сокрытие ошибок"
type: "antipattern"
slug: "error-hiding"
url: "http://localhost:3000/ru/antipatterns/error-hiding.md"
description: "Отказ от сообщения подробностей об ошибке"
---
# Сокрытие ошибок

> Отказ от сообщения подробностей об ошибке

В [программировании](https://en.wikipedia.org/wiki/Computer%5Fprogramming "Computer programming") **сокрытие ошибок** (или **проглатывание ошибок**) — это практика перехвата ошибки или [исключения](https://en.wikipedia.org/wiki/Exception%5F%28computing%29 "Exception (computing)") с последующим продолжением работы без журналирования, обработки или передачи сведений об ошибке другим частям программного обеспечения. Такая обработка ошибок считается плохой практикой и [антипаттерном](https://en.wikipedia.org/wiki/Anti-pattern "Anti-pattern") в [программировании](https://en.wikipedia.org/wiki/Computer%5Fprogramming "Computer programming"). В языках с [поддержкой обработки исключений](https://en.wikipedia.org/wiki/Exception%5Fhandling#Exception%5Fsupport%5Fin%5Fprogramming%5Flanguages "Exception handling") эта практика называется **проглатыванием исключений**.

Ошибки и исключения служат нескольким целям:

* Помогают тем, кто сопровождает ПО, находить и понимать проблемы, возникающие при работе пользователя с программой, — в сочетании с системой журналирования
* Предоставляют полезную информацию пользователю программы — в сочетании с осмысленными сообщениями об ошибках, кодами ошибок или типами ошибок, отображаемыми в интерфейсе, в виде консольных сообщений или данных, возвращаемых из [API](https://en.wikipedia.org/wiki/API "API") (в зависимости от типа программного обеспечения и типа пользователя)
* Сигнализируют о том, что нормальная работа не может продолжаться, чтобы программа могла прибегнуть к альтернативным способам выполнения требуемой задачи или прервать операцию.

Когда ошибки проглатываются, эти цели не могут быть достигнуты. Информация об ошибке теряется, что крайне затрудняет поиск проблем. В зависимости от того, как реализовано программное обеспечение, это может вызвать непреднамеренные побочные эффекты, которые каскадом порождают другие ошибки, дестабилизируя систему. Без информации о коренной причине проблемы очень трудно понять, что идёт не так и как это исправить.

## Примеры

### Языки с обработкой исключений

В этом примере на [C#](https://en.wikipedia.org/wiki/C%5FSharp%5F%28programming%5Flanguage%29 "C Sharp (programming language)"), хотя код внутри блока _try_ выбрасывает исключение, оно перехватывается всеохватывающим предложением _catch_. Исключение проглочено и считается обработанным, а программа продолжает работу.

try {
  throw new Exception();
} catch {
  // ничего не делать
}

В этом примере на [PowerShell](https://en.wikipedia.org/wiki/PowerShell "PowerShell") предложение _trap_ перехватывает выбрасываемое исключение и проглатывает его, продолжая выполнение. Сообщение _"I should not be here"_ отображается так, будто никакого исключения не произошло.

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

Проглатывание исключений может также происходить, если исключение обрабатывается и перевыбрасывается как другое исключение, отбрасывая исходное исключение и весь его контекст.

В этом примере на C# все исключения перехватываются независимо от типа, и выбрасывается новое обобщённое исключение, сохраняющее лишь сообщение исходного исключения. Исходная трассировка стека теряется вместе с типом исходного исключения, любым исключением, обёрткой над которым было исходное, и любой другой информацией, содержавшейся в объекте исключения.

try {
    // что-то сделать
} catch (Exception ex) {
    // возможно, выполнить локальную обработку исключения
    throw new Exception(ex.Message);
}

Лучший способ перевыбросить исключение, не теряя информации, — выбросить исходное исключение из предложения _catch_:

try {
    // что-то сделать
} catch (Exception ex) {
    // выполнить локальную обработку исключения
    throw;
}

В качестве альтернативы можно создать новое исключение, которое оборачивает исходное, чтобы любые другие обработчики имели доступ к обоим:

try {
    // что-то сделать
} catch(Exception ex) {
    // возможно, выполнить локальную обработку исключения
    throw new CustomException(ex);
}

### Другие языки

В [Go](https://en.wikipedia.org/wiki/Go%5F%28programming%5Flanguage%29 "Go (programming language)") ошибки распространяются путём возврата объекта _Error_ вместе с обычным возвращаемым значением функции. Его можно проигнорировать, как в этом примере.

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

В случае системных вызовов [C](https://en.wikipedia.org/wiki/C%5F%28programming%5Flanguage%29 "C (programming language)") на ошибки указывает то, что возвращаемое значение вызова равно _NULL_, а информация об ошибке хранится в глобальной переменной _errno_. Этот код проверяет, что _file_ допустим, прежде чем обращаться к нему, но если _fopen_ завершился неудачей, ошибка проглатывается.

FILE *file = fopen("", "r");
if (file) {
  // что-то сделать с файлом
}

## Причины

Наиболее частая глубинная причина проглатывания ошибок — отсутствие хороших инструментов и процессов журналирования в то время, когда разработчик создаёт программное обеспечение. Столкнувшись с ошибкой, которую нелегко обработать, разработчик, имеющий хорошие инструменты журналирования, не тратит на журналирование непредвиденной ошибки ни времени, ни усилий. Журналирование ошибки должно быть простым (один вызов метода), быстрым (без влияния на производительность приложения), безопасным (не вызывает никаких ошибок или исключений) и гарантировать сохранение всей информации за счёт записи типа ошибки и любых связанных с ней данных, [трассировки стека](https://en.wikipedia.org/wiki/Stack%5Ftrace "Stack trace") ошибки (чтобы разработчик мог точно определить, где произошла ошибка и какие инструкции к ней привели), а также временной метки ошибки.

### Временные обработчики исключений

В языках с [проверяемыми исключениями](https://en.wikipedia.org/wiki/Checked%5Fexceptions "Checked exceptions") все исключения, возбуждаемые в методе, должны быть перечислены в сигнатуре этого метода. При прототипировании и реализации программного обеспечения код часто меняется, а значит, часто меняется и набор типов исключений, которые могут возбуждаться в методе. Необходимость корректировать сигнатуру метода всякий раз, когда что-то меняется, замедляет разработку и может раздражать, поэтому проглатывание исключений как временная мера во время крупных изменений кода выглядит привлекательно. Такой временный код обработки исключений может в итоге попасть в выпущенную [кодовую базу](https://en.wikipedia.org/wiki/Codebase "Codebase").

Даже в языках без проверяемых исключений добавление временных обработчиков исключений во время крупных изменений кода для ускорения прототипирования вполне возможно, что может привести к проглатыванию ошибок.

### Предотвращение сбоев

В ситуациях, когда программное обеспечение не должно аварийно завершаться ни по какой причине, проглатывание ошибок — это практика, в которую программист может легко скатиться. Например, ожидается, что [плагин](https://en.wikipedia.org/wiki/Plug-in%5F%28computing%29 "Plug-in (computing)"), работающий внутри другого приложения, обрабатывает все ошибки и исключения так, чтобы не привести к аварийному завершению приложения, в которое он встроен. Всеохватывающий перехват ошибок и исключений — это паттерн, в который легко скатиться при попытке любой ценой предотвратить сбои; а в сочетании с плохими инструментами журналирования это может привести к проглатыванию ошибок.

### Сокрытие сложности от пользователей

При показе ошибок пользователям важно превращать загадочные технические ошибки в сообщения, объясняющие, что произошло и какие действия пользователь может предпринять (если они есть) для устранения проблемы. В ходе такого перевода технических ошибок в осмысленные пользовательские сообщения конкретные ошибки часто объединяются в более общие, и этот процесс может привести к тому, что пользовательские сообщения становятся настолько бесполезными, что пользователь не понимает, что пошло не так и как это исправить. С точки зрения пользователя ошибка оказалась проглочена.
