Персональный блог Игоря Антонова aka "spider_net"

1С:Предприятие 8. Адаптация типовых конфигураций без лишних сложностей. Применение механизма расширений на практике

1С:Предприятие 8. Адаптация типовых конфигураций без лишних сложностей. Применение механизма расширений на практике

Адаптация типовых решений от «» под требования заказчика чаще всего сопровождается сложностями. Вместе с новым функционалом, приходят проблемы дальнейшего сопровождения в виде трудностей установки обновлений от поставщика. Применение хорошо зарекомендовавших практик доработки решает проблему частично – как не старайся, а переопределить типовой код без снятия конфигурации с поддержки невозможно. Помочь справиться с надоевшей проблемой, призвана новая технология – механизм расширений.

В прошлом номере нашего журнала публиковалась статья «Правильная доработка типовых решений от 1С». В ней мы рассмотрели практики доработки типовых решений, позволяющих максимально сократить сложности с последующей установкой обновлений от поставщика. К сожалению, при глобальных доработках, затрагивающих основополагающие алгоритмы типового решения, предложенные методы не смогут полностью решить все проблемы.

Разработчику придется снимать конфигурацию с поддержки и вносить изменения напрямую, модифицируя типовой код. Единственный способ не потеряться в собственных изменениях – включить на полную катушку документирование и с помощью подручных технологий автоматизировать проверку возможности объединения серьезно переработанных участков. Шаг влево, шаг вправо и прощай выполненные изменения.

Особые сложности возникают при росте участков с изменениями типового кода. В моей практике адаптации типовой конфигурации «Бухгалтерия 2.0» изменения затрагивали десятки участков типового кода. Каждый процесс обновления требовал особой внимательности, чтобы не затереть наработки. Наиболее трудно сращивать изменения после серьезного рефакторинга кода со стороны поставщика. При сопровождении «молодого» типового решения проблемы сращивания кода доставляют особые проблемы. Поставщик активно меняет код и надо успевать подстраивать свои наработки.

Механизм расширений

Компания «1С», в курсе перечисленных выше проблем. Разработчики платформы потратили большое количество времени, чтобы привнести в систему новую технологию, способную решить наболевшие проблемы. Таким решением стал механизм расширений конфигурации.

Как и все новое, с момента первого релиза технология подвергалась переосмысливанию, доработкам и пересмотру функционала. За пару лет существования, концепт технологии устоялся, и сегодня ее можно применять без особого страха и рисков. Основные возможности прекрасно работают и прикладным разработчикам пора примять ее в проектах.

Перед тем как погрузиться в технические нюансы и рассмотрение практических примеров, давайте немного поговорим об общем механизме системы расширения конфигурации. Каким образом новая технология решает стек закоренелых проблемам?

Первая и важная особенность расширений – работа поверх стоковой конфигурации. Разработчику не требуется снимать конфигурацию поддержки. В контексте механизма расширений, необходимые доработки выносятся прямо в расширение. Технически расширение представляет из себя мини-конфигурацию, которая при подключении объединяется с основной.

Объединение выполняется автоматически сразу после подключение. Непосредственное подключение происходит прямо из режима «предприятие». Достаточно выбрать файл-расширение (*.cfe) и подключить его через менеджер расширений. Потребуется перезапуск предприятие и после него расширение будет готово к работе. Процесс подключения и активации расширения выполняется максимально прозрачно.

Механизм расширений практически полностью решает проблему сопровождения доработанных конфигураций. В идеальных случаях конфигурацию не требуется снимать с поддержки, и последующие обновления выполняются стандартным образом. После установки обновления от поставщика, добавленные расширения автоматически подключаться к обновленной информационной базе.

Как разработчика, вас никто не ограничивает в количестве расширений. Хотите – дробите функционал на отдельные расширения или держите доработки в одном. Главное придерживайтесь принципа – все расширения должны быть к место. Чрезмерное количество подключенных расширений может сыграть злую шутку и нанести урон производительности.

Хорошо, а что если поставщик конфигурации внесет глобальные изменения, подобно упомянутым выше – проведет серьезный рефакторинг кода? В этом случае фатального ничего не случится. Расширение просто перестанет работать, и вы сможете заняться адаптацией к новым требованиям.

