Нужно ли оборачивать весь код в блоки Попытка-Исключение и является ли это новым трендом?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Философия обработки исключений: «Быстрый отказ» против «Защитного программирования»

Рассмотрим две основные концепции. Первая — Fail-fast (Быстрый отказ). Согласно этой концепции, программа должна прекратить выполнение сразу же, как только возникла непредвиденная ситуация. Это позволяет разработчику мгновенно увидеть ошибку, получить точный стек вызовов и исправить причину на этапе разработки или тестирования. Проанализируем вторую концепцию — Defensive Programming (Защитное программирование). Она предполагает, что программа должна продолжать работу любой ценой. Повсеместное использование try/catch (или Попытка...Исключение в 1С) часто является извращенной формой этой концепции, которую в индустрии называют «ловлей покемонов» (Gotta catch 'em all!).

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

Стандарты 1С: Почему нельзя просто «проглатывать» ошибки

Согласно официальным стандартам 1С (система ИТС), использование блоков Попытка...Исключение должно быть оправданным и точечным. Основная рекомендация платформы заключается в том, что в общем случае исключения перехватывать не нужно. Выясним основные причины такого подхода:

  1. Маскировка багов: Если код обернут в «пустую» попытку, программист никогда не узнает, что в логике допущена ошибка (например, обращение к пустому значению или деление на ноль).
  2. Неопределенное состояние: Программа продолжает выполнение с некорректными данными, что может привести к лавинообразному накоплению ошибок в базе данных.
  3. Сложность отладки: При возникновении реальной проблемы в будущем будет невозможно понять, где именно она зародилась, так как первичный стек вызовов был уничтожен в блоке исключения.

Критическая опасность в транзакциях

Разберем ситуацию, которая является фатальной для систем на базе 1С. Это использование Попытка...Исключение внутри транзакционных блоков. В 1С транзакция обладает свойством атомарности, и если внутри нее происходит любая ошибка уровня базы данных (например, нарушение уникальности индекса или блокировка), транзакция помечается платформой как «битая».

Проанализируем пример неправильного кода:


НачатьТранзакцию();
Попытка
    // Какое-то действие с БД
    Объект.Записать(); 
    ЗафиксироватьТранзакцию();
Исключение
    // Ошибка поймана, но транзакция уже пометилась как неисправная
    ЗаписатьВЖурналРегистрации("Что-то пошло не так, но работаем дальше");
    // Здесь НЕТ отмены транзакции и НЕТ проброса исключения выше
КонецПопытки;

В этом случае, если Объект.Записать() вызовет исключение, внешняя транзакция не будет отменена. Любая последующая попытка зафиксировать транзакцию или выполнить любое действие с БД приведет к системной ошибке «В данной транзакции происходила ошибка!». Это делает систему крайне нестабильной.

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


Попытка
    НачатьТранзакцию();
    // Логика работы
    ЗафиксироватьТранзакцию();
Исключение
    Если ТранзакцияАктивна() Тогда
        ОтменитьТранзакцию();
    КонецЕсли;
    // Обязательно фиксируем ошибку и пробрасываем её выше
    ЗаписатьВЖурналРегистрации("Критическая ошибка: " + ОписаниеОшибки());
    ВызватьИсключение; 
КонецПопытки;

Когда оправдано использование «везде»? Логирование и мониторинг

Существует современный тренд, упомянутый в обсуждении — логирование исключений в отдельный стек (например, с использованием систем типа Sentry, Crashlytics или специализированных расширений для 1С). В этом случае разработчики действительно могут оборачивать крупные блоки кода в try/catch, но не для того, чтобы «замолчать» ошибку, а чтобы:

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

Практический пример из недр БСП

Рассмотрим ситуацию, когда частичная обработка исключений полезна. В Библиотеке Стандартных Подсистем (БСП) часто встречается подход, когда процедура нижнего уровня обрабатывает данные (например, таблицу значений). Если на одном из этапов обработки конкретной строки возникает ошибка, она перехватывается, логируется, но выполнение процедуры продолжается для остальных строк. Это допустимо только в тех случаях, когда целостность всей системы не зависит от успеха этой конкретной подзадачи.

Итоговые рекомендации

Подводя итог нашему анализу, сформулируем правила здоровой обработки исключений:

  1. Не используйте Попытка...Исключение для скрытия ошибок. Если вы не знаете, что делать с ошибкой в блоке Исключение, не ловите её. Пусть она упадет и будет исправлена.
  2. Транзакции священны. Внутри транзакций всегда используйте ВызватьИсключение, чтобы не оставить базу в несогласованном состоянии.
  3. Логируйте с умом. Если вы внедряете систему логирования, убедитесь, что она сохраняет полный стек вызовов (используйте ПодробноеОписаниеОшибки() в 1С).
  4. Разделяйте типы ошибок. Пользовательские ошибки (неверный ввод) обрабатывайте условиями Если...Тогда. Системные сбои (сеть, права доступа) — через попытки.
  5. Глобальные обработчики. Вместо того чтобы писать Попытка в каждой функции, рассмотрите возможность использования глобального обработчика необработанных исключений (если платформа это позволяет, как в случае с Android или веб-сервисами).

Помните, что хороший код — это не тот код, который никогда не падает, а тот, который падает предсказуемо, понятно и не портит при этом данные пользователя.

← На главную