Comments 16
Пользовательские — те, которые должны отображаться клиенту с нормальным текстом.
Все системные ошибки пользователь видит всегда как одну, например, Внутренняя ошибка сервера.
У большинства разработчиков, начинаются трудности в понимании, какую ошибку нужно выбрасывать в том или ином случае.
Вот здесь бы пару рецептов и лучших практик услышать…
Ошибки на сервере тоже могут быть весьма разными. Можно отталкиваться от стандартных HTTP кодов ошибок.
Так пользователь может ввести невалидные данные, очень часто отправлять запросы или может быть просто не авторизован.
Иначе как обычно: пользователь жалуется что у него ничего не работает, сообщение об ошибке неинформативное (та самая «внутренняя ошибка» и все), а на сервере в логи постоянно валится столько всего, что отследить какая именно ошибка случилась у этого пользователя без дополнительных подсказок очень сложно.
С другой стороны, тот же заказчик выставляет определнные требования к ошибкам, отдел безопасности выставляет требования к сокрытию данных, да и самих клиентов порой выбешивает — Внутренняя ошибка сервера. EA125. Вот и получается, что не все так однозначно… :)
Исключения — это не ошибки, а прерывание нормального потока исполнения. Значит, если вы для себя рассчитываете "вот, у меня тут могут возникнуть какие-то ошибки, но поток исполнения это не будет прерывать, я их как-то обработаю" — то используйте не исключения, а какие-то специальные значения.
Любая серьёзная ошибка, если она не замыкается на сервере или в глубине приложений, должна иметь возможность доехать до техподдержки, чтобы она могла самостоятельно или с помощью разработчиков объяснить пользователю, что делать дальше. Т.е. в интерфейсе заранее предусматривается страница с ошибкой, на которой выводится код ошибки и какая-либо подробная информация о случившемся, которую пользователь может передать в техподдержку голосом или через e-mail по кнопке «Сообщить об ошибке».
Для формирования кода ошибки каждый модуль приложения/сервера нумеруется, а внутри него нумеруются все места, кидающие ошибки/исключения. И на выходе получаем код ошибки как
module * 100 + errorNumber
Который передаётся с нижних уровней до UI в классе, подобному
/**
* Описание ошибки, которое передаётся для отображения и обработки с нижних уровней в UI
*/
data class ErrorDescription (
val fatal: Boolean, // степень важности ошибки:
// если true, то дальнейшая работа приложения не возможна, показываем диалог "переустановите или обратитесь к разработчику"
// false - показываем "попробуйте повторить операцию"
val code: Int, // код ошибки, см. ниже
val desc: String, // описание ошибки для пользователя
val exMessage: String = "", // сообщение в исключении
val stackTrace: String = "" // stack trace исключения
)
Если ошибка приезжает с сервера, то достаточно иметь code и desc, чтобы техподдержка могла быстро её найти в серверных логах.
В статье смешивается понятие ошибки и исключения. Ошибка — это именно ошибка в коде, когда тот работает не так, как задумывалось. Например, фабрика возвращает null вместо объекта.
Исключение — когда код работает корректно и происходит что-то нестандартное, но вполне нормальное — например, отсутствует файл, не отвечает сервер, пользователь ввёл кривые данные.
Соответсвенно, исключения надо обрабатывать и сообщать о них, а подход к ошибкам может быть самым разным, и остановка программы — тоже неплохой вариант.
Ошибка в коде — это баг, которых быть вообще не должно, но если они случаются, то программа не должна падать, а должна корректно сообщить пользователю что не так и куда ему обращаться за помощью.
Если программа может сообщить что не так, значит в принципе об этом было известно и тому, кто добавил вывод сообщения об ошибке.
Если возникает ошибка, которую никто не предполагал (а иначе её бы не было), то программа может остаться в неожиданном состоянии и экстренное завершение — довольно адекватный вариант. Допустим, в таком случае можно поставить глобальный обработчик и делать дамп всего что только можно и, проверяя его наличие при запуске, предлагать отправить отчёт.
Особенно это касается встраиваемых систем, представьте, что у марсохода сбоит гироскоп/термометр/дальномер/камера, он куда будет дамп скидывать для отчёта?
Самое главное, чего нет в этой статье, это как правильно рассказывать пользователю об ошибках, про это пишут в книжках про UI.
Прочитайте внимательно, пожалуйста.
Если возникает ошибка, которую никто не предполагал
Отказ удаленного сервиса (особенно 3rd party) — это не ошибка приложения, а прогнозируемое поведение, которое не оставит приложение в неопределённом состоянии.
Когда у марсохода сбоит компонента и этот сбой можно обнаружить — это не ошибка системы управления.
Но в случае именно ошибок для встраиваемых систем ещё более опасно оставаться в состоянии, которое разработчиком не предполагалось и в таких ситуациях космические аппараты перезапускают сами систему управления. Телеметрию, вообще говоря, с них так же передают, в т.ч. и информацию о сбоях.
Собственно, вы же, наверное, подходя к перекрестку не вызываете заранее машину скорой помощи, потому что не предполагаете, что вас собьёт машина. Но, если не дай бог это случится, то и добивать Вы себя не станете, правда?
Обработка ошибок в Kotlin/Java: как правильно это делать?