Механизм расширений покрывает сценарии адаптации типовых решений, но важно запомнить, что расширение не является полноценной конфигурацией. Разработчик может создавать дополнительные объекты метаданных (в расширении), но перечень поддерживаемых для создания объектов ограничен. Не буду перечислять список поддерживаемых объектов (см. официальную документацию), скажу лишь, что в расширениях отсутствует возможность создания объекты для хранения информации. Добавить новый справочник или реквизит документа не получится.

Это одновременно ограничение и защита данных. Если разработчик имеет возможность создавать в расширении объекты для хранения информации, а потом расширение случайно отключается от информационной базы, то данные улетят в трубу, что не допустимо.

Хорошо, а как тогда быть, если доработка подразумевает ввода в конфигурацию дополнительных объектов метаданных (справочников, документов)? Снимать с поддержки? Нет, в этом случае активируется возможность внесения изменений (поддержка остается на месте), создаются новые объекты, а вот взаимодействие или переопределение типовых вещей выполняется в расширении. Схема работы расширений приведена на рисунке 1.

Рисунок 1. Схема работы расширений

Создаем первое расширение

Для создания нового расширения разработчику требуется воспользоваться менеджером расширений – «Конфигурация» -> «Расширения конфигурации». Открываем менеджер (см. рисунок 2).

Рисунок 2. Менеджер расширений в режиме

В окне менеджера вы можете управлять доступным расширениями (удалять, тестировать на возможность применения к конфигурации, выгружать в файлы и т.д.) и создавать новые.

Для создания расширения нажимаем кнопку «Добавить». В появившемся окне (см. рисунок 3) требуется заполнить:

  • Имя расширения. К именованию применяются стандартные правила именования новых метаданных объектов.
  • Синоним.
  • Префикс. Ко всем процедурам/функция добавляется указанный префикс. Префикс желательно выбирать исходя из контекста расширения.

Рисунок 3. Создание нового расширения

Двойной клик мышкой по расширению откроет дерево конфигурации расширения. В нем вы можете создавать новые объекты или помещать объекты основной конфигурации для последующего расширения. Последнюю операцию удобно выполнять через контекстное меню объекта метаданных в дереве рабочей конфигурации (см. рисунок 4).

Рисунок 4. Добавляем в расширение общий модуль

Далее выполняется стандартный цикл разработки – пишите бизнес-логику расширения и запускаете режим предприятие для тестирования. После завершения разработки, выполняется выгрузка (через менеджер расширений) расширения в файл («Конфигурация» -> «Сохранить конфигурацию в файл») и последующее подключение к рабочей базе. Подключение готового расширение реализуется в режиме предприятие («Все функции» -> «Стандартные» -> «Управление расширениями конфигурации»).

Расширяем модули

Переходим непосредственно к практической части и начнем рассматривать расширения в контексте модернизации модулей. Начиная с релиза 8.3.9, механизм расширений серьезно обновился и привнес новый функционал в работе с модулями. Разработчики получили возможность изменять любые типы модулей, определенные в конфигурации.

Функционал, направленный на расширение модулей покрывает задачи, которые раньше невозможно было решить без изменения. В расширении разработчик может создавать новые общие модули и самое главное переопределять существующие путем перехвата вызова функций/процедур (далее будем использовать слово «метод»). Переопределяемые методы могут вызывать: перед типовыми, после типовых или вместо типовых.

Рассмотрим практический кейс расширения модулей. Представим, в модуле «СуперМодуль» есть функция: РассчитатьСебестоимость(Товар). Не будем вдаваться в детали, мы знаем лишь, что она возвращает себестоимость переданного в качестве параметра товара. Поступает задача переделать функцию так, чтобы к себестоимости каждого товара добавлялась магическое число 100.

Проще всего задача решается добавление строчки кода в конец функции «РассчитатьСебестоимость()», но тогда в будущем на нас упадут все проблемы сопровождения. В контексте технологии расширения модулей задача сведется к переопределению функции «РассчитатьСебестоимость()» в новом расширении.

Порядок решения будет таким. Создаем новое расширение и через контекстное меню дерева конфигурации помещаем в него «СуперМодуль». Затем, в дереве конфигурации расширения переопределяем интересующий нас метод:

&Вместо(«РассчитатьСебестоимость»)
Функция ПрефиксРасширения_РассчитатьСебестоимость(Товар)
	Результат = ПродолжитьВызов(Товар);
	Возврат Результат + 100;
КонецФункции

