Одна идея этого урока: лучшее место для борьбы с ошибкой – дизайн, в котором она невозможна.
Знакомая ситуация
Ты просишь агента: «сделай, чтобы планировщик не падал». Агент послушно оборачивает каждый шаг проверками. Код раздувается вдвое, читать его стало тяжело – а через неделю пользователь жалуется: «нажал кнопку, ничего не произошло». Смотришь в лог – пусто. Ошибка была, агент её поймал... и молча проглотил.
Это классика: с ошибками начали бороться, вместо того чтобы их проектировать.
Обработка ошибок – один из главных источников сложности. Оустерхаут: сначала определи ошибки прочь из существования (define errors out of existence), и только то, что осталось, обрабатывай – в одном месте, громко и понятно.
Иерархия работы с ошибками
У сеньора есть чёткий порядок предпочтений. Каждый следующий уровень – только если предыдущий невозможен:
1
Сделать ошибку невозможной по дизайну define errors out of existenceПример Оустерхаута: «удали файл» при отсутствующем файле – не ошибка, а успех: файла нет, цель достигнута. Твой случай: «отпиши студента от рассылки», когда он уже отписан – это успех, а не сбой. Меняешь определение операции – и целый класс ошибок исчезает.
2
Обработать в одном месте error aggregationНе двадцать проверок по всему коду, а один общий обработчик: любая непойманная ошибка попадает туда, логируется и превращается в понятный ответ пользователю. Меньше дублей – меньше сложности.
3
Упасть громко и рано fail fastЕсли продолжать бессмысленно (нет ключа API, нет доступа к базе) – лучше остановиться сразу с внятным сообщением, чем ковылять дальше и портить данные. Тихая деградация данных страшнее громкого падения.
Две аудитории одного сообщения
Каждая ошибка говорит с двумя разными слушателями, и им нужны разные тексты:
Пользователю – что делать дальше. Не «Error 500», а «Не удалось сохранить план. Попробуй ещё раз или напиши в поддержку». Без технических деталей, с ясным следующим шагом.
В лог – что случилось технически. Какой запрос, какие данные, какой ответ пришёл от внешнего сервиса. Всё, что понадобится тебе или агенту, чтобы найти причину за минуты, а не часы.
Худший вариант – молча проглотить. ИИ-агенты это любят: обернуть вызов, а в ветке ошибки оставить пустоту. Приложение «не падает», но и не работает – и никто не знает, почему. Проглоченная ошибка отнимает больше времени, чем десять громких.
Как думают три уровня
Джун · ловит как попалоГде-то ошибки не обработаны вовсе, где-то проглочены «чтобы не падало». Сообщения – технический жаргон наружу или тишина. Каждый инцидент – детектив без улик.
Мидл · обрабатывает всё подрядПроверки на каждом шагу, код тонет в защитных конструкциях. Ошибки пойманы, но сложность выросла, а что видит пользователь – по-прежнему лотерея. Борется с симптомами, не с причиной.
Сеньор · меняет дизайнСначала спрашивает: «какие из этих ошибок можно определить прочь из существования?». Оставшиеся стягивает в одно место, критичные роняют систему громко и рано. Ошибок в коде меньше, а надёжность выше.
Проверь себя
1. В планировщике кнопка «удалить задачу» иногда выдаёт ошибку: задача уже удалена с другого устройства. Агент предлагает показывать «Ошибка: задача не найдена». Что предложит сеньор?
Это учебный пример «define errors out of existence»: пользователь хотел, чтобы задачи не было – её и нет, всё получилось. Подробный код ошибки полирует симптом, а блокировка устройств режет удобство ради проблемы, которую можно просто определить прочь из существования.
2. Студентка пишет: «нажимаю оплатить – ничего не происходит». В логах приложения пусто. Какова самая вероятная причина?
Сочетание «ничего не происходит» + «в логах пусто» – фирменный почерк проглоченной ошибки: перехватили, а в ветке обработки – пустота. Списывать на браузер рано, а логировать вообще всё – дорого и шумно. Сначала найти и вскрыть глотающие обработчики.
3. Приложение стартует, хотя ключ платёжного API не задан – ошибка всплывёт при первой оплате. Агент говорит: «зато сервис доступен». Позиция сеньора?
Отсутствие ключа – ошибка конфигурации, чинится только человеком. Падение при старте обнаружит её через минуту после деплоя. «Красивая обработка» и «тихое отключение» превращают минутную проблему в потерянные продажи: клиенты будут утыкаться в неработающую оплату, пока кто-то случайно не заметит.
Что говорить агенту уже сегодня
На этапе дизайна: какие из возможных ошибок можно define out of existence – изменить дизайн так, чтобы их не могло быть?
Против размазанных проверок: собери обработку ошибок в одно место, а не в каждой функции отдельно
Аудит на проглатывание: найди все места, где ошибка перехватывается и молча игнорируется – это запрещено
Два адресата: для каждой ошибки: пользователю – что делать дальше, в лог – технические детали для диагностики
Источники
John Ousterhout, A Philosophy of Software Design – глава 10 «Define Errors Out of Existence»: исключения как источник сложности и четыре техники борьбы.
Конспект книги – краткий разбор ключевых идей, включая философию ошибок.