" в 1С. Анализ читаемости, производительности и лучших практик написания условных операторов. Рекомендации по использованию отрицаний в коде для улучшения его понятности и поддержки."> " в 1С. Анализ читаемости, производительности и лучших практик написания условных операторов. Рекомендации по использованию отрицаний в коде для улучшения его понятности и поддержки.">
В процессе разработки и поддержки кода на 1С часто возникают споры о стиле написания. Один из таких вечных вопросов: какой способ проверки на неравенство лучше — использовать оператор <> или конструкцию НЕ ... = ...? На первый взгляд, это мелочь, но она напрямую влияет на читаемость, а следовательно, на скорость понимания и поддержки кода. Разберемся, можно ли считать использование НЕ в таких случаях антипаттерном.
Основная проблема, с которой сталкиваются программисты, — это сложность восприятия. Мозг при беглом чтении кода может попросту "пропустить" частицу НЕ, стоящую в начале длинного условия.
Посмотрим на пример из реального кода, который вызвал обсуждение:
// Вариант 1: с "НЕ"
Если НЕ СтруктураТаблицДокумента.ТаблицаУслуги = Неопределено тогда
// ... делаем что-то
КонецЕсли;
// Вариант 2: с "<>"
Если СтруктураТаблицДокумента.ТаблицаУслуги <> Неопределено тогда
// ... делаем что-то
КонецЕсли;
Во втором варианте условие считывается как единое целое: "если таблица услуг не равна Неопределено". В первом же варианте приходится выполнять мысленную операцию: сначала прочитать "СтруктураТаблицДокумента.ТаблицаУслуги = Неопределено", получить результат (Истина или Ложь), а затем инвертировать его с помощью НЕ. Это требует больше умственных усилий и замедляет понимание, особенно в сложных, вложенных условиях.
Главный аргумент против НЕ ... = ... — это ухудшение читаемости. Проанализируем основные причины:
НЕ и знак равенства = находятся в разных частях выражения. При быстром просмотре кода взгляд легко может пропустить отрицание, что приведет к неверному толкованию логики.НЕ ЭтоНеГруппа заставляют мозг "зависать" и требуют дополнительного времени на расшифровку.НеВключатьВЧек) в сочетании с оператором НЕ порождает код, который сложно понять: Если НЕ НеВключатьВЧек Тогда.... Этого следует избегать, используя позитивные формулировки (например, ИсключитьИзЧека или антоним ВключитьВЧек).Вывод: В простых сравнениях оператор <> является единым, визуально целостным и интуитивно понятным символом неравенства, что делает код более читаемым и менее подверженным ошибкам.
Иногда можно услышать аргумент, что конструкция с НЕ выполняется быстрее. Это утверждение, как правило, является мифом, уходящим корнями в особенности работы старых платформ. Проведенные тесты на миллионе операций показывают, что разница в скорости выполнения между этими двумя конструкциями ничтожно мала и находится в пределах погрешности.
// Текст замера Количество Время, с
Если НЕ Сч = ПроверочноеЧисло Тогда 1 000 001 1,169575
Если Сч <> ПроверочноеЧисло Тогда 1 000 001 1,164398
Разница в 5 тысячных секунды на миллионе итераций не может служить основанием для выбора в пользу менее читаемого варианта. Современные платформы 1С достаточно хорошо оптимизируют оба подхода. Выбирать синтаксис на основе микрооптимизаций в ущерб читаемости — плохая практика.
Несмотря на все вышесказанное, существуют ситуации, где оператор НЕ не только уместен, но и является лучшим выбором.
Конструкции вида Если НЕ МойФлаг или Если НЕ ЗначениеЗаполнено(Переменная) являются стандартными идиомами в программировании. Они легко читаются и не вызывают затруднений.
Если НЕ ЭтоГруппа Тогда
// Логика для элемента справочника
КонецЕсли;
Если НЕ Отказ Тогда
Записать();
КонецЕсли;
В этих случаях НЕ применяется к простому утверждению и воспринимается естественно.
Иногда проще и понятнее инвертировать целую группу условий, чем применять отрицание к каждому ее элементу. Это особенно полезно, когда условие в скобках представляет собой единую бизнес-логику.
Сравним два эквивалентных примера:
// Вариант 1: с "НЕ" перед скобкой. Читается как "Если НЕ (это списание в долг ИЛИ в подарок)"
Если НЕ (Объект.ВидОперации = Перечисления.ВидыОперацийСписания.ВДолг
ИЛИ Объект.ВидОперации = Перечисления.ВидыОперацийСписания.ВПодарок) Тогда
// ...
КонецЕсли;
// Вариант 2: без "НЕ"
Если Объект.ВидОперации <> Перечисления.ВидыОперацийСписания.ВДолг
И Объект.ВидОперации <> Перечисления.ВидыОперацийСписания.ВПодарок Тогда
// ...
КонецЕсли;
В данном случае первый вариант может быть более читаемым, так как он явно выделяет группу исключаемых операций. Выбор здесь зависит от контекста, но возможность использовать НЕ для инвертирования блока условий — полезный инструмент.
Обсуждение НЕ часто выявляет более глубокую проблему — чрезмерно сложные логические условия в коде. Если условие трудно прочитать, дело может быть не только в операторе отрицания.
Рассмотрим пример сложного для восприятия условия:
Если Не ТребуетсяУказаниеДопДанных
И ЗначениеЗаполнено(ПараметрыСканирования.ДокументОснование)
И Не ЗначениеЗаполнено(ДанныеШтрихкода.Серия)
И ДанныеДокументаОснования <> Неопределено Тогда
// ...
КонецЕсли;
Такой код заставляет вчитываться, анализировать несколько отрицаний и связей. Лучшим решением здесь будет рефакторинг — вынесение сложной проверки в отдельную функцию с "говорящим" названием.
// Код после рефакторинга
Функция ТребуетсяПоискСерииВДанныхОснования(ПараметрыСканирования, ДанныеШтрихкода, ДанныеДокументаОснования)
Возврат Не ТребуетсяУказаниеДопДанных // Предполагается, что это параметр функции
И ЗначениеЗаполнено(ПараметрыСканирования.ДокументОснование)
И Не ЗначениеЗаполнено(ДанныеШтрихкода.Серия)
И ДанныеДокументаОснования <> Неопределено;
КонецФункции
// ... основной код ...
Если ТребуетсяПоискСерииВДанныхОснования(ПараметрыСканирования, ДанныеШтрихкода, ДанныеДокументаОснования) Тогда
// ...
КонецЕсли;
После рефакторинга основной код становится самодокументируемым. Мы читаем не набор логических операций, а осмысленное действие, что значительно упрощает понимание и дальнейшую поддержку.
<>. Эта конструкция однозначна, визуально целостна и не требует дополнительных умственных усилий для понимания. Использование НЕ ... = ... в этих случаях является плохой практикой, ухудшающей читаемость.НЕ для отрицания булевых переменных и функций. Это стандартный и легко читаемый прием (Если НЕ Выполнено).НЕ для инверсии целых логических блоков, если это делает код понятнее (НЕ (Условие1 ИЛИ Условие2)).Если разрастается и его становится трудно понять, выносите его в отдельную функцию с ясным, осмысленным названием.Код пишется один раз, а читается многократно. Инвестиции в читаемость и простоту всегда окупаются в долгосрочной перспективе, снижая время на поддержку и количество потенциальных ошибок.