Переопределяя в расширении типовой метод, в первую очередь мы должны определиться с вариантом его вызова. Порядок вызова описывается при помощи добавленных в язык препроцессора новых аннотаций:

  • &Вместо («ИмяПроцедуры/Функции»)
  • &После («ИмяПроцеудры/Функции»)
  • &Перед («ИмяПроцедуры/Функции»)

В примере выбор был сделан в пользу аннотации «&Вместо». Таким образом, после применения расширения, типовой метод «РассчитатьСебестоимость» становится «мертвым». Вместо него всегда будет вызываться наша реализация. На практике это представляет опасную ситуацию, поскольку мы ставим крест на возможных обновлениях реализации оригинального метода. Применять полное перекрытие стоит только в крайних случаях.

Поскольку полное перекрытие несет ряд ненужных сложностей, в теле метода я объявляю переменную и присваиваю в нее результат выполнения функции «ПродолжитьВызов(Товар)». Эта встроенная функция передаст управление оригинальному методу, и результат выполнения запишется в переменную «Результат». Получив результат выполнения оригинальной функции, выполняем прибавление числа 100.

Модифицировать результат требуется далеко не всегда. Например, при необходимости проведения документа по новому регистру, подойдет переопределение метода с аннотацией «После». В этом случае сначала отработает оригинальный код, а потом вызовется наша процедура. Механизм расширения модулей прекрасно подходит как для адаптации решений, так и для создания экстренных заплаток (кейс рассмотрим ниже).

Модернизация форм

Теперь взглянем, как выглядит процедура модернизации типовых форм посредством расширений. Для демонстрации примера я возьму документ «НачислениеЗарплаты» типовой конфигурации «Бухгалтерия некредитной финансовой организации КОРП» (вы можете повторить на любом другом) и доработаю основную форму.

Согласно техническому заданию, необходимо вывести на форму значение нового реквизита «КомиссияАгента» и добавить команду, автоматизирующую заполнение в табличной части колонки «Дата выплаты».

Создаем новое расширение и переносим в него основную форму документа «НачисленияЗарплаты». Помимо интересующей нас формы, в дерево конфигурации расширения попадут связанные сущности (документы, справочники и т.д.). На них не стоит обращать внимание (таков принцип работы расширений). Нас интересует форма документа, которую надо немного доработать.

Рисунок 6. Конфигурация нового расширения

Я вынес на форму отображение необходимого реквизита (КомиссияАгента) и добавил команду – «Проставить дату оплаты». Чтобы не запутаться в создаваемых элементах, каждому сразу присваивается префикс в виде наименования организации. Например, «ИмяОрганизации_КомиссияАгента», «ИмяОрганизации_ВыполнитьПростановкуДатыОплаты».

Обратите внимание на маленькую особенность. Если в оригинальной форме не было ссылок на некоторые реквизиты объекта, то они не автоматически не перенесутся в расширение. Их придется добавлять в ручную таким же образом, как и форму. Только после этой операции реквизит будет доступен для закрепления в форме расширения.

При модификации сложных форм (содержащих большое количество реквизитов разного типа), в дереве конфигурации расширения начнет твориться легкий бардак в виде появившихся огромного числа ссылок на объекты конфигурации. Чтобы не затеряться в нем, воспользуйтесь кнопкой «Измененные и добавленные в расширение» на панели инструментов дерева окна конфигурации (см. рисунок 7).

Рисунок 7. Управление видимостью измененных объектов

Команды формы создаются стандартным способом. В примере я добавляю одну новую команду «Проставить дату оплаты» и в обработчики события пишу код:

&НаСервере
Процедура НЗА_ДальЖАСО_ПроставитьДатуВыплатыПередНаСервере()
	
	Для Каждого ЭлементНачисления Из ОБъект.Начисления Цикл		
		ЭлементНачисления.ПланируемаяДатаВыплаты = ДальЖАСО_ДатаВыплаты;		
	КонецЦикла;		
	
	Модифицированность = Истина;
	
КонецПроцедуры

В модуле формы расширения вы видите только свой код. Программный код из оригинальной формы не переносится, но ваш код выполняется в контексте модуля оригинальной формы. Все методы формы, описанные в конфигурации поставщика, доступны из расширения.

Рисунок 8. Модуль формы расширения

Рисунок 9. Результат расширения формы

Если при изменении формы требуется переопределить логику обработчиков существующих элементов, то следует применять уже разобранный процесс перехвата методов. Принцип тот же, но тип вызова указывается не аннотацией, а в конструкторе обработчика.

На практике это процесс выглядит следующим образом. Переходите в инспекторе свойств команды (например, «Заполнить») и нажимаете на кнопку определения обработчика. Перед вами должно отобразиться диалоговое окно (см. рисунок 10) с вопросом выбора контекста исполнения обработчика (клиент, сервер) и типа вызова.

Рисунок 10. Определяем порядок вызова обработчика

Тип вызова позволяет задать порядок выполнения переопределяемого обработчика. Варианты аналогичны доступным аннотациям: перед, после и вместо.

Рисунок 11. После создания обработчика формы

После создания обработчика, в инспекторе свойств (см. рисунок 12) появится дополнительная иконка, отражающая порядок исполнения переопределённого обработчика события.

Расширение как заплатка

Само слово «расширение» заставляет воспринимать технологию как средство для модернизации типового функционала. Не нужно загонять себя в рамки и откидывать альтернативные идеи применения расширений. Одним из интересных кейсов использования технологии расширений – создание заплаток.

Вычистить полностью код от ошибок сложно и как обычно, они возникают в самых неожиданных местах. Разработчики привыкли ругать программистов «1С» за многочисленные баги в типовых конфигурациях, но не все отдают себе отчет в масштабности проекта и размеру кодовой базы.

Ошибки всегда имеют место быть и далеко не всегда заплатки от поставщика приходят оперативно. Что делать в таких случаях? Самый верный вариант – откатиться на предыдущую версию. Только сделать это удается не всегда. Ошибка может долго не проявляться, а возникнуть при выполнении регламентных операций.

Например, представим, что после очередного обновления возникла ошибка в документе начисления заработной платы. Если обновление с ошибкой появилось после ежемесячного начисления заработной платы, то о проблеме узнают только к следующему расчету зарплаты. За это время информационная база полнится данными и просто так, без их потери, откатиться к резервной копии не получится.

В таких ситуациях, механизм расширений может сослужить хорошую службу. Ничего не мешает вам создать новое расширение и внести в него исправление ошибок типового механизма, получив тем самым своеобразную заплатку. Вы останетесь со всеми свежими изменениями и примените элегантный патч на код, содержащий ошибки. Как только разработчики выпустят официальное исправление, потребуется просто отключить временное расширение.

Озвученная методика будет актуальна не только для разработчиков, занимающихся сопровождением типовых решений, но и тем, кто занят в разработке собственных решений. Если вы выпустили обновление с проблемной функцией, которой пользуется только несколько ваших клиентов, то возможно проще будет поставить лично им заплатки, чем выкатывать новый релиз и принуждать к обновлению остальных.

Расширение как плагин

Компания «1С» пока не спешит агитировать разработчиков в создании полноценных тиражных решений на основе механизма расширений, мотивируя молодостью технологии и не совсем подходящей архитектурой. Несмотря на это, уже сейчас вполне реально применять технологию расширений для создания небольших универсальных плагинов.

Безусловно, проблемы тиражирования имеет место быть (как правило, речь идет об организационных моментов), но во многих случаях они решаемы. Я долго думал над примером для демонстрации кейса универсального расширения. Мне в голову не пришло ничего лучше, чем разработка плагина, проверяющего уникальность контрагентов при записи. Если в базе существует контрагент с таким же ИНН, то плагин запретит запись.

Создаем новое расширение стандартным способом. Затем, добавляем в него форму элемента справочника «Контрагенты». Проверку на дубли будем выполнять в интерактивном режиме, т.е. во время взаимодействия пользователя с формой справочника. Для реализации защиты от дублей, нам требуется расширить обработчик события формы «ПередЗаписью».

Создаем для расширяемой формы обработчик события «ПередЗаписью» и в качестве типа вызова выбираем «Вызывать перед обработчиком из расширяемого модуля». В теле обработчика пишем код из листинга 1.

Листинг 1. Запрещаем запись дублированных контрагентов

ЭтоФизическоеЛицо = Объект.ЮридическоеФизическоеЛицо = ПредопределенноеЗначение("Перечисление.ЮридическоеФизическоеЛицо.ФизическоеЛицо");
	
Если (Объект.ИННВведенКорректно И Объект.КППВведенКорректно) ИЛИ
         (Объект.ИННВведенКорректно И ЭтоФизическоеЛицо) Тогда 
		
КоличествоДублейКонтрагентов = ВыполнитьПоискДублейСервер(Объект.ИНН, Объект.КПП, Объект.Ссылка);	
		
Если КоличествоДублейКонтрагентов > 0 Тогда			
Отказ = Истина;			
ТекстСообщенияПользователю = СтрШаблон("В справочнике ""Контрагенты"" существуеют элементы с таким ИНН/КПП - %1/%2.							|Запись элемента не может быть выполнена.", Объект.ИНН, Объект.КПП);
	
ПоказатьПредупреждение(, ТекстСообщенияПользователю);			
  КонецЕсли;
КонецЕсли;

Перед записью элемента мы выполняем проверку на корректность введенных ИНН и КПП. Причем мы ставим два условия – в первом проверяем пару ИНН + КПП, а во втором ИНН и признак физического лица. Если условие выполняется, то приступаем к поиску дублей.

Сам алгоритм поиска дублей мы не реализовываем – пользуемся готовой функцией «ВыполнитьПоискДублейСервер». Но где описана данная функция? Она описана в модуле оригинальной формы, к которому мы можем обратиться исходя из правила контекста.

Результатом выполнения функции «ВыполнитьПоискДублейСевере» будет число – количество обнаруженных дублей. Если оно больше нуля, то в базе есть уже контрагент с введёнными ИНН/КПП и запись надо пресекать (Отказ = Истина), не забыв при этом известить пользователя.

Код расширения получился достаточно простым, но наглядно продемонстрировал легкость и практическую пользу применения расширений в виде плагинов. Плагин получился универсальным и его без особо труда легко подключить к похожей типовой конфигурации.

Рисунок 12. Тест расширения запрета записи контрагентов с дублями

Слабые стороны

Механизм расширений привносит в процедуру адаптации типовых решений новые богатые возможности и изменяет устоявшиеся правила игры. Доработать конфигурации становится проще и новый функционал не препятствует последующей поддержки типового решения.

Как у любой технологии, у механизма расширений есть минусы. Первый и самый весомый – технические ошибки. Технология новая, затрагивает множество участков платформы и ошибки имеют место быть. Их немного, они правятся от релиза к релизу, но они есть. По опыту использования механизма расширений еще с версии «8.3.6» могу сказать, что в «8.3.9» проблем стало значительно меньше. Именно с этого релиза мы начали применять механизм расширений в рабочем окружении.

Второй важный минус – дополнительная сложность доработки конфигураций с большим количеством подключенных расширений. Пока нет никаких встроенных средств, позволяющих понять, какое из расширений переопределяет метод оригинальной конфигурации. Из-за неготовности внутреннего инструментария, могут возникать трудности при изучении механизма работы уже применяемых в базе расширений.

Третий весомый минус кроется в режиме совместимости. Я говорил, что самые интересные нововведения механизма расширений появились в последних версиях платформы. Так вот, чтобы воспользоваться ими, необходимо соблюсти условие - расширяемая конфигурация не должна работать в режиме совместимости с более ранними версиями.

В противном случае, придется выбирать: довольствоваться функционалом механизма расширений, актуальным для версии совместимости или самовольно его снимать. Типовые конфигурации в этом плане медлительны и многие только недавно перешли на режим совместимости с 8.3.8.

Вместо заключения

Можно долго рассуждать о сильных и слабых сторонах механизма расширений, но так или иначе, уже сейчас эта технология позволяет решить ряд исторически проблем. Не все разработчики охотно ее встречают: есть замечания к недоработкам концепции, и общей сырости технологии. Все это временные трудности.

Механизм расширений стоит применять уже сегодня, чтобы завтра быть готовым к новым правилам адаптации типовых решений. «» взяла строгий курс на развитие этой технологии. Следовательно, разработчики прикладных решений, в обозримом будущем получат еще больше возможностей бесшовной доработки функционала типовых решений.

Статья опубликована в журнале "Системный администратор" (http://samag.ru/). Март 2017 г.

Исходник расширения "Запрет дублирование контрагентов"

P.S. В мая 2017 года я выступал на конференции ha1s с одноименным докладом. Запись доклада и презентацию можно посмотреть здесь.

Оставьте комментарий!
comments powered by HyperComments