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