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