Исключения и обработка ошибок в читаемом коде
Тема дополняет быстрый провал и отказ от null: ошибка — часть контракта, а не побочный if с магическим кодом возврата.
Классика Мартина (Clean Code) и практика индустрии сходятся: узкий try, осмысленные типы, без пустых catch.
Исключения — не поток управления
Использовать throw вместо обычных веток цикла — тот же запах, что goto. Ожидаемые бизнес-ситуации («корзина пуста») часто лучше выражать Result, кодом возврата домена или Optional, а исключения оставить для нарушенных инвариантов и сбоев инфраструктуры.
Пустые и широкие catch
try {
parseDate(input);
} catch (Exception e) {
// пусто — пользователь не поймёт, лог пуст
}
На практике:
- не глотать исключения;
- маленький блок try — один уровень абстракции;
- перехватывать конкретные типы, не
Exception«на всякий случай».
Коды возврата vs исключения
В C и legacy API коды 0/-1 размазывают проверки. Замените на исключения или Result на границе модуля, чтобы внутри домена не было if (rc != OK) на каждом шаге.
Вложенность try/catch
«Стрелы» из try внутри try лечатся guard clauses и выделением методов — так же, как глубокие if.
Сообщения пользователю и безопасность
Не показывайте стек и внутренние детали конечному пользователю; логируйте полную ошибку на сервере. Связь с безопасностью (санитизация, утечки данных).
Для API — стабильные коды ошибок, correlation id в логах (наблюдаемость).
Ожидаемые случаи
Переписать исключения для ожидаемых отказов: «файл не найден» при экспорте отчёта — часть сценария, а не NullPointerException где-то глубоко.
Связь с null
NullReferenceException часто значит: в модели допустили null там, где нужен Optional или Null Object. Исправление типов обычно эффективнее try/catch вокруг каждого вызова.
На ревью
- Новый пустой
catch— отклонить. throws Exceptionв сигнатуре публичного API — уточнить контракт.- Бизнес-ветка через
throw new Exception("error")— заменить типизированным доменным исключением или Result.
Указатель тем — 13. См. также тесты и глобалы.
См. также
Другие статьи этого же раздела в боковом меню (как на странице "О разделе"). Именование, форматирование, комментарии, документация в коде и базовые принципы читаемости — практики, которые команда договаривается соблюдать каждый день. Цикломатическая сложность — одна из наиболее устойчиво применяемых метрик статического анализа программного кода, призванная количественно оценивать логическую структуру исполняемого модуля. Правило MAPPER (Model Abstract Partial Programmable Explaining Reality) — как сопоставлять реальность и код один к одному. Богатые объекты предметной области, value objects вместо string/int и антипаттерны DTO-оргии. const, иммутабельность, ленивая инициализация и побочные эффекты в читаемом коде. Разделение «что» и «как», итерации, магические числа, callback hell и явные ошибки. Меньше if и switch, отказ от null, быстрый провал и полиморфизм вместо флагов. Singleton, god object, shotgun surgery, feature envy и глобальное состояние — симптомы и приёмы рефакторинга. Мёртвый код, лишние абстракции, отключённые предупреждения и отложенный рефакторинг. Приватные методы, flaky-тесты, assertTrue, моки и данные — качество тестового кода и связь с разделом тестирования. Краткие итоги раздела "Культура кода". Вопросы перед отправкой кода в репозиторий — именование, принципы, тесты, ревью и безопасность. Ответы ищите в статьях раздела.Культура написания и поддержки кода
Цикломатическая сложность и читаемость кода
MAPPER — модель кода и предметная область
Анемичные модели и примитивная одержимость
Изменяемость, побочные эффекты и неизменяемые данные
Декларативный код — что и как
Условия, null и явные контракты
Связанность, глобалы и запахи модульности
YAGNI, быстрый провал и техдолг в коде
Тесты как часть культуры кода
Итоги
Чек-лист самопроверки