Кодогенерация и метагенерация в 1С

В своем докладе на конференции INFOSTART EVENT 2024 EDUCATION Дмитрий Белозеров рассказал о разработке инструмента, позволяющего программно работать с метаданными 1С и писать скрипты для выполнения тех же действий, которые выполняет разработчик в конфигураторе –  с какими сложностями и нюансами пришлось столкнуться, и что получилось в итоге.

 

 

Здравствуйте, коллеги. Меня зовут Дмитрий Белозеров. Я работаю системным архитектором в компании LM Soft. Мы занимаемся внедрением систем проектного управления, управления жизненным циклом изделий и другими сложными и интересными решениями.

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

 

Что такое кодогенерация?

 

 

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

 

 

Но в самой идее, которая заложена в основе, нет ничего особо нового. 

 

 

Если вы в поисковике напишите слово «кодогенерация», то можете найти на эту тему много хороших статей и видео, в том числе и на русском языке – в последнее время я видел на YouTube несколько классных докладов по кодогенерации от разработчиков из мира Java, .NET, Swift и т.д.

Но надо понимать, что наша 1С – это достаточно специфическая среда разработки, и все эти практики требуют некоторой адаптации под особенности платформы.

 

 

Давайте сначала дадим определение, что такое кодогенерация. Это – очень широкое понятие:

  • Когда вы просто пишите код в конфигураторе, вы тоже в каком-то смысле занимаетесь кодогенерацией. 

  • Или, когда, например, вы в «Конвертации данных 3.0» пишите правило, а потом на его основе формируете код на языке 1С, это тоже кодогенерация. 

  • Или, например, когда вы заходите на сайт Facebook или ВКонтакте, то в этот момент тоже выполняется кодогенерация – весь Web2.0 технически основан на кодогенерации.

  • Но в нашем случае кодогенерация – это когда одна программа на языке высокого уровня пишет другую программу на языке высокого уровня. Я буду говорить сегодня именно об этом. 

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

После такого определения, я думаю, у вас должен возникнуть вопрос – зачем такие сложности? Зачем генератор? Зачем код на исходном языке?

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

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

  • Расширяете состав определяемого типа;

  • Включаете объект в состав подписки на событие;

  • Добавляете какую-то строчку в модуль формы, еще что-то. 

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

 

 

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

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

 

 

Если выражаться на языке бизнеса, то получается, что кодогенерация – это способ:

  • Во-первых, уменьшить себестоимость разработки;

  • А во-вторых, увеличить качество продукта.

 

 

Примеры применения кодогенерации для 1С

 

 

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

Первый, наиболее понятный пример – это наш программный продукт, MDM-система (от английского Master Data Management), с помощью которой мы управляем нормативно-справочной информацией. Фактически это конфигурация на платформе 1С, которая содержит большое количество справочников. Причем, все эти справочники обладают общей функциональностью – возможность поиска дублей, нормализации и т.д. По сути, они разные, но однотипные. 

 

 

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

 

 

В какой-то момент мы решили, что так больше жить нельзя, и реализовали собственный инструмент, который позволил выполнять эту работу автоматически. 

Как теперь выполняется разработка нашей MDM-системы?

  • У нас есть «ядро MDM» – некий набор общих механизмов, некая базовая конфигурация, в которой нет справочников НСИ, но есть некий эталонный справочник. 

  • Дальше есть Jinnee (джинн) – мы так назвали наш кодогенератор, который:

    • Берет эталонный справочник, копирует его;

    • Изменяет его необходимые свойства – добавляет нужные реквизиты, выводит их на форму;

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

Соответственно, если мы вносим изменения в ядро – мы можем перегенерировать конфигурацию еще раз, и все эти изменения туда попадут.

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

 

 

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

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

Получается «умный Continuous Integration» – именно интеграция на уровне кода, когда машина сама знает, что, куда и как нужно внести.

 

 

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

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

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

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

 

 

Следующий возможный кейс – это то, к чему мы все придем в ближайшее время – разработка через моделирование. 

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

Как я это вижу? 

  • У нас есть некая модель. Мы реализуем ее в любом редакторе, в любой нотации, в которой хотим.

  • Следующим шагом мы выгружаем эту модель в формат XML. 

  • Полученный результат конвертируем в Jinnee-сценарий. 

  • И этот Jinnee-сценарий, полученный на основе модели, используя некие библиотеки, выдает на выходе готовую конфигурацию.

