Статьи

Правда, лежащая в основе больших исключений

Исключения, вероятно, являются наиболее неправильно используемой функцией языка Java. Вот почему

Давайте разберемся с некоторыми мифами. Там нет зубной феи. Санта не настоящий. ТОДО комментарии. finalfinalversion-final.pdf. Мыло без мыла. И … Исключения на самом деле являются исключениями. Последнему, возможно, понадобится больше убедительности, но мы вас прикрыли.

В этом посте мы попросили Avishai Ish-Shalom , опытного системного архитектора и давнего друга блога (что особенно важно, большого любителя пушистых шляп ), присоединиться к нам, чтобы поболтать о текущем состоянии исключений в приложениях Java , Вот что мы узнали.

Исключения по определению далеки от нормальных

Давайте начнем с цитаты из официальной документации по Java : «Исключением является событие, которое происходит во время выполнения программы, которая нарушает нормальный поток инструкций». Честное раскрытие: мы добавили шапки сами.

На практике нормальный поток инструкций в большинстве приложений заполнен «нормальными» повторениями этих так называемых «нормальных» исключений, которые вызывают «нормальные» сбои.

Исключение-мим-300x259 @ 2x

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

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

Например, большинство приложений имеют «нормальный» уровень событий ошибок. На следующем снимке экрана мы видим, что это около 4 тыс. Событий в час:

Исключения

Панель анализа ошибок Takipi — Тенденции ошибок

Если нам «повезет», новая ошибка будет отображаться как всплеск на графике, как у нас здесь, с исключением IllegalStateException, возникающим сотни тысяч раз около 1 часа ночи (Ой). Мы можем сразу увидеть, что вызвало всплеск.

Зеленая линия указывает общее количество событий, а остальные строки указывают конкретные исключения и зарегистрированные ошибки / предупреждения.

Опасность исходит от исключений, за исключением нескольких небольших, но смертельных случаев, которые скрыты в так называемом «нормальном» уровне исключения.

Что это за «нормальные» исключения, о которых вы говорите?

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

  1. Бизнес-ошибки — все, что может сделать пользователь / данные, что бизнес-поток не разрешает. Как и любая проверка формы, заполнение текста внутри поля формы телефонного номера, проверка с пустой корзиной и т. Д. Кроме того, внутреннее число NumberFormatException достигло уровня 2 из 10 исключений в нашей последней публикации, посвященной исследованию более 1B в производственных условиях .
  2. Системные ошибки — все, что вы спрашиваете у операционной системы и может быть нет, вещи, которые находятся вне вашего контроля. Например, пытаясь получить доступ к файлу, для которого у вас нет прав.

С другой стороны, настоящие исключения — это вещи, о которых вы не знали при написании кода, такие как исключение OutOfMemoryException или даже исключение NullPointerException, которое неожиданно портит ситуацию. Проблемы, требующие принятия мер для их устранения.

Inconceviable-Исключения-300x278 @ 2x

Исключения предназначены для аварий и сгорания

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

Основная цель исключения в Java — помочь вам поймать ошибку и устранить ее, не пересекая линии в логику приложения. Они должны были помочь в отладке, поэтому они стараются содержать как можно больше информации с точки зрения приложения.

Другая проблема, которую это может создать, — это несогласованное состояние, когда поток приложения становится… нервным, это даже хуже, чем оператор goto. У него те же недостатки, с некоторыми изюминками:

  1. Это нарушает поток программы
  2. Трудно отследить и понять, что будет дальше
  3. Трудно очистить, даже с наконец-то блоки
  4. Тяжеловес, в отличие от «goto», несет в себе весь стек и дополнительные данные

Используйте «ошибочные» потоки без исключений

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

Проблемы, которые могут возникнуть, на самом деле не являются исключением из книги. Интересное решение приходит от Futures в Scala — обработка ошибок без исключений. Пример Scala из официальных документов Scala:

01
02
03
04
05
06
07
08
09
10
import scala.util.{Success, Failure}
 
val f: Future[List[String]] = Future {
    session.getRecentPosts
}
 
f onComplete {
    case Success(posts) => for (post <- posts) println(post)
    case Failure(t) => println("An error has occured: " + t.getMessage)
}

Исключения могут быть вызваны кодом, выполняемым внутри будущего, но они содержатся и не просачиваются наружу. Возможность сбоя явно указывается веткой Failure (t), и очень легко следить за выполнением кода.

В новой функции Java 8 CompletableFuture (о которой мы недавно писали) мы можем использовать completeExceptionally (), хотя она не такая красивая.

Сюжет становится толще с API

Допустим, у нас есть система, которая использует библиотеку для доступа к базе данных. Как библиотека БД будет выставлять свои ошибки внешнему миру? Добро пожаловать на дикий дикий запад. И имейте в виду, что библиотека может по-прежнему генерировать общие ошибки, такие как java.net.UnknownHostException или NullPointerException

Один реальный пример того, как это может пойти не так, — это библиотека, которая оборачивает JDBC и просто генерирует общее исключение DBException, не давая вам возможности узнать, в чем дело. Может быть, все просто отлично, и есть только ошибка подключения, или, может быть … вам действительно нужно изменить код.

Распространенным решением является библиотека БД, использующая базовое исключение, скажем, DBException, от которого наследуются исключения библиотеки. Это позволяет пользователю библиотеки перехватывать все ошибки библиотеки одним блоком try. Но как насчет системных ошибок, которые могли вызвать ошибку библиотеки? Общее решение — обернуть любое исключение, происходящее внутри него. Поэтому, если он не может разрешить DNS-адрес, который является скорее системной ошибкой, чем ошибкой библиотеки, он перехватит его и сбросит это исключение более высокого уровня, которое должен знать пользователь библиотеки. Попробуйте поймать кошмар, с намеком на вложенные исключения, обертывающие другие исключения.

Если мы добавим актеров в микс, поток управления станет еще сложнее. Асинхронное программирование с исключениями — беспорядок. Он может убить Actor , перезапустить его, сообщение будет отправлено другому Actor с исходной ошибкой, и вы потеряете стек.

Итак … Что вы можете с этим поделать?

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

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

Подводя итог, неактивные исключения вызывают много путаницы:

  • Производительность
  • стабильность
  • Мониторинг / анализ журнала
  • И … Скрыть реальные исключения, которые вы хотите видеть и действовать на

жизнь-это-боль-768x432

Решение состоит в том, чтобы … сделать тяжелую работу по удалению шума и созданию потоков управления, которые имеют больше смысла. Еще одно креативное решение — изменение уровней журналов, если это не исключение для действий, не регистрируйте его как ошибку. Это только косметическое решение, но вы можете получить до 80% работы.

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

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

Последние мысли

Суть в том, есть ли у вас Исключение, которое не приводит к изменениям кода? Вы даже не должны тратить время на это.

Этот пост основан на молниеносном разговоре, который Авишай назвал «Исключениями, которые можно применить»: