Какое условие лучше использовать в 1С: Если Документ.Организация = "тест" И Документ.Подразделение = "Тестовое подразделение" Тогда или вложенные Если Документ.Организация = "тест" Тогда Если Документ.Подразделение = "Тестовое подразделение" Тогда?

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

Когда мы, как разработчики 1С, сталкиваемся с необходимостью проверки нескольких условий для выполнения определенного действия, перед нами часто встает вопрос: какой синтаксис выбрать? Использовать ли единое условие с логическим оператором И, или же предпочесть вложенные операторы Если? Разберем эту ситуацию подробнее, чтобы понять, в чем заключаются различия, какие подходы предпочтительнее в разных случаях, и есть ли между ними фундаментальная разница.

Укороченная логика (Short-circuit evaluation) в 1С

Давайте начнем с одного из ключевых понятий, которое существенно влияет на выполнение логических выражений в 1С – это укороченная логика, или "short-circuit evaluation".

В платформе 1С 8.x (часто называемой "снеговиком") условия в логических выражениях вычисляются слева направо. Этот процесс останавливается сразу, как только результат всего выражения становится определенным.

  1. Для оператора И: Если первое условие (операнд) оказывается Ложь, то второе и все последующие условия не будут вычисляться. Ведь для того, чтобы выражение с И было Истина, все его части должны быть Истина. Если одна часть уже Ложь, то весь результат выражения однозначно Ложь, и дальнейшие проверки бессмысленны.
  2. Для оператора ИЛИ: Если первое условие (операнд) оказывается Истина, то второе и все последующие условия не будут вычисляться. Для того, чтобы выражение с ИЛИ было Истина, достаточно, чтобы хотя бы одна его часть была Истина. Если первая часть уже Истина, то весь результат выражения однозначно Истина, и дальнейшие проверки также бессмысленны.

Рассмотрим пример из практики, который наглядно демонстрирует полезность укороченной логики. Представим, что мы пишем условие, которое может привести к ошибке выполнения, если не будет применена укороченная логика:


Если (1 <> 1) И (1 / 0 = 0) Тогда
    Сообщить("Это сообщение никогда не появится");
КонецЕсли;

В этом примере, первое условие (1 <> 1) является Ложь. Благодаря укороченной логике, второе условие (1 / 0 = 0), которое могло бы вызвать ошибку деления на ноль, не будет вычисляться. В итоге, программа не выдаст ошибку, и блок кода внутри Если не будет выполнен.

Теперь проанализируем, как укороченная логика относится к нашим двум сравниваемым конструкциям:


// Вариант 1: С логическим оператором И
Если Документ.Организация = "тест" И Документ.Подразделение = "Тестовое подразделение" Тогда
    // Действие выполняется, если оба условия истинны
КонецЕсли;

// Вариант 2: С вложенными операторами Если
Если Документ.Организация = "тест" Тогда
    Если Документ.Подразделение = "Тестовое подразделение" Тогда
        // Действие выполняется, если оба условия истинны
    КонецЕсли;
КонецЕсли;

С точки зрения чистого выполнения условий и принятия решения о входе в "основной" блок кода, оба варианта ведут себя очень похоже благодаря укороченной логике. В первом случае, если Документ.Организация = "тест" будет Ложь, второе условие не проверится. Во втором случае, если Документ.Организация = "тест" будет Ложь, мы просто не войдем во внутренний Если, и второе условие также не проверится. Таким образом, в плане "вычисления всех операндов до конца", большой разницы не будет.

Ключевое различие: Обработка блока "ИНАЧЕ"

Фундаментальное и наиболее значимое различие между этими двумя подходами заключается в том, как мы можем обрабатывать ситуации, когда условия не выполняются, то есть в структуре и поведении блока ИНАЧЕ.

1. Вариант с логическим оператором И

При использовании конструкции Если ... И ... Тогда, у нас есть только один блок ИНАЧЕ. Этот блок сработает, если хотя бы одно из условий оказалось ложным.


Если Документ.Организация = "тест" И Документ.Подразделение = "Тестовое подразделение" Тогда 
    // Здесь выполняются действия, когда оба условия Истина
    Сообщить("Организация и подразделение корректны.");
ИНАЧЕ
    // Этот блок сработает, если Организация НЕ "тест"
    // ИЛИ если Подразделение НЕ "Тестовое подразделение"
    // (или оба условия ложны)
    Сообщить("Неправильная организация ИЛИ подразделение. Что-то не то.");
КонецЕсли;

В этом случае, если мы хотим сообщить пользователю, что именно не так, мы не сможем сделать это напрямую из блока ИНАЧЕ, не проведя дополнительные проверки внутри него. Мы получаем общее сообщение о том, что "что-то не то", но не можем точно указать, какое именно условие не выполнилось.

2. Вариант с вложенными операторами Если

В случае с вложенными операторами Если, мы получаем возможность иметь отдельные блоки ИНАЧЕ для каждого уровня условия. Это позволяет нам более точно реагировать на то, какое именно условие не выполнилось, и предоставлять более специфическую обратную связь или выполнять разную логику.


Если Документ.Организация = "тест" Тогда
    // Если организация корректна, проверяем подразделение
    Если Документ.Подразделение = "Тестовое подразделение" Тогда 
        // Здесь выполняются действия, когда оба условия Истина
        Сообщить("Организация и подразделение корректны.");
    ИНАЧЕ
        // Этот блок сработает только если Организация корректна,
        // но Подразделение НЕ "Тестовое подразделение"
        Сообщить("Неправильное подразделение.");
    КонецЕсли;
ИНАЧЕ
    // Этот блок сработает только если Организация НЕ "тест"
    Сообщить("Неправильная организация.");    
КонецЕсли;

Как мы видим, этот подход предоставляет гораздо большую гибкость. Мы можем четко разделить логику обработки ошибок или альтернативных сценариев в зависимости от того, на каком этапе условие перестало выполняться.

Оптимизация производительности: Стоит ли беспокоиться?

Часто возникает вопрос об оптимальности кода: какой из вариантов быстрее или требует меньше ресурсов? На форумах 1С нередко можно встретить совет: "Не занимайтесь преждевременной оптимизацией."

Для простых условий, как в нашем примере, разница в производительности между этими двумя конструкциями обычно минимальна, если не сказать несущественна. Современные компиляторы и интерпретаторы (включая платформу 1С) хорошо оптимизируют подобные логические операции. Укороченная логика работает одинаково эффективно в обоих случаях для определения того, нужно ли входить в основной блок кода.

Фокусироваться в первую очередь следует на читаемости, поддерживаемости и корректности работы кода, а не на микрооптимизациях, которые могут дать прирост в миллисекундах, но при этом усложнить понимание и отладку кода. Если только у нас нет доказательств, что именно этот участок кода является "узким местом" по производительности, нет смысла тратить время на его "выжимание" до максимума в ущерб понятности.

Читаемость и поддерживаемость кода: Что выбрать?

Выбор между двумя конструкциями часто сводится к вопросу читаемости и поддерживаемости кода.

  1. Для простых случаев и единого действия:

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

    
    // Коротко и понятно, если не нужна детализация ошибок
    Если Документ.Организация = "НашеПредприятие" И Документ.Проведен Тогда
        ОбновитьСтатусДокумента();
    КонецЕсли;
    

    Такой подход предпочтителен, когда "условие выполнения одно" и не требуется ветвление логики для каждого невыполненного подусловия.

  2. При необходимости разных действий для каждого условия:

    Если нам нужны разные действия или специфическая обратная связь в зависимости от того, какое из условий не выполнилось, вложенные Если с отдельными блоками ИНАЧЕ являются более подходящим вариантом. Они позволяют явно разделить логику обработки каждой ветки и предоставить пользователю или системе точную информацию о причине отказа.

    
    // Детализированная обработка ошибок
    Если Пользователь.Роль.Содержит("Администратор") Тогда
        Если ДатаДокумента > ТекущаяДата() Тогда
            Если СуммаДокумента > 0 Тогда
                // Выполняем действия администратора с будущим документом и положительной суммой
            ИНАЧЕ
                Сообщить("Сумма документа должна быть больше нуля!");
            КонецЕсли;
        ИНАЧЕ
            Сообщить("Дата документа не может быть в будущем!");
        КонецЕсли;
    ИНАЧЕ
        Сообщить("У вас недостаточно прав для выполнения этой операции.");
    КонецЕсли;
    

    Однако, здесь есть и обратная сторона: глубокая вложенность операторов Если может ухудшать читаемость кода и увеличивать его сложность (так называемая "цикломатическая сложность"). Статический анализ кода часто "наказывает" за каждый новый уровень вложенности, так как это затрудняет понимание нормального хода выполнения программы и усложняет отладку.

Принцип "защитных условий" (Guard Clauses)

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

Рассмотрим, как это работает на примере:


// Вместо глубокой вложенности:
Процедура ОбработатьДокумент(ДокументСсылка)
    Документ = ДокументСсылка.ПолучитьОбъект();

    Если Не ЗначениеЗаполнено(Документ) Тогда
        Сообщить("Документ не найден.");
        Возврат;
    КонецЕсли;

    Если Документ.Проведен Тогда
        Сообщить("Документ уже проведен.");
        Возврат;
    КонецЕсли;

    Если Документ.Дата < НачалоГода(ТекущаяДата()) Тогда
        Сообщить("Нельзя обрабатывать документы прошлых лет.");
        Возврат;
    КонецЕсли;

    // Если все защитные условия пройдены, переходим к основной логике
    // Код основной логики находится на более "плоском" уровне вложенности
    Сообщить("Документ успешно прошел все проверки, выполняем основную логику.");
    Документ.Записать();
КонецПроцедуры

Этот подход позволяет "спрямить" основной поток выполнения кода, делая его более линейным и понятным. Основная логика выполняется только тогда, когда все предварительные условия успешно пройдены.

Приоритет логических операций

Необходимо также помнить о приоритете логических операций в 1С при вычислении сложных логических выражений. 1С соблюдает стандартный порядок:

  1. Сначала вычисляется НЕ.
  2. Затем вычисляется И.
  3. В последнюю очередь вычисляется ИЛИ.

Для изменения порядка выполнения операций, а также для улучшения читаемости сложных выражений, всегда рекомендуется и нужно использовать круглые скобки. Например, Если (Условие1 И Условие2) ИЛИ Условие3 Тогда явно указывает на порядок выполнения, даже если он совпадает с приоритетом по умолчанию.

Булевы выражения

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


Перем РезультатПроверки;
РезультатПроверки = (Документ.Организация = "тест" И Документ.Подразделение = "Тестовое подразделение");

Если РезультатПроверки Тогда
    Сообщить("Все условия выполнены.");
Иначе
    Сообщить("Одно или несколько условий не выполнены.");
КонецЕсли;

Этот подход может быть полезен, когда нам нужно сохранить результат проверки для дальнейшего использования или передать его в другую функцию.

Заключительные рекомендации

Итак, давайте суммируем наши выводы и дадим конкретные рекомендации по выбору между двумя подходами:

  1. Используйте Если ... И ... Тогда:
    • Когда вам нужно выполнить одно действие, если все условия истинны.
    • Когда нет необходимости предоставлять специфические сообщения или выполнять разную логику для каждого невыполненного подусловия.
    • Когда код должен быть максимально лаконичным и простым для понимания "с первого взгляда".
    Этот подход идеален для большинства стандартных проверок, где достаточно общего сообщения об ошибке или отсутствии действия.
  2. Используйте вложенные Если ... Тогда Если ... Тогда:
    • Когда требуется разная логика выполнения или специфическая обратная связь (сообщения пользователю) в зависимости от того, какое именно из условий не выполнилось.
    • Когда каждое условие представляет собой отдельный этап проверки, и невыполнение каждого этапа требует уникальной обработки.
    Однако, будьте осторожны с глубокой вложенностью. Если условий очень много, рассмотрите возможность рефакторинга кода с использованием "защитных условий" (guard clauses) или выноса логики проверки в отдельные функции.

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

← На главную