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