В практике разработки на платформе 1С:Предприятие перед каждым программистом регулярно встает дилемма: каким образом корректно прервать выполнение алгоритма, если данные не прошли проверку или возникла внештатная ситуация? Традиционно мы используем два механизма: установку параметра Отказ в значение Истина в обработчиках событий или прямое инициирование исключения через ВызватьИсключение. Несмотря на то, что в обоих случаях результат для пользователя часто выглядит похожим — операция отменяется, — механизмы их работы, последствия для транзакций и влияние на пользовательский опыт существенно различаются.
Рассмотрим подробнее каждый из подходов, проанализируем их сильные и слабые стороны, а также разберем ситуации, в которых один метод предпочтительнее другого.
Параметр Отказ — это стандартный способ платформы 1С сообщить системе, что текущую операцию (запись, проведение, удаление) выполнять не следует. Установка этого параметра в значение Истина не прерывает выполнение кода в ту же секунду. Процедура дорабатывает до конца, и только после выхода из нее платформа анализирует значение переменной.
Разберем основные преимущества этого метода:
Отказ = Истина в сочетании с объектом СообщениеПользователю позволяет вывести список всех ошибок сразу. Если у документа не заполнены три реквизита, мы можем проверить их все, сформировать три сообщения и в конце установить Отказ = Истина. Пользователь увидит все замечания одновременно, исправит их и сохранит документ.СообщениеПользователю, мы можем указать свойство Поле. В этом случае на форме 1С некорректно заполненное поле подсветится красным, а сообщение станет «кликабельным» — при нажатии на него курсор автоматически переместится в нужное место.Отказ = Истина позволяет нам зафиксировать ошибку для одного объекта и спокойно перейти к обработке следующего, не прерывая весь процесс работы алгоритма.Проанализируем пример кода в обработчике ПередЗаписью:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если Не ЗначениеЗаполнено(Организация) Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не заполнена организация!";
Сообщение.Поле = "Объект.Организация";
Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Сообщить();
Отказ = Истина;
КонецЕсли;
Если Не ЗначениеЗаполнено(Склад) Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не указан склад отгрузки!";
Сообщение.Поле = "Объект.Склад";
Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Сообщить();
Отказ = Истина;
КонецЕсли;
// Если Отказ стал Истина, выполнение кода продолжится,
// но по завершении процедуры платформа отменит транзакцию записи.
КонецПроцедуры
Оператор ВызватьИсключение действует иначе. Он мгновенно прерывает выполнение текущего блока кода и начинает поиск ближайшего обработчика Попытка...Исключение вверх по стеку вызовов. Если такого обработчика нет, выполнение программы полностью прекращается, а пользователю выводится модальное окно с текстом ошибки.
Выясним причины, по которым этот метод считается «агрессивным» для бизнес-логики:
Однако существуют ситуации, где ВызватьИсключение — это единственный правильный выбор:
СообщениеПользователю может не дойти до клиента. Использование ВызватьИсключение гарантирует, что задание перейдет в статус «Ошибочно», а текст ошибки будет записан в Журнал регистрации.Один из самых важных технических моментов касается управления транзакциями базы данных. Рассмотрим ситуацию, когда мы вызываем исключение внутри блока Попытка...Исключение, который в свою очередь находится внутри открытой транзакции (например, в обработке проведения).
Важное правило: если внутри транзакции произошло исключение, эта транзакция помечается платформой как «битая» (непригодная для фиксации). Даже если вы «поймали» ошибку в блоке Исключение и решили не пробрасывать её дальше, попытка зафиксировать транзакцию в конце приведет к фатальной ошибке: «В данной транзакции уже происходили ошибки!».
Посмотрим на пример неправильной обработки:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
НачатьТранзакцию();
Попытка
// Некий код, который вызывает исключение
ВызватьИсключение "Ошибка записи во внешнюю систему";
Исключение
// Ошибка поглощена, выполнение продолжается
ЗаписатьСобытиеВЖурналРегистрации("Ошибка", УровеньЖурналаРегистрации.Ошибка);
КонецПопытки;
// При выходе из процедуры или вызове ЗафиксироватьТранзакцию()
// произойдет падение системы, так как транзакция помечена как ошибочная.
КонецПроцедуры
В случае с Отказ = Истина такой проблемы не возникает. Платформа сама корректно и «чисто» откатит транзакцию после завершения кода процедуры, не оставляя систему в неопределенном состоянии.
Проанализируем ситуацию с точки зрения ресурсов сервера. Генерация исключения — это тяжелая операция. Она требует от сервера 1С сбора информации о стеке вызовов (какие функции вызывались до момента ошибки). В высоконагруженных системах, где проверки документов срабатывают тысячи раз в час, массовое использование исключений может создавать лишнюю нагрузку на процессор.
Что касается логирования, то здесь есть преимущество у ВызватьИсключение: такие события автоматически попадают в Журнал регистрации с уровнем «Ошибка». Для событий типа Отказ = Истина разработчик должен самостоятельно прописывать вызов ЗаписатьСобытиеВЖурналРегистрации(), если он хочет видеть историю отказов в админ-панели.
Подводя итог, разделим зоны ответственности между этими двумя механизмами:
Используйте Отказ = Истина, если:
ПередЗаписью, ОбработкаПроведения, ПередУдалением).Используйте ВызватьИсключение, если:
Отказ через все уровни архитектуры неоправданно усложнит код.Помните, что качественный код в 1С — это не только правильные алгоритмы, но и забота о пользователе, который должен получать понятную и наглядную обратную связь от системы.