Дальше я покажу, как это у нас реализовано. Я надеюсь, что так будет понятнее. 

 

 

Основные принципы проектирования инструмента

Но перед тем как я буду показывать сам инструмент, я расскажу о трех основных принципах, которые мы закладывали при его проектировании.

 

 

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

Почему это важно? Потому что писать код, который напишет за вас код, экономически выгодно только в том случае, если его написание не занимает у нас много времени. 

Например, если вы написали скрипт на 100 строк, который вам сгенерировал 1000 строк, вы сэкономили время и исключили риски человеческого фактора – это хорошо.

Но чтобы сэкономить это время, сам псевдоязык, на котором вы пишете скрипт для генерации, должен быть для разработчика максимально простым – в случае с 1С идеально было бы использовать родной 1С-ный синтаксис. Только в этом случае такая разработка становится экономически выгодной. Иначе можно и не начинать.

 

 

Второй принцип – это правильный выбор уровня абстракции. Что это означает? Дело в том, что наш инструмент работает на уровне XML. Это означает, что:

  • У нас есть исходный набор XML-файлов (мы выгрузили конфигурацию из конфигуратора в XML);

  • Что-то там с этими XML-ками программно сделали;

  • А потом их загрузили в конфигуратор и получили готовую конфигурацию.

Так вот, вся эта программная модификация XML не должна сильно напрягать разработчика. Разработчик не должен думать, как это реализовано на уровне XML. Например, чтобы изменить имя объекта метаданных, нужно внести изменения в нескольких местах XML-файла. Зачем разработчику это знать? Он просто напишет «ИзменитьСвойствоОбъектаМетаданных(<Имя>, <Значение>)».

Получается, что в нашем случае разработчик может мыслить именно в терминах объектов метаданных. Он вообще не знает, как это устроено с точки зрения XML, он делает то, что делал бы сам в конфигураторе руками. 

В этом есть и другие плюсы – если XML-формат выгруженных файлов изменится (а такое периодически бывало и с форматом конфигуратора, и с форматом EDT), нам не придется переписывать наши уже написанные скрипты.

 

 

Третий архитектурный паттерн, который мы применили, я назвал «Сыктывкар». Объясню почему. 

Пять лет назад я ездил в командировку в этот северный город, и тот район, где нас разместили, был очень печальный. И когда поздно ночью один мой коллега сказал: «У меня сигареты закончились, давайте сходим, купим», другой, более опытный коллега, который уже пожил в Сыктывкаре и знал, насколько этот район криминально опасный, ответил ему: «Тут за сигаретами нужно ходить с сигаретами». 

Перефразируя эти слова применительно к нашему случаю – разрабатывая инструментарий 1С, нужно использовать инструментарий 1С.

Примеров такого подхода тоже много – это Конвертация данных, АПК, Инструменты разработчика. Разработчики, используя платформу 1С, уже существенно облегчили себе жизнь.

 

 

Работа с инструментом на практике

 

 

Перейдем к самому инструменту – рассмотрим, как он выглядит. 

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

 

 

Перейдем к правилу, посмотрим, как оно устроено. 

Принцип реализации правила независимо от используемой платформы всегда примерно один и тот же:

  • берется некий шаблон;

  • неким образом модифицируется;

  • и получается итоговый результат. 

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

 

 

В результате, при переходе на соседнюю вкладку у нас получится вот такой сценарий. Причем, обратите внимание – в сценарии есть один и тот же объект (имя объекта метаданных одинаковое), но команды разные. Это означает, что мы можем переносить как объекты метаданных в отдельности, так и подсистему целиком.

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

 

 

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

Как я уже говорил, мы старались максимально упростить работу с инструментом, чтобы разработчик мог там что-то описать, просто мысля в терминах метаданных, – изменить какие-то объекты, добавить реквизит, добавить табличную часть и т.д. 

На текущий момент у нас написано 84 правила (84 скрипта). Это уже достаточно большая кодовая база.

 

 

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

  • ИзменитьСвойствоОбъектаМетаданных; 

  • ПолучитьСвойствоОбъектаМетаданных;

  • ДобавитьЭлементФормы;

  • УдалитьЭлементФормы. 

Принцип, я думаю, понятен.

 

 

Разберем одну из этих функций. 

Как на практике происходит программная модификация объекта метаданных? 

  • Мы пишем «ИзменитьСвойствоОбъектаМетаданных()»;

  • В качестве первого параметра передаем полное имя изменяемого объекта – это у нас определяемый тип ВладелецФайлов;

  • Далее указываем, какое свойство этого объекта мы хотим изменить, и какое значение ему присвоить. 

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

 

 

