Каждый разработчик на платформе «1С:Предприятие» рано или поздно сталкивается с динамическим кодом. Использование функций Выполнить() или Вычислить() незаменимо, когда алгоритм должен формироваться на лету, настраиваться пользователем в режиме «1С:Предприятие» или загружаться из внешних источников (например, при обмене данными). Однако в процессе разработки возникает серьезная проблема: как только выполнение доходит до динамической строки, отладчик просто «пролетает» ее насквозь. Зайти внутрь этой строки стандартным шагом (клавишей F11) невозможно.
В этой статье мы подробно разберем, почему платформа ведет себя именно так, и проанализируем все существующие способы отладки динамического кода — от простых «кустарных» методов до профессиональных инструментов, которыми пользуются эксперты.
Давайте выясним техническую причину этого ограничения. Чтобы конфигуратор 1С мог остановить выполнение программы на определенной строке и показать ее разработчику, ему необходим физический или виртуальный скомпилированный модуль, жестко привязанный к метаданным или файлу на диске. В этот момент конфигуратор сопоставляет исполняемый байт-код с номерами строк в текстовом редакторе.
Когда мы передаем строку в функцию Выполнить(), платформа компилирует и выполняет этот код динамически «в оперативной памяти». Для этого фрагмента не создается постоянного модуля, у него нет физического адреса или файла на диске, к которому отладчик мог бы привязать точку останова (брейкпоинт). Поэтому прямой вход отладчиком в строку, исполняемую через Выполнить(), в платформе «1С:Предприятие» технически невозможен.
Тем не менее, у нас есть целый арсенал обходных путей. Рассмотрим их по шагам от простых к продвинутым.
Это самый очевидный и простой способ, который часто применяется «на скорую руку». Если динамический код хранится в переменной или константе, мы можем временно перенести его в реальный модуль конфигурации.
Рассмотрим этот процесс по шагам:
Выполнить(КодСТипомСтрока).КодСТипомСтрока и вставляем его как обычный код 1С внутрь нашей временной процедуры.Выполнить() временно пишем вызов нашей новой процедуры.Посмотрим на пример. Было:
// Динамический код, который невозможно отладить
КодСТипомСтрока = "РезультатТаблицы = Запрос.Выполнить().Выгрузить();";
Выполнить(КодСТипомСтрока);
На время отладки мы преобразуем это в следующий вид:
// Временно закомментировали динамический вызов
// Выполнить(КодСТипомСтрока);
// Вызываем временную процедуру отладки
Тест_ОтладкаКода();
А в конце модуля определяем саму процедуру, где ставим точку останова на строке с запросом:
Процедура Тест_ОтладкаКода()
// Сюда мы скопировали динамический код
РезультатТаблицы = Запрос.Выполнить().Выгрузить(); // <-- Сюда ставим точку останова (F9)
КонецПроцедуры
Минусы метода: если динамический код активно использует локальный контекст (переменные исходной процедуры), вам придется передавать все эти переменные в параметры временной процедуры, что бывает крайне трудоемко при большом количестве связей.
Если код небольшой, а переносить его в процедуру не хочется, можно пойти по классическому пути логирования. Мы можем модифицировать динамическую строку так, чтобы она сама сообщала нам промежуточные значения переменных в процессе выполнения.
Для этого внутрь исполняемого текста внедряются вызовы функций Сообщить() или запись в журнал регистрации через ЗаписьЖурналаРегистрации().
Например, если у нас выполняется цикл, мы можем модифицировать строку кода следующим образом:
КодСТипомСтрока = "Для Каждого Стр Из Таблица Цикл " +
" Сообщить(""Обработка строки: "" + Стр.Номенклатура); " +
" Стр.Цена = Стр.Цена * 1.1; " +
"КонецЦикла;";
Выполнить(КодСТипомСтрока);
Этот способ незаменим, когда отладка происходит на рабочей базе (продуктивной среде), где останавливать процесс точками останова категорически нельзя, но нужно понять, на каком этапе ломается алгоритм.
Если динамический код в вашей системе — это не разовое решение, а регулярно изменяемый бизнес-алгоритм (например, формулы расчета скидок, правила заполнения реквизитов), лучшей практикой будет полный отказ от хранения этого кода в виде строк в базе данных.
Вместо этого мы рекомендуем вынести этот алгоритм в экспортный метод общего модуля (или в расширение конфигурации, если вы работаете с типовой конфигурацией и не хотите снимать ее с поддержки).
Как это реализовать:
дф_ДинамическиеАлгоритмы) с флагами «Сервер», «Вызов сервера».Выполнить() оставляем только вызов этой процедуры.Посмотрим на пример реализации:
// В базе данных вместо огромного куска кода храним только одну строчку вызова:
КодСТипомСтрока = "дф_ДинамическиеАлгоритмы.ВыполнитьРасчетСкидки(ПараметрыАлгоритма);";
Выполнить(КодСТипомСтрока);
Сам алгоритм теперь находится в конфигураторе:
Процедура ВыполнитьРасчетСкидки(ПараметрыАлгоритма) Экспорт
// Здесь находится весь сложный код
// Мы можем без проблем поставить точку останова на любой строке ниже!
Для Каждого СтрокаТовара Из ПараметрыАлгоритма.ТабличнаяЧасть Цикл
СтрокаТовара.Скидка = СтрокаТовара.Сумма * 0.05;
КонецЦикла;
КонецПроцедуры
Преимущества: Полная поддержка отладчика, проверка синтаксиса при компиляции, высокая скорость работы и безопасность решения.
Иногда нам не нужно отлаживать сам динамический код по шагам, но нам крайне необходимо выполнить произвольный код прямо в момент остановки на точке останова, чтобы посмотреть, как изменятся данные, или быстро проверить гипотезу.
В штатном режиме окно «Вычислить выражение» (Shift + F9) в 1С не умеет выполнять многострочные конструкции или присвоения (например, Объект.Отказ = Истина там написать нельзя — возникнет ошибка синтаксиса).
Для обхода этого ограничения мы можем создать универсальную функцию-обертку в любом глобальном или общем модуле конфигурации:
Функция ДУ(Код, П1 = Неопределено, П2 = Неопределено) Экспорт
Выполнить(Код);
Возврат П1;
КонецФункции
Теперь, когда вы стоите на любой точке останова в программе, вы можете открыть окно Табло (Ctrl + Alt + W) или Вычислить выражение (Shift + F9) и написать там вызов вашей функции, передав код строкой:
ДУ("П1.Отказ = Истина", ЭтотОбъект)
В данном случае функция выполнит код, который изменит свойство Отказ у переданного объекта ЭтотОбъект (который внутри функции привязан к параметру П1), и вернет измененный объект обратно в табло. Это дает мощный инструмент интерактивной отладки «на лету».
Этот способ отлично знаком тем, кто работал с правилами обмена в «Конвертации данных 2.0». Там обработчики событий пишутся в виде текста, но при выгрузке/загрузке их нужно как-то отлаживать.
Суть метода заключается в программном создании временного файла внешней обработки:
.epf).ВыполнитьАлгоритм()).ВнешниеОбработки.Создать() и вызывает этот метод.Чтобы отладить такой код, разработчику достаточно сделать паузу в коде (например, через окно предупреждения или точку останова перед вызовом обработки), зайти в каталог временных файлов, открыть сгенерированную обработку в Конфигураторе, расставить в ней точки останова и продолжить выполнение в предприятии. Отладчик успешно перехватит выполнение внутри модуля внешней обработки!
Если вы хотите заниматься разработкой и отладкой на профессиональном уровне, рекомендуем использовать мощный бесплатный пакет программ «Инструменты разработчика» (автор TormozIT).
В его состав входит специализированная Консоль кода, которая умеет выполнять пошаговую отладку динамических алгоритмов.
Выполнить().ирОбщий.От()) вы можете сделать снимок (дамп) всего текущего контекста и значений переменных.Несмотря на то, что прямого способа войти отладчиком в Выполнить() в платформе 1С не существует, мы рассмотрели множество альтернативных путей решения этой задачи:
Выбирайте наиболее подходящий под ваши задачи метод и делайте вашу разработку в 1С быстрой и комфортной!