В процессе разработки и сопровождения систем на платформе 1С:Предприятие часто возникает задача временного или условного отключения определенных блоков кода. Традиционный путь — создание новой константы или реквизита в справочнике — не всегда приемлем, так как это влечет за собой изменение структуры метаданных, необходимость монопольного доступа к базе при обновлении и потенциальные сложности при поддержке типовых конфигураций. В этой статье мы подробно разберем, как реализовать механизмы управления логикой приложения («Feature Toggles»), используя только существующие инструменты платформы.
Одним из самых простых и эффективных способов хранения флагов без изменения метаданных является использование системного объекта ХранилищеОбщихНастроек. Этот механизм предназначен для хранения произвольных данных в разрезе пользователей или системы в целом. Мы можем записывать туда логическое значение (истину или ложь) и считывать его в коде перед выполнением критичного блока.
Рассмотрим пример записи настройки, который можно выполнить в любой обработке или через консоль кода:
// Записываем значение флага "ОтключитьПроверкуЛимитов"
ХранилищеОбщихНастроек.Сохранить("ПараметрыСистемы", "ОтключитьПроверкуЛимитов", Истина);
Теперь проанализируем, как проверить это условие непосредственно в том месте, где нужно ограничить выполнение кода. Важно помнить, что обращение к хранилищу — это чтение из базы данных, поэтому для оптимизации производительности такие проверки лучше кэшировать в повторно используемых модулях или параметрах сеанса.
НужноЛиОтключать = ХранилищеОбщихНастроек.Загрузить("ПараметрыСистемы", "ОтключитьПроверкуЛимитов");
Если Не НужноЛиОтключать = Истина Тогда
// Здесь располагается основной код, который мы хотим иметь возможность отключить
ВыполнитьПроверкуОстатков();
КонецЕсли;
Если по каким-то причинам работа с хранилищем настроек неудобна, можно прибегнуть к методу создания «элемента-семафора». Мы выбираем любой технический или редко используемый справочник (например, Справочник.КлассификаторЕдиницИзмерения или специализированный справочник настроек, если он уже есть в конфигурации) и создаем там элемент с уникальным наименованием или кодом.
Разберем логику: наличие элемента или определенная пометка в его наименовании будет служить сигналом для кода. Посмотрим на программную реализацию такой проверки:
Функция ФункционалОтключен()
// Ищем элемент по предопределенному имени, которое не встретится у обычного пользователя
ЭлементСемафор = Справочники.ДополнительныеОтчетыИОбработки.НайтиПоНаименованию("DEBUG_DISABLE_INTEGRATION");
Возврат Не ЭлементСемафор.Пустая();
КонецФункции
// Использование в коде
Если Не ФункционалОтключен() Тогда
ОтправитьДанныеВУчетнуюСистему();
КонецЕсли;
Преимущество данного метода заключается в том, что управлять включением и выключением кода может администратор системы прямо в пользовательском режиме, просто переименовывая или удаляя этот элемент.
Это наиболее современный и рекомендуемый подход. Расширения позволяют модифицировать поведение системы, не затрагивая основную конфигурацию. Если нам нужно «выключить» процедуру, мы можем создать расширение и перехватить выполнение метода с помощью аннотации &Вместо.
Рассмотрим, как это выглядит. Допустим, у нас есть процедура РассчитатьСложныеНалоги() в общем модуле. Чтобы ее отключить, мы создаем в расширении метод-заглушку:
&Вместо("РассчитатьСложныеНалоги")
Процедура Расш1_РассчитатьСложныеНалоги_Вместо()
// Мы просто оставляем тело процедуры пустым.
// Основной код оригинальной конфигурации не будет выполнен.
ЗаписьЖурналаРегистрации("Внимание", УровеньЖурналаРегистрации.Предупреждение, , , "Выполнение расчета налогов пропущено через расширение.");
КонецПроцедуры
Преимущество здесь в том, что расширение можно подключать и отключать в списке «Управление расширениями», что мгновенно меняет логику всей базы данных без сеанса «Конфигуратора».
Если ваша конфигурация разработана на базе Библиотеки стандартных подсистем (БСП), мы можем использовать механизм «Дополнительных сведений». Этот механизм позволяет добавлять свойства к объектам без изменения метаданных (данные хранятся в общем регистре сведений).
Выясним, как это реализовать. Мы можем добавить дополнительное сведение к узлу информационной базы или к конкретной организации. Программа будет считывать значение этого сведения. Поскольку это штатный механизм БСП, он предоставляет удобный интерфейс для редактирования этих флагов.
// Пример получения значения дополнительного сведения
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДополнительныеСведения.Значение КАК Значение
|ИЗ
| РегистрСведений.ДополнительныеСведения КАК ДополнительныеСведения
|ГДЕ
| ДополнительныеСведения.Объект = &Объект
| И ДополнительныеСведения.Свойство = &Свойство";
Запрос.УстановитьПараметр("Объект", Справочники.Организации.НайтиПоРеквизиту("ИНН", "0000000000"));
Запрос.УстановитьПараметр("Свойство", ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("ИспользоватьНовыйАлгоритм"));
Результат = Запрос.Выполнить();
// Далее ветвим логику на основании результата
В некоторых случаях удобно хранить само условие или даже фрагмент кода во внешнем текстовом файле или в текстовом макете внутри базы. Это позволяет менять логику «на лету».
Проанализируем ситуацию: мы можем создать общий макет типа «Текст» и поместить туда структуру настроек в формате JSON. При старте системы или выполнении операции код считывает макет и интерпретирует его.
ТекстНастроек = ПолучитьОбщийМакет("НастройкиИнтеграции").ПолучитьТекст();
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(ТекстНастроек);
Настройки = ПрочитатьJSON(Чтение);
Если Настройки.ВключитьНовыйМеханизм Тогда
Выполнить(Настройки.ТекстВыполняемогоКода);
КонецЕсли;
Важно: использование функций Выполнить() и Вычислить() требует осторожности с точки зрения безопасности, чтобы исключить возможность инъекции произвольного кода пользователями.
Мы рассмотрели несколько подходов к управлению кодом без изменения метаданных. Подведем итоги, выбрав лучшие практики для разных ситуаций:
&Вместо — это самый чистый и технологичный метод.ХранилищеОбщихНастроек является оптимальным балансом между простотой реализации и производительностью.Выбор конкретного метода зависит от архитектуры вашей конфигурации и того, насколько часто предполагается переключать данные флаги.