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