Статьи

Бросать исключение без надлежащего контекста — плохая привычка

Четыре комнаты (1995) Аллисон Андерс и соавт.

Четыре комнаты (1995) Аллисон Андерс и соавт.

Я повторяю одну и ту же ошибку снова и снова. Настало время остановиться и выработать правило, чтобы этого больше не происходило. Ошибка не смертельная, но очень раздражающая. Когда я просматриваю производственные журналы, я часто вижу что-то вроде "File doesn't exist" , и я спрашиваю себя: какой файл? Где это должно существовать? Что сервер пытался сделать с этим? Что происходило за секунду до его падения? В журнале нет ответа, и это полностью моя вина. Я либо 1) не перебрасываю, либо 2) перебрасываю без предоставления контекста. Оба не правы.

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

1
2
3
4
5
if (!file.exists()) {
  throw new IllegalArgumentException(
    "File doesn't exist"
  );
}

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

1
2
3
4
5
try {
  Files.delete(file);
} catch (IOException ex) {
  throw new IllegalArgumentException(ex);
}

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

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

1
2
3
4
5
6
7
8
if (!file.exists()) {
  throw new IllegalArgumentException(
    String.format(
      "User profile file %s doesn't exist",
      file.getAbsolutePath()
    )
  );
}

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

01
02
03
04
05
06
07
08
09
10
11
try {
  Files.delete(file);
} catch (IOException ex) {
  throw new IllegalArgumentException(
    String.format(
      "Can't delete user profile data file %s",
      file.getAbsolutePath()
    ),
    ex
  );
}

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

Но я должен.

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

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

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

Такой код буквально признак неуважения к клиенту:

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

Я должен быть более многословным и дать больше деталей.

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

Поэтому будьте более многословны в своих сообщениях об исключениях. Я сделаю то же самое в моем коде 🙂

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