Throwing an Exception Without Proper Context Is a Bad Habit

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

Я продолжаю совершать одну и ту же ошибку снова и снова. Поэтому пришло время остановиться и установить правило, чтобы предотвратить это больше не происходило. Ошибка не фатальна, но она очень раздражает. Когда я смотрю на производственные журналы, я часто вижу что-то вроде "Файл не существует", и задаю себе вопрос: Какой файл? Где он должен существовать? Что сервер пытался сделать с ним? Что происходило за секунду до сбоя? В журнале нет ответа, и это полностью моя вина. Я либо не перебрасываю исключение, либо перебрасываю его без контекста. И то, и другое неправильно.

Вот как может выглядеть код:

if (!file.exists()) {
  throw new IllegalArgumentException(
    "File doesn't exist"
  );
}

Это также может выглядеть так:

try {
  Files.delete(file);
} catch (IOException ex) {
  throw new IllegalArgumentException(ex);
}

Оба примера демонстрируют неадекватный стиль обработки ситуаций, связанных с исключениями и их отчетностью. Что здесь не так? Сообщения об исключениях недостаточно подробны. Они просто не содержат никакой информации о месте, откуда они были вызваны.

Вот как они должны выглядеть вместо этого:

if (!file.exists()) {
  throw new IllegalArgumentException(
    String.format(
      "User profile file %s doesn't exist",
      file.getAbsolutePath()
    )
  );
}

И второй пример должен выглядеть так:

try {
  Files.delete(file);
} catch (IOException ex) {
  throw new IllegalArgumentException(
    String.format(
      "Can't delete user profile data file %s",
      file.getAbsolutePath()
    ),
    ex
  );
}

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

But I should.

Должно существовать правило: каждый раз, когда мы бросаем или повторно бросаем, сообщение об исключении должно описывать проблему с максимальной детализацией.

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

Бросание исключения - это буквально эскалация проблемы на более высокий уровень управления. Представьте, что мой начальник просит меня установить новый сервер. Я возвращаюсь к нему через несколько часов и говорю: “Я потерпел неудачу, извините”. Это звучало бы странно. Он бы попросил больше подробностей. Почему я потерпел неудачу? Что именно пошло не так? Можно ли сделать это иначе? И так далее.

Такой код является явным проявлением неуважения к клиенту.

throw new IllegalArgumentException(
  "File doesn't exist"
);

Мне нужно быть более развернутым и предоставлять больше деталей.

И я не один в этой ошибке. Я вижу ее повсюду, и это действительно затрудняет отладку, особенно в производственной среде, где почти невозможно воспроизвести проблему сразу же.

Поэтому, пожалуйста, будьте более развернутыми в сообщениях об ошибках. Я сделаю то же самое в своем коде.

И еще одна вещь, прежде чем вы уйдете. В большинстве ООП-языков исключения не проверяются, что означает, что их перехват не является обязательной операцией, к сожалению. Тем не менее, я рекомендую вам всегда перехватывать исключения, добавлять контекст и снова их выбрасывать. Это может показаться просто лишним шумом, но это не так! Просто сделайте ваши методы более компактными и убедитесь, что все исключения, выбрасываемые из них, содержат достаточную информацию о своем происхождении. Вы сделаете себе и всем остальным большую услугу.

Translated by ChatGPT gpt-3.5-turbo/35 on 2023-09-09 at 05:38

sixnines availability badge   GitHub stars