Расскажу про возможность параметризации правила. Что это значит? 

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

  • Одно и то же правило;

  • Один и тот же алгоритм, по которому все должно задаваться;

  • Но в этот алгоритм нужно было как-то передать данные – с каким именем, с каким атрибутным составом, с какими свойствами мы должны создать справочник. 

Соответственно, у правила есть возможность задать некие параметры, которые потом при настройке сценария можно будет заполнить, и дальше, при выполнении сборки они будут передаваться на вход правила. 

На слайде можно увидеть пример настройки такого правила и то, как при настройке сценария в него передаются значения параметров.

 

 

Версионирование правил при помощи Git

 

 

Расскажу про версионирование. Почему у нас вообще возникла необходимость версионирования?

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

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

  • У нас есть некая серверная часть – база, где хранятся общие данные, 

  • И есть клиентская часть – именно клиент является средой разработки правила. 

  • Но само правило в базе вообще не хранится, оно хранится в XML-файле под версионированием Git. Самая ближайшая аналогия – это EDT. 

В результате получается, что правила хранятся вместе с основным кодом и версионируются тоже вместе с основным кодом, и точно так же отправляются на CodeReview. Примерно такая архитектура у нас сейчас реализована.

 

 

Проблемы и их решения

 

 

Чтобы начать этим пользоваться, нужно было все это пережить и разрулить проблемы. У нас это получилось не сразу. Расскажу про самые интересные проблемы, с которыми мы столкнулись. 

Первое – это проблема ссылочной целостности. Когда вы забираете в вашу конфигурацию какую-то подсистему из БСП, вы не задумываетесь о том, что ваши объекты метаданных имеют ссылки друг на друга, потому что, когда вы их переносите, конфигуратор эти проблемы автоматически решает – он удаляет ссылки на несуществующие объекты, если такие есть. Но в случае, если мы сами манипулируем XML-файлом, никто за нас этого не сделает. Поэтому, когда мы пытались загрузить нашу конфигурацию из XML-файлов, то получали вот такую простыню ошибок. 

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

 

 

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

Для этого мы в нашем инструменте реализовали механизм, который сохраняет уже сгенерированные идентификаторы. Это решило проблему.

 

 

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

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

 

 

Роль кодогенератора в решении архитектурных проблем

 

 

Тут стоит задуматься вот о чем. Если вы решили пойти по пути модульной разработки, когда у вас есть подсистемы, которые собираются и изменяются с помощью какого-то инструмента, вы должны решить ряд архитектурных проблем, ответить себе на вопрос: «Как мне проектировать мои механизмы, чтобы они были отчуждаемые, встраиваемые и т.д.?»

И сейчас на следующем слайде мы увидим ответ, как наш кодогенератор решает эти архитектурные проблемы.

 

 

Никак он их не решает. Что вы хотели? Но это, наверное, и хорошо. Иначе, зачем мы были бы нужны?

Этим я просто хочу подчеркнуть, что необходимость грамотного проектирования никуда не делась. Скорее, наоборот, она встает еще более остро.

 

 

Заключение

 

 

И еще один архитектурный антипаттерн, который тоже нужно учитывать – называется «Золотой молоток». Это – когда разработчик освоил какую-то крутую технологию, и она ему настолько сильно понравилась, что он начинает ее использовать везде. Даже там, где это нецелесообразно. Поэтому помните, что любая технология имеет границы применимости и подходить к её использованию нужно с позиции здравого смысла и экономической целесообразности.

Два слова о том, как мы видим дальнейшее развитие инструмента. Во-первых, это реализовать поддержку формата EDT. Интересно было бы научит Jinnee парсить код на языке 1С и формировать AST-tree (хотя у нас большой потребности в этом не было, но это могло бы открыть новые интересные возможности). Есть много идей по развитию внутреннего инструментария, а также хочется попробовать реализовать конвертацию моделей в jinnee-сценарии, т.е. приблизится к разработке через моделирование.

 

 

Ну и напоследок, приведу реальную цитату с Инфостарта, которую прочитал в одном из обсуждений. Оказалось что идея подобного инструмента была не только у нас:

 

 

****************

Данная статья написана по итогам доклада, прочитанного на конференции INFOSTART EVENT 2024 EDUCATION. Больше статей можно прочитать здесь.

