Структура статьи:
- Цель
- Концепция
- Объекты системы без четкого описания методики изменения
- Методики
Сразу оговорюсь, что изменение конфигурации по описанной ниже методике более трудоемка, но время, потраченное на этапе разработки с лихвой окупается при последующих обновлениях.
ЦЕЛЬ
Модификация конфигурации, находящейся на поддержке, с возможностью последующего «быстрого обновления».
КОНЦЕПЦИЯ ИЗМЕНЕНИЙ
- Минимальная правка кода в модулях конфигурации. Все требуемые изменения нужно выносить в общие модули или модули менеджеров новых объектов (справочников / регистров / обработок), логически связанных с вносимыми изменениями.
- Отказ от «непосредственного» изменения текстов запросов. Касается как запросов расположенных в текстах модулей, так и запросов-источников динамических списков.
- Отказ от изменения форм объектов на уровне конструктора форм. Использование только программного (при помощи написанного кода) способа. Речь идет не только о добавлении/изменении элементов форм, но и о добавлении реквизитов форм, событий элементов форм (и самой формы) и условного оформления форм.
- Максимальное использование подписок на события.
ОБЪЕКТЫ СИСТЕМЫ БЕЗ ЧЕТКОГО ОПИСАНИЯ МЕТОДИКИ ИЗМЕНЕНИЙ
- Изменение ролей
- Изменение функциональных опций
- Изменение состава реквизитов
- Изменение состава регистраторов
- Изменение состава общих команд
- Изменение схем компановки данных
МЕТОДИКИ
- Комментарии к изменениям. Считается хорошим тоном, а в случае изменения модуля, находящегося на поддержке являются обязательными комментарии с открывающимися и закрывающимися «тегами» к программному коду который вы внесли/модифицировали. Обычный минимум – это дата изменения и «ФИО» разработчика. Плюсом будет номер тикета или краткое описание изменений.
- Минимальная правка кода в модулях конфигурации. Руководствуемся «достаточным» минимумом изменений. Конечно, если Ваши изменения в объеме 1-3 строки, то не стоит для этого их выносить в отдельный модуль. В случае если код «большой» или он используется в нескольких местах, выносим его из тела модуля.
Все вызовы функций/процедур воспринимаем как некий «черный ящик» у которого есть параметры/источники данных (передаваемые или общие) на вход и результат на выходе. Если мы можем изменить входные параметры таким образом, чтобы «метод» вернул нам требуемый результат – меняем входные параметры (передаем их в нашу процедуру/функцию) и там их переопределяем. Если есть возможность изменить/дополнить данные на выходе – вызываем наш метод после. В случае невозможности «подменить» входные/выходные параметры принимаем решение: либо разбираемся-«осветляем» ящик и ищем «точку входа» в нем, либо пишем свой метод взамен текущего.
Результаты запросов, если есть сложность и нецелесообразность менять сам запрос (см. методику модификации запроса ниже) тоже можно переопределить/дополнить, выгрузив его в таблицу значений и потом в качестве источника модифицировать в своем запросе.
Если есть некая конструкция кода с условиями и циклами, результат которого вам «не подходит» после нее напишите свой и «переопределите» результат. Нужно ли комментировать исходный код зависит от его ресурсоемкости. Желательно его оставить «как есть».
Свои процедуры и функции можно располагать в новых общих модулях или менеджерах Ваших новых объектов. К примеру, если Вы создали справочник «Номенклатура клиентов» и в печатных формах Вам нужно модифицировать запрос таким образом чтоб вместо артикула номенклатуры компании выводился артикул клиента – процедуру модификации запроса целесообразней расположить именно в модуле менеджера справочника «Номенклатура клиентов».
По возможности стараемся не менять обработчики событий форм. О переопределении обработчиков событий, их «отключении» без модификации самих обработчиков и формы см. в разделе «Отказ от изменения форм объектов на уровне конструктора форм»
3. Отказ от «непосредственного» изменения текстов запросов. Часто используемым подходом к изменению текста запросов является «непосредственное» изменение запроса с закомментированными в нем «исходными» блоками. Основной недостаток такого подхода – при случайном или необдуманном использовании конструктора запросов «слетают» комментарии и «куски» закомментированного запроса от поставщика конфигурации. Другой способ – копирование и модификация исходного запроса целиком в своей процедуре и последующая подстановка нового запроса. В этом случае при обновлении конфигурации есть необходимость сверять запросы м/у собой – новый от поставщика старый от поставщика и измененный разработчиком. Причем, так как нужно сравнивать уже 3 текста, делать это приходится не средствами 1С, а сторонними программами, к примеру - KDiff3.
Предлагаемый подход направлен на сохранение первоначального текста запроса и «точечной» его модификации. Для этого находим требуемые задачей «точки входа» и функцией СтрЗаменить() меняем исходный текст запроса – вставляем необходимые условия, соединения, выбираемые поля. Небольшой пример для понимания (пример надуманный и очень простой, но помогает понять вышеописанный принцип):
ТекстЗапроса = «
|ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура»;
Нам нужно ограничить выборку записями, имеющимися в некотором регистре сведений и вывести некоторые значения из этого регистра
Добавим внутреннее соединение
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, «
| Справочник.Номенклатура КАК Номенклатура», «
| Справочник.Номенклатура КАК Номенклатура
|ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДляПримера КАК Пример
| ПО Номенклатура.Ссылка = Пример. Номенклатура»);
Вынесем в результат требуемые поля
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, «
| Номенклатура.Ссылка КАК Ссылка,», «
| Номенклатура.Ссылка КАК Ссылка,
| Пример.Поле1 КАК Поле1,
| Пример.Поле2 КАК Поле2»);
Таким образом, мы, сохраняя исходный текст на поддержке, при изменении его поставщиком (без кардинальных изменений), можем гарантировать обновление запроса поставщика без обдумывания наших изменений.
Немногим более сложна модификация предложенным способом пакетного запроса. Как вы уже догадались, пакетный запрос – это набор «одиночных» запросов. Нам остается разобрать пакет на отдельные запросы, изменить/подменить конкретный (ые) и собрать пакет запросов обратно. В УТ11 есть замечательные функции для этого «СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок()» и «СтроковыеФункцииКлиентСервер.ПолучитьСтрокуИзМассиваПодстрок()». Делителем строк будет являться символ «;».
Для динамических списков текст запросов меняем аналогично. В случае если динамический список использует реальную таблицу – меняем настройки динамического списка и подставляем текст запроса:
.УстановитьТекстЗапросаДинамическогоСписка_ЗаказНаПеремещениеСписок(Список);
Процедура УстановитьТекстЗапросаДинамическогоСписка_ЗаказНаПеремещениеСписок(Список) Экспорт
Список.ПроизвольныйЗапрос = Истина;
Список.ТекстЗапроса
= "ВЫБРАТЬ
| ЗаказНаПеремещение.Ссылка, ……
4. Отказ от изменения форм объектов на уровне конструктора форм. По моему мнению, самым проблемным в обновлении измененных конфигураций – это обновление форм. Решение, позволяющее упростить эту задачу – менять форму программным способом, т.е. использовать динамическое/программное изменение состава, отображения, поведения формы.
На программном создании элементов форм особо останавливаться не стоит, так как примеров и механизмов написано достаточно. Нужно только выбрать подходящий для себя. Я писал свой. Список добавляемых элементов хранится в макете. Вызов процедуры общего модуля происходит в процедуре ПриСозданииНаСервере(). При таком подходе я добавляю новые реквизиты в модифицируемый объект, прописываю вызов процедуры динамического создания элементов и добавляю в макет описание добавляемого реквизита. На все уходит не более 5 минут.
Реквизиты формы (те что нужны на форме только на момент ее существования и не должны храниться в базе) тоже создаю программно. Подход аналогичный подходу, используемый при создании элементов форм. При этом динамически созданный реквизит может являться источником (прописанным в пути) для динамического элемента формы.
Условное оформление тоже доступно для модификации программно. На момент написания статьи я еще не разработал более-менее внятного механизма по его «настройке» и просто прописываю в виде куска кода (конечно же, с вызовом в общем модуле).
Динамическое переопределение и добавление обработчиков событий формы.
Зачастую при модификации форм Вам, к примеру, на событие ПриИзменении нужно «добавить» обработку события. Обычно мы в форме определяем вызов метода «ПриИзменении» и уже в теле созданной процедуры описываем поведение. В этом случае при обновлении конфигурации у нас «распознаются» не только изменения модуля формы, но и изменения самой формы.
Мною разработан модуль «динамически подключаемых обработчиков событий» элементов форм и самих форм со следующим функционалом:
- Добавление обработчика события
- Удаление обработчика события
- Переоределение обработчика события с возможностью вызова оригинального обработчика до, после, либо возможность его отключить.
На практике на момент написания данной статьи мною разрабатывается конфигурация для крупной торговой компании, занимающейся поставкой инструментов, на базе УТ11. Формы справочников и основных документов товарооборота и планирования сильно доработаны. Добавлены реквизиты шапки, табличных частей, вычисляемые реквизиты форм, добавлены и переопределены обработчики событий форм и реквизитов. Блокируются строки в табличных частях товаров и многое другое. Всего не описать. Примечательно, что при всех этих изменениях в модулях измененных форм всего несколько вызовов процедур в процедуре «ПриСозданииНаСервере» и в случае динамически подключаемых событий по одному «шаблону-процедуре» на событие.
Данная статья не предполагает детального описания разработанного вышеуказанного механизма. В случае здорового интереса к нему готов написать отдельную статью с детальным описанием и выложить исходники с примерами использования модуля по созданию динамических реквизитов, элементов и подключаемых обработчиков.
5. Максимальное использование подписок на события. Собственно если есть возможность использовать подписку на событие – используйте.