В 2024 году приглашаем всех принять участие в 7 региональных митапах, а также юбилейной INFOSTART EVENT 2024 в Москве.

Выбрать мероприятие.

28 Comments

  1. user-z99999

    Jinnee — в тексте повторяется 6 раз.

    Как скачать?

    Примеры как использовать?

    Платно/бесплатно ?

    Reply
  2. VmvLer

    (1) Львиная доля статей-докладов не более чем маркетинг а ля

    «конкретно мы вам ничего не скажем, просто покажем вам картинки чтобы вы поняли какие мы крутые и купили у нас услуги, товары и т.п.»

    Reply
  3. for_sale

    (1)

    Очередная статья из серии «Смотрите, как мы умеем!»

    Reply
  4. nytlenc

    Все мне пора в отпуск. Прочитал как «Кодогенерация и матогенерация в 1С»…

    Reply
  5. kirovsbis

    (1)

    Jinnee — в тексте повторяется 6 раз.

    Не считал, но верю Вам на слово 🙂


    Как скачать?

    Примеры как использовать?

    Платно/бесплатно ?

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

    Reply
  6. kirovsbis

    (2)

    конкретно мы вам ничего не скажем, просто покажем вам картинки чтобы вы поняли какие мы крутые

    Хотелось бы больше конкретики в претензиях на отсутствие конкретики 🙂 Статья всё-таки написана по итогам 30-минутного доклада, в котором полноценно раскрыть тему невозможно при всём желании. Целью было донести до слушателей саму идею, плюсы-минусы, реальные кейсы применения технологии, рассказать кратко про сам инструмент и возможные проблемы использования. Если тематика интересна — могу более подробно рассказать в следующих статьях о том как оно работает, как организован сам процесс разработки, каких архитектурных принципов стараемся придерживаться при разработке, как реализуем модульность на практике.

    Reply
  7. user-z99999

    (5)

    Выложите инструмент, дайте попробовать.

    Научите в нём работать. Простые примеры, создание справочников.

    Если вы продаете, так и пишите — распространение на платной основе.

    Reply
  8. VmvLer

    (6) Моя реплика — это общий взгляд на современные презентации.

    Reply
  9. kirovsbis
    Выложите инструмент, дайте попробовать.

    Научите в нём работать. Простые примеры, создание справочников.

    Выложу, как только подготовлю версию, которую не стыдно выложить 🙂 Про планируемые сроки уже написал.

    Если вы продаете, так и пишите — распространение на платной основе.

    С моделью распространения ещё не определились, поэтому пока не знаю что ответить на этот вопрос.

    Reply
  10. Darklight
    Reply
  11. sikuda

    А я то и не знал что пишу кодогенератор php1c.ru 😉

    Reply
  12. kirovsbis

    (10)

    Спасибо за содержательный комментарий!

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

    Пример:

    Есть объект метаданных, например определяемый тип. Если мы зайдем в конфигуратор и в дереве метаданных выберем наш определяемый тип, а затем откроем окно свойств (Alt + Enter), то увидим существующие свойства объекта. Некоторые будут «простыми» — например «Имя» или «Синоним», другие «сложными» (или составными) — например «Тип», но всё равно это СВОЙСТВА объекта метаданных. Поэтому независимо от того меняем ли мы синоним или добавляем новый тип в состав определяемого типа (или наоборот удаляем тип из состава) мы фактически изменяем одно из свойств объекта метаданных.

    Полное описание функции «ИзменитьСвойствоОбъектаМетаданных» выглядит так:

    ИзменитьСвойствоОбъектаМетаданных(<Полное имя объекта метаданных>, <Имя свойства>, <Добавляемое значение>, <Удаляемое значение>)

    Разработчик подает на вход функции имя объекта метаданных и имя свойства, а инструмент соответственно на основе этих данных понимает как правильно интерпретировать третий или четвертый параметр.

    Примеры использования функции

    Сделаем справочник иерархическим:

    ИзменитьСвойствоОбъектаМетаданных(«Catalog.ПримерСправочника»,»Hierarchical»,»true»);

    Добавим новый тип в состав определяемого типа (именно добавим новый, не трогая уже включенные в состав, «изменить» это не то же самое что «заменить»):

    ИзменитьСвойствоОбъектаМетаданных(«DefinedType.ВладелецФайлов», «Type», «CatalogRef.ПримерСправочника»);

    А можем и сразу несколько типов добавить:

    МассивТипов = Новый Массив;
    МассивТипов.Добавить(«CatalogRef.ПримерСправочника1»);
    МассивТипов.Добавить(«CatalogRef.ПримерСправочника2»);
    ИзменитьСвойствоОбъектаМетаданных(«DefinedType.ВладелецФайлов», «Type», МассивТипов);
    Reply
  13. kirovsbis

    (11)

    Наверное правильнее это транслятором назвать

    Reply
  14. Darklight
    Reply
  15. PerlAmutor

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

    Reply
  16. Darklight
    Reply
  17. Darklight

    (15)Абсолютно верно — я уже тоже давно пришёл к тому, что в будущем такой подход продажи будет очень оправдан — платишь ровно за то, что тебе нужно — и не получаешь ничего лишнего в нагрузку — соответственно конфигурация легче — понятнее и быстрее!

    Ну а нужно потом что-то ещё — так докупаешь и быстренько интегрируешь в свою систему!

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

    Reply
  18. kirovsbis

    (10)

    Ну и как развитие данной тем — нужно присваивать исходным метаданным маркеры, на которые можно было бы опереться при кодогенерации — и дальше, например, решать включать или не включать это метаданное (или его часть) в итоговое решение, ну или как-то иначе модифицировать — т.е. оперировать уже не конкретными элементами метаданных — а некими общими признаками. Например, присвоив маркер «ЕстьОрганизация» как справочнику «Организация» (условно), так и измерениям регистров, и реквизитам документов «Организация», а также блокам программного кода, обращающимся к этим метаданным — то в зависимости от настройки — ведения учета по разным организациям — можно выкинуть все эти элементы из итоговой конфигурации, тем самым снизив её сложность — а значит повысив эффективность её исполнения платформой и СУБД.

    Покажу на примере как мы решаем этот вопрос.

    Допустим у нас есть некая «Подсистема1», которая содержит «Документ1» (причем реквизита «Организация» у этого документа изначально нет).

    Мы написали «Правило1», которое переносит «Подсистему1» из исходной конфигурации в результирующую.

    А ещё есть «Подсистема2», которая содержит справочник «Организации».

    Мы написали «Правило2», которое переносит «Подсистему2» и добавляет в «Документ1» реквизит «Организация».

    Если мы создадим сценарий генерации состоящий из двух шагов, например:

    Шаг 1 по «Правилу1»

    Шаг 2 по «Правилу2»

    то в результате получим конфигурацию содержащую «Документ1» с реквизитом «Организация».

    Но если «Шаг 2» отключить то в результате получим «Документ1» без реквизита «Организация» т.е. этот реквизит как бы «Удалится» (но правильнее сказать «не добавится»). Поэтому проблема быстрого исключения из конфигурации ненужной функциональности легко решается если изначально нужным образом спроектировать сценарий генерации.

    Reply
  19. muskul

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

    Reply
  20. kirovsbis

    (19)

    Клонирование справочников(чем копировать вставить не то)? С данынми? Можно более конкретно в каким местах это может помочь на каких реальных задачах.

    Попробую более детально объяснить.

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

    У нас возникает потребность в создании вполне конкретного справочника НСИ, например справочника «Активы». Мы заходим в конфигуратор, копируем эталонный справочник. Соответственно в полученной копии будет такой же модуль объекта, модуль менеджера, формы и т.д. Ура!

    Решён ли вопрос создания справочника «Активы»? Неа.

    Нам как минимум ещё нужно:

    1. Изменить значения некоторых свойств этого справочника (Например Имя, Синоним)

    2. Включить созданный справочник в состав нужным нам определяемых типов, планов обмена и т.д.

    3. Назначить права на этот справочник для одной или нескольких существующих ролей.

    4. Добавить для этого справочника нужные реквизиты.

    5. Вывести эти добавленные реквизиты на уже существующую форму элемента.

    6. Модифицировать запрос динамического списка в форме списка справочника.

    7. Возможно ещё ряд некоторых действий.

    В статье об этом написано в целом, для создания справочника «руками» была даже написана специальная инструкция, просто скопировать объект метаданных недостаточно.

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

    На практике гораздо важнее стоит вопрос сопровождения этого кода. Допустим мы нашли ошибку в одном из модулей нашего справочника НСИ. Поскольку у нас все справочники НСИ создаются копированием эталонного, то значит ошибку надо исправлять в модуле КАЖДОГО справочника НСИ, а у нас их например штук 40. Заходить в каждый и вносить изменения удовольствие ниже среднего. В нашем случае ошибку достаточно исправить в модуле эталонного справочника, выполнить пересборку и нужные изменения будут внесены ВЕЗДЕ. Т.е. кодогенерация это по-сути способ масштабировать собственную работу.

    Reply
  21. kirovsbis

    (16)

    Спасибо как минимум за то что не поленились продумать и написать такой кусок кода 🙂 Вечером я помедитирую над ним )

    Reply
  22. ambrozii

    (20) >> Заходить в каждый и вносить изменения удовольствие ниже среднего

    Будь мужиком! Исправь все руками!

    Reply
  23. kirovsbis

    (22)

    )))

    Ну да, настоящие мужики терпят!!!

    Reply
  24. Darklight
    Reply
  25. Darklight

    (21)Просто я тоже давно грёзю кодогенерацией в 1С и программными скриптами изменения метаданных — и много думал на эту тему. Так что подобные выкладки кода — это просто продолжение моих размышлений — и как стать, может когда-нибудь это всё станет не только моей фантазией….

    Reply
  26. Darklight

    (19)Смотрите мои посты (14)(16)(24) — я там как раз говорю об этом

    Reply
  27. Darklight

    (16)В листинге у меня небольшая опечатка: «КонецЦикла» перед. п.4. рано закрыл 🙁 — это же был цикл перебора блоков кода — его нужно закрыть в самом конце — перед закрытием последнего цикла перебора процедур/функций, чтобы контексты п.4 и п.5. были внутри этого цикла.

    Ещё добавка — алгоритмы п.3 (анализирующие инструкции и выражения; да, впрочем, это важно для всех вариантов пунктов) в приведённом листинге не имеют проверки на вид блока кода — а это может быть очень важно для его разбора — например блок кода с текстом запроса скорее всего нужно обрабатывать иначе, чем просто инструкции языка 1С, уж как минимум Лексер в ASTДерево и Генератор кода для него должны быть свои (поэтому для п.3. это очень важно, для других случаев — это не обязательно, но всё-равно лучше всегда знать с каким видом блока кода имеешь дело).

    Reply
  28. Darklight

    Аналогично объединению метаданных можно реализовать и алгоритм ввода нового метаданного на основании другого метаданного

    Фильтр = ПолучитьФильтр(); //Какой-то фильтр, определяющий что нужно переносить из Родителя в Потомок (можно без него — команда сама знает как провести наследование)
    ПравилаНаследование = ПолучитьПравилаНаследования(); //Если наследование должно идти по не стандартным правилам их можно тут задать — особенно будет полезно для множественного наследования
    Родитель1 = НекаяКонфигурация.Метаданные.Найти(ПолныйПутьРодителя); //Ищем метаданное источник
    Родитель2 = НекаяКонфигурация.Метаданные.Найти(ПолныйПутьРодителя); //Ищем метаданное источник
    Потомок = НекаяКонфигурация.Метаданные.Найти(ПолныйПутьПотомк); //Ищем метаданное потомок, но без части, наследуемой у родителя
    
    //Обновляем потомка — хотя можем сделать и совсем новое метаданное — особенно когда Потомок просто импортируется из какого-то вспомогательного модуля
    Потомок.Обновить(КомандыИзмененияМетаданных.Наследовать, Родитель1, Фильтр, ПравилаНаследования);
    Потомок.Обновить(КомандыИзмененияМетаданных.Наследовать, Родитель2, Фильтр, ПравилаНаследования); //Тут вполне допустимо множественное наследование — коллизии могут быть разрулены в ПравилаНаследования
    Потомок.Применить();
    

    Показать

    Тут вся фишка во встроенной Команде «КомандыИзмененияМетаданных.Наследовать» в которой (в Процессоре обработки команды, который тоже можно задать свой) прописан универсальный алгоритм того, как совмещаются два объекта метаданных при операции наследования (ну и, он использует переданные «ПравилаНаследования» — если они не стандартные, которые тоже могут быть изменены, и берутся отсюда: НекаяКонфигурация.ПравилаНаследования.Основное()).

    По умолчанию — она (команда) переносит из Родителя в Потомок всё то, чего там нет (согласно фильтру — если будет задан) — а где есть пересечения — объединяет их свойства с приоритетом потомка. Ну перенос текстовых алгоритмов тут более сложный — но в целом он должен работать как классическом ООП (специальные аннотации в методах модулей будут в помощь). Ну и совмещение форм и макетов — это тоже не простые задачи — но это всё внутренние универсальные задачи движка

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *