Расширяемый фреймворк на 1С, или Нюансы натягивания совы на глобус
Предисловие
Данная статья является текстовым вариантом доклада в рамках митапа от Инфостарт “Библиотеки и фреймворки на 1С и всё, что с этим связано”
Фреймворки и библиотеки. Что это такое в рамках 1С и как их разрабатывать, поддерживать, а главное “расширять”?
Дисклеймер
Данная статья - это мой личный опыт. И он может не совпадать с вашим. А тема достаточно холиварная. Поэтому милости просим в комментарии и всем добра =)
О докладчике
Меня зовут Черненко Виталий
- Лидер 1С:Сообщества в компании Магнит
- Разрабатываю внутреннюю БСП Магнита. Пока что конфигурация закрыта, но в будущем планируем выпустить часть подсистем на GitHub* Публикуюсь на GitHub, Инфостарт с 2012 года
- Люблю создавать необычные инструменты. Например:
- Управление платформенными обработками - расширение для извлечения и автоматической подмены встроенных в платформу обработок (консоль запросов, журнал регистрации и так далее)
- Менеджер открытых форм - обработка для перехвата открытых окон для анализа и изменения их свойств и данных
- Конструктор внешних печатных форм - мой первый эксперимент, который позволял в несколько кликов получить внешнюю обработку с выбранной типовой печатной формой
- Люблю изучать платформу на прочность, а результаты исследований публиковать в телеграм канале Желтый Чайник 1С
Но в рамках данной статьи мы поговорим о создании “расширяемого фреймворка” и нюансах натягивания этой совы на 1Сный глобус.
Библиотеки VS Фреймворки
Сразу появляется первый вопрос. Что же такое фреймворки и чем они отличаются от библиотек?
- Библиотека - это некий набор инструментов. Она не ограничивает вас в построении своего приложения, а лишь даёт возможность взять в любой момент условный молоток и забить им гвоздь (или что попадется под руку). Грубо говоря, это просто набор удобных методов, облегчающий какие-то бытовые задачи. Перегнать таблицу в массив структур или же разбить строку на символы.
- Фреймворк - это каркас приложения. Он обладает своим подходом к разработке и набором правил, которые требуются от вашего кода. Фреймворк так или иначе вызывает ваш код (или требует от вас прописать вызовы в нужных местах). Часто фреймворк - это почти готовое приложение, под архитектуру которого вы уже подстраиваетесь, чтобы использовать его возможности.
И то и другое может быть и простым и сложным. Бывает, что какие-то решения лишь условно относятся к одной из двух категорий, сочетая в себе качества обеих. Но общий принцип, думаю, ясен.
Возникает вопрос, что же такое БСП? Ведь это “Библиотека стандартных подсистем”. И тут, как это часто бывает в 1С, возникает путаница в терминологии. Ведь у 1С свой “особый путь” и своё “видение” на общепринятые названия. Поэтому в “БСП” важно не слово “Библиотека”, а слово “подсистем”. А подсистема может быть и библиотекой, и фреймворком, и просто некой бизнес-функциональность.
На примерах разных подсистем можно выяснить, что в БСП есть и то, и другое:
- Библиотеки в БСП - это всякие методы общего назначения, строковые функции и так далее. Небольшие подсистемки, которые не заставляют как-то по-особенному подходить к архитектуре вашего приложения. Просто удобный инструмент, который вы можете использовать в любой момент, а можете и проигнорировать
- Фреймворки в БСП - это подсистемы, для использования которых вы должны следовать определенным правилам. Например, создавая справочник присоединенных файлов, необходимо делать его по определенному шаблону как реквизитов так и кода. Для подключения доп. реквизитов к объекту необходимо добавить ему табличную часть с определенным именем и составом колонок, а в нужных местах прописать вызовы кода подсистемы.
И выходит, что БСП - это не “библиотека” в “общепрограммистском” понимании. И слово “библиотека” здесь применяется в смысле “Набор”. Это некий набор стандартных фреймворков и библиотек.
Фреймворк “Расширенный глобальный поиск” ^
Ради эксперимента я решил сделать свой “фреймворк” на 1С и выбрал для этого неисследованную тему - построение произвольного меню внутри поля глобального поиска.
Данное расширение позволяет объединить все свои дополнительные возможности поля поиска в одно иерархическое меню. И предоставляет удобные методы для его настройки. Оно само строит меню, производит постраничный вывод, добавляет стандартные команды, вызывает переданные вами методы и так далее.
С таким подходом пользователю достаточно запомнить один ключевой символ для активации меню, а далее действовать интерактивно.
Расширение уже содержит встроенное меню, но разработано как фреймворк для создания своих отдельных пунктов. При этом это можно делать в своих независимых расширениях, чтобы не было необходимости изменять основное.
Подробнее ознакомиться можно на странице проекта.
Создаем свой фреймворк
Прежде чем начать создавать свою библиотеку или фреймворк, стоит ответить для себя на ряд вопросов:
Варианты поставки
Один из самых важных вопросов - как поставлять свою разработку конечному потребителю?
Три основных варианта поставки:
- Конфигурация. Пилим свой код в конфигурации и отдаём её на съедение внедрение в целевое решение. Имеет свои очевидные минусы - это необходимость снимать целевую конфигурацию с поддержки, внедрять “чужой” код в свой, хранить всё это в своём кодовом хранилище, а потом ещё и обновлять. При этом главный плюс - простота программного использования внутри конфигурации. Все методы доступных без костылей и после внедрения словно уже и полностью наши.
- Обработки. И тут я подразумеваю не просто “внешнюю обработку”, а те варианты сложных решений, которые поставляются в виде основного “движка”. А уже сам “движок” умеет “подключать” к себе внешние “модули” - отдельные обработки на диске, которые написаны с соблюдением правил основного инструмента. Этот подход уже не так популярен после появления расширений, но всё равно имеет свои плюсы. Например, максимальная мобильность и простота обновления (просто открыли новую версию в любой базе и пользуемся). В качестве примеров можно вспомнить “старые” инструменты разработчика и вариант поставки Vanessa, который позволяет открыть “основную” внешнюю обработку и подключить к ней выполняемые тестовые сценарии - отдельные обработки. Из минусов - достаточно ограниченные возможности влияния на основную конфигурацию (даже учитывая старания подсистемы БСП).
- Расширение. Этот вариант всё более популярен и, как мне кажется, уже является основным способом поставки. Расширения обладают большими возможностями по работе с конфигурацией, достаточно просто обновляются и так далее. Из минусов - условное ограничение на “невидимость” других расширений, которое можно обходить разными способами (об этом позднее)
В таблице ниже я привёл небольшое сравнение разных видов поставки (надо больше холивара).
Любой вариант поставки хорош и обладает своими плюсами, которые, возможно, в вашем конкретном случае перевесят минусы. Далее я буду делать упор на разработке расширения, потому что именно его и использую.
Комбинированные варианты поставки
Стоит не забывать ещё и про “комбинированные варианты”. Они уже ограничены чисто вашей фантазией.
Приведу пример. Допустим, мы разрабатываем свою подсистему по интеграции с месседжерами. У нас есть базовый фреймворк\каркас\движок\комбайн. Он имеет свой заявленный программный интерфейс - методы, позволяющие получать и отправлять сообщения через любой вид месседжеров. Этот каркас может поставляться в виде конфигурации, а значит будет лежать внутри вашего целевого приложения. А значит его можно будет просто вызывать через условный общий модуль “РаботаСМесседжерами.ОтправитьСообщение()”.
При этом, реализация для конкретного месседжера будет лежать отдельно в виде написанного по специальному правилу расширения. Т.е. отдельное расширение для Телеграм, отдельное для Вайбер, отдельное для ВК и так далее. Основной “движок” анализирует подключенные расширения и предоставляет возможность отправки через те каналы, которые сейчас есть.
Что дает такой комбинированный подход?
- Простота обновления. Любой конкретный месседжер можно обновлять в любой момент
- Изолированность компонентов. Сломался ВК? Ок, починим, а пока будут работать все остальные. Не хотим больше использовать ватсап? В любой момент просто удаляем его и никто даже случайно через него ничего не отправит. Передумали? Ну в пару кликов вернём назад.
- Простота программного вызова. Методы API находятся внутри нашей конфигурации, а значит легко вызываются.
При этом можно пойти дальше - вынести и сам движок в расширение. А в конфигурации оставить парочку общих модулей. Они будут просто “обёрткой”, которая перенаправит наши вызовы в методы расширения. Такой подход позволит минимизировать количество обновлений в самой конфигурации. Пока не потребуется изменить методы API самого нашего движка.
Универсальность <> Игнорирование БСП
Какие конфигурации должен поддерживать наш продукт? Допустим, мы хотим сделать максимально универсальное расширение, которое “станет” на всех конфигурациях независимо от наличия БСП. Такой подход может ввести в заблуждение, что мы теперь и вовсе должны игнорировать методы БСП и использовать только свой внутренний код. Но всё как раз наоборот.
Универсальность означает опциональную поддержку БСП
Наше расширение должно:
- Работать и на конфигурациях без БСП
- При этом подстраиваться под логику при её наличии
Ведь БСП - это каркас приложения. Который обладает своими правилами и архитектурными подходами. И будет неправильно, если ваше “доп.приложение” будет работать в разрез с логикой основной конфигурации.
Например, по подходу подсистемы “Права пользователей”, если у пользователя есть роль “Полные права”, то это автоматически означает, что у него есть любая роль. Даже если она не проставлена в самом пользователе ИБ.
В подсистеме “Длительные операции” есть возможность при помощи параметра запуска базы отключить порождение фоновых заданий. Все фоновые задания не будут запускаться, а их методы буду выполняться в текущем сеансе. Согласитесь, будет странно, если при этом ваше расширение проигнорирует и это правило.
И таких нюансов в БСП много. А ещё есть набор возможностей, которыми мы могли бы расширить способы применения своего расширения и улучшить пользовательский опыт. Например, подключаемые команды, в которые тоже можно внести ваши пункты меню.
Обо всём этом стоит задумываться в процессе разработки и по возможности поддерживать механизмы БСП, чтобы ваше приложение не выглядело каким-то прибитым сбоку автомобиля квадратным колесом.
Опциональная поддержка возможностей платформы
Платформа 1С развивается и дополняется новыми возможностями. И их хочется использовать в своём инструменте, но как при этом сохранить “обратную совместимость”? Не удобно же держать разные версии расширения под разные версии платформы и вносить доработки в каждое из них. Да, приходится новые возможности поддерживать опционально и вызывать “безопасно”:
- Проверка версии платформы и совместимости. Самый напрашивающийся вариант. Но при этом не самый удобный и не везде подходящий. Часто данные в СП некорректные, но даже и если всё верно, то оставить в модуле вызов несуществующего раньше метода = нарваться на ошибку компиляции в “старой” платформе. Поэтому нужно использовать и другие подходы
- Проверка существования типа. Делать это можно подобным костыльным методом. И использовать новые типы только в том случае, если они проходят проверку существования
- Проверка существования объекта. Такой способ удобен для, например, объекта СредстваБуфераОбмена. Его необходимо получать программно при помощи Вычислить(). И при неудаче возвращать неопределено. В примере на скрине есть ещё и доп. проверка “ИспользованиеДоступно()”. При этом, если такого объекта нет, то мы можем или использовать какие-то старые костыльные способы работы с буфером, либо же просто не давать такой возможности. Например, не выводить кнопку “Скопировать в буфер”
- Проверка существования метода. Иногда в платформе появляются новые методы. Например, по работе с регулярными выражениями. Опциональная поддержка методов ещё сложнее, ведь при каждом вызове их необходимо выполнять через “Вычислить” или “Выполнить”. Иначе же в старых платформах мы поймаем ошибку компиляции.
Но зато мы можем проверить существование метода таким хитрым способом. Позаимствовал я его из YaxUnit, но вроде как это “древний баян”. Суть в том, чтобы в попытке выполнить метод, передав в него огромное количество “запятых” - необязательных параметров. В результате метод никогда не выполнится, но по тексту ошибки можно понять существует ли он. Или платформа поругается на превышение числа параметров, или на отсутствие метода как такового
- Проверка наличия свойства. Когда же в каком-то объекте платформы добавляется новое свойство, то получить его “безопасно” можно старым добрым методом БСП
Ну и последний совет - используйте “методы-обертки”. Хотите добавить возможность копирования текста в буфер? Создайте свой метод и везде вызывайте его. А внутри уже проверяйте существование объекта платформы, реализуйте костыли, или вызывайте исключение в каких-то случаях и так далее. Главное, что такой метод позволит в одном месте вносить доработки и поддерживать новые возможности.
Способы переопределения и настройки
Вот мы разрабатываем свое расширение-фреймворк. Но как же реализовать главную его цель - возможность донастройки конечным потребителем? Да так, чтобы было проще поддерживать и обновлять. Есть разные способы, рассмотрим основные:
- Внутри самого фреймворка. По классике это переопределяемые модули, которые лежат рядом с основным кодом. Плюсы - простота и привычность для 1Сника. Минусы - каждое обновление требует анализа переопределений. Случайно не забыть, случайно не забить. И всё потом вернуть на место. И так при каждом обновлении
- Вызов из целевых объектов. Если вам удастся использовать этот подход, то вам повезло. Ведь переопределяемый код находится внутри ваших форм. Вы можете передать доп.настройки и подписаться на какие-то события. При этом сам фреймворк может вообще не дорабатываться, что значительно упростит обновление
- Методы целевых объектов. Ещё один простой способ, когда фреймворк вызывает определенные методы (например, из модулей менеджеров). И передаёт в них какие-то настройки, которые мы можем изменить. Такой подход тоже позволяет вносить минимум доработок в само расширение.
- Целевые переопределяемые модули. Тут уже мы переходим к некой реализации “модульности” на базе расширений. Мы можем хранить внутри фреймворка лишь шаблоны переопределяемых модулей. И при необходимости доработки - копируем этот модуль в своё независимое расширение. Соблюдая какие-то правила именования модулей (например, он должен начинаться с определенного префикса), мы можем упростить обновление фреймворка (ведь его мы не дорабатываем), и при этом хранить свои доработки отдельно. Такой подход так же позволяет хранить разные доработки фреймворка в разных расширениях. И в любой момент отключить одну из них.
Такой метод я использую в расширенном глобальном поиске. Об этом ещё поговорим в следующем разделе
- Глобальная переменная. Ещё один хитрый способ изменить настройки фреймворка, не меняя его код. В основном расширении мы создаем общую глобальную переменную. И наполняем её дефолтными настройками. А уже в отдельном расширении мы получаем переменную и вносим в неё свои изменения.
- Метод “Оповестить()”. Продолжаем костылить! Ещё можно в основном фреймворке использовать метод Оповестить, передавая в него какие-то настройки и имя переопределяемого события. А в отдельном расширении мы создаем общую форму, которую получим при старте системы и поместим в глобальную переменную. Открывать форму не нужно, достаточно чтобы она “висела” где-то в памяти. И тогда такая форма может подписаться на события фреймворка и обрабатывать передаваемые параметры.
- Параметры сеанса, хранилища настроек, константы и так далее… Вариантов переопределения на самом деле много и возможно вы для себя придумаете ещё более удобный способ.
Работа с контекстом
Возможно, у вас в голове висит вопрос. “А как одно расширение будет видеть другое?”. Ведь нам везде заявляют, что это невозможно. На самом деле, контекст всегда един. В 1С нет неймспейсов и подобных способов разделения кода. Есть общий контекст, который разделяется лишь на доступность клиент-серверного взаимодействия. Поэтому ошибки со скрина вы увидите только в среде разработки. В режиме предприятия их не будет (если, конечно, все нужные расширения стоят).
Но такие предупреждения усложняют разработку. Среди них можно не заметить реальную ошибку вашего кода. В таком случае лучше использовать более безопасные обращения. О некоторых мы уже говорили ранее. Добавлю ещё часть “лайфхаков”.
- Безопасное обращение к модулям. Это классический подход БСП. Мы не обращаемся к модулям напрямую, а получаем их через Вычислить()
- Описание интерфейсов. Для упрощения разработки в EDT можно использовать “интерфейсы”. Если мы в нашем расширении хотим удобнее обращаться к методам другого, то можем к себе добавить специальные модули, которые будут содержать лишь описания часто используемых методов. Без конкретного кода, а лишь описания входящих параметров и возвращаемого значения
При этом отдельный модуль будет возвращать нам реализацию этих интерфейсов. Возвращать настоящие модули другого расширения. Но в описании возвращаемого значения мы указываем ссылку на модуль-интерфейс. Таким способом мы словно обманываем EDT и заставляем её подумать, что метод вернет наш модуль. Методы которого мы знаем. А по факту там будет модуль другого отдельного расширения. Сигнатуру методов которого мы имитируем
- Модули-обертки. Уже на самом митапе поднимался вопрос. А как сделать подобное, но для разработчиков на Конфигураторе? Конечно, интерфейсы использовать мы не сможем, конфигуратор вообще таких возможностей типизации не имеет. Но с другой стороны, мы можем сделать модуль-обёртку. В нём будут опять же методы программного использования. А внутри этих методов вызов методов другого расширения. Таким образом, внутри своего расширения мы вызываем наш модуль. Он сам перебрасывает вызов в модуль другого расширения. Но при этом упрощает нам разработку, взяв на себя роль почтальона.
- Экранирование при помощи Перем. Сейчас кто-то ужаснётся и громко вскрикнет. “Нет, нельзя так делать, ведь все говорят, что это плохо!”. Я же придерживаюсь позиции, что любую возможность нужно использовать (или не использовать) с умом. Конкретно данный лайфхак позволяет нам писать наш код обращаясь к общим модулям так, словно они существуют в нашем расширении. Сохранив при этом “безопасность”.
На скрине в самом начале нашего метода первой строчкой кода мы резервируем под себя имена переменных. Они совпадают с именами модулей фреймворка. Отныне внутри нашего кода эти переменные становятся Неопределено. После этого мы сразу же помещаем в эти переменные соответствующие им общие модули (которые получаем через функции при помощи Вычислить()). Казалось бы, в результате ничего не изменилось. Но на самом деле, это позволяет писать следующий код так, словно нашему отдельному расширению известны общие модули с такими именами. Мы не будем получать ошибки в среде разработки. А наш код будет легко переноситься. Например, можно просто скопировать из фреймворка какой-то кусок кода и вставить к себе. Без необходимости поправлять имена модулей.
“Треугольник расширений”
Описанные выше подходы позволяют разрабатывать “связующие” расширения.
На самом деле, мне уже после доклада напихали в комментариях, что такая связка из трёх шестерёнок крутиться не будет. Но сюда всё равно вставлю, потому что картинка мне нравится)
И так, у нас есть наш фреймворк. Расширенный глобальный поиск. Он позволяет в поле глобального поиска выводить подменюшки со своим функционалом.
Ещё у нас есть какое-то другое расширение. В моём примере это Infostart Toolkit - набор инструментов разработчика от Infostart. Я им люблю пользоваться, поэтому хочу добавить в поле глобального поиска подменюшку с командами Toolkit. Т.е. в свой фреймворк добавить команды из другого расширения. При этом я не хочу попасть на проблемы обновления ни того, ни другого. Моя задача так их связать, чтобы не изменять их код и иметь возможность в любой момент обновить их простым “Загрузить расширение из файла”.
Для этого мы используем отдельное “связующее расширение”. Это маленькое отдельное расширение, которое:
- Содержит переопределяемый модуль по шаблону фреймворка расширенного глобального поиска
- Считывает команды из Infostart Toolkit
- Обрабатывает события фреймворка и добавляет в него команды из Toolkit
Что мы в результате имеем:
- Фреймворк поиска в любой момент можно обновить или удалить. Обновление не требует никаких доработок и может происходить хоть автоматически при выходе новой версии
- Toolkit в таком же положении. Мы его не изменили и можем в любой момент обновить или удалить
- Если одно из “больших” расширений мы удалим, то второе никак не пострадает. При условии, что связующее расширение написано с учетом правил безопасности, о которых я писал выше.
- Связующее расширение тоже можно в любой момент удалить. Если при обновлении одного из “больших” расширений наше связующее перестанет работать, то его можно просто отключить и починить. Во время исправления и расширенный поиск и Toolkit будут работать без проблем, просто не будет наших доработок.
Но помимо всего описанного, мы можем бесконечно расширять возможности фреймворка и наполнять его разными “командами”. Мы таких “связующих” расширений можем сделать сколько угодно. Каждое будет добавлять в фреймворк свою небольшую команду\подменюшку со своим изолированным функционалом. И в любой момент можно что-то обновить, что-то удалить. И что-то отдельное чинить при поломках. Весь остальной функционал остаётся работоспособным, ведь они все изолированы друг от друга.
Такие подходы позволяют нам приблизиться к той самой “модульности”, которой нет в 1С. Да, не без проблем. Да, с костылями. Через боль, страдания и периодические унижения. Но всё равно это возможно и в ряде случаев позволяет значительно упростить свою жизнь.
Пример такого связующего расширения
Мультиязычная разработка
Помимо нашего привычного “русскоязычного” кода, существуют ещё и конфигурации на английском. И не только с англоязычным интерфейсом, но и самим кодом. А ещё есть и “международная” БСП, где все нам известные подсистемы полностью написаны на английском. Что если мы хотим поддерживать и их?
- НСтр() или Словари. Первый вопрос - как переводить тексты сообщений, предупреждений и так далее. Классический подход - метод НСтр(). Но у него есть ряд недостатков. Во-первых, если у пользователя стоит язык интерфейса, которого нет в вашей мультиязычной строке, то пользователь увидит просто пустую строку. Да, НСтр() не возвращает текст по умолчанию. Он просто вернёт пустоту) Во-вторых, лично мне кажется плохим подходом смешивать сам код и переводы (представления). Выходит, что везде при вызове каждого сообщения нужно вставлять перевод на другие языки. И при желании добавить поддержку нового языка в наше приложение, нам приходится менять кучу модулей и методов. Везде вставлять переводы. И везде их подерживать. И хоть у нас есть инструменты для облегчения этой задачи, но мне лично больше нравится “классический” подход из других языков разработки. Когда тексты интерфейсов и их переводы хранятся в отдельных файлах. Поэтому у себя в расширении я использую специальный общий модуль со словарями. В нём содержатся все переводы используемых в коде сообщений. И в зависимости от текущего сеанса пользователь видит или свой язык, или язык по умолчанию (если его языка нет в наших словарях). При этом для добавления нового языка достаточно просто в одном модуле добавить один новый словарь. И всё, весь остальной код остаётся нетронутым. Ну и можно подключить модули автоматического перевода. Как, например, это есть в БСП.
- Заполянем все представления. Если вы поддерживаете два языка интерфейса, то все представления метаданных, реквизитов, элементов, команд и так далее нужно заполнять в двух языках. И даже поля СКД или содержимое ячеек табличных документов.
- События платформы. Интересная особенность расширений заключается в перехватах общих событий (не привязанных где-то в свойствах формы, а тех, что имеют зарезервиварованные имена методов). Ваши русскоязычные названия событий могут просто не сработать в англоязычной конфигурации. И наоборот. Это не всегда, а зависит от конкретной комбинации свойств конфигурации и расширения. Но приводит это к тому, что легче просто перехватывать сразу русскоязычный и англоязычный методы
- Описания ошибок. Если вы программно обрабатываете как-то описания ошибок (анализируете их текст), то стоит учитывать, что теперь они могут быть не только на русском)
- Пути метаданных и форм. В ряде случае на пути к метаданным и формам платформа может ругаться. Поэтому, например, желательно открывать формы, получая их полные пути программно из метаданных.
- Некоторые свойства платформы. Иногда бывают глюки и платформа не понимает русскоязычное название глобального свойства в англоязычной конфигурации. Например, такое было с элементами стиля.
- Международная БСП
- Модули, методы. Да, БСП на английском содержит свои имена модулей и методов) Не Пользователи, а Users. И так далее. При поддержке международной БСП нужно и это учитывать и хранить некое соответствие.
- Свойства объектов. Вот вызываете вы привычный БСПшный метод, а он вам структуру возвращает, где все свойства на английском. Придётся учитывать и это тоже)
- Метаданные. Расширяете справочник Пользователи? Ну так в международной БСП это Users. Уже просто так не сделаешь. Хотите написать запрос к привычным таблицам? Ну придется теперь программно запросы строить или допиливать
В целом, “международная” разработка доставляет массу неудобств (ещё некоторые упомяну позднее). Думаю, иногда просто легче забить, чем поддерживать. Или же хранить отдельную версию под разный язык кода. Но в моих разработках привязка к БСП минимальная, так что ради экспериментов можно немного пострадать)
Среда разработки
Рассмотрю пару тем, которые хоть и не касались напрямую темы митапа, но всё равно важны для “выбора пути”. Какую использовать IDE для нашего проекта?
- Конфигуратор - дефолтная IDE для 1Сника. Что-то из времен динозавров. Дополнительно можно обвеситься “помогаторами”, чтобы не было так грустно
- 1С:Enterprise Development Tools - новая, модная, молодёжная. Да кого я обманываю, этот продукт на Eclipse по сравнению с современными IDE хоть и “новее” конфигуратора, но максимум тянет на что-то из каменного века. Но куда нам 1Сникам деваться?
На самом деле, несмотря не предыдущий крик души, я уже года два сижу на EDT как на основной среде разработки. Примерно год использую строгую типизацию где только можно. И обратно в конфигуратор не хочу. Дополнить опыт можно ещё всякими плагинами или сделать свой (если психика крепкая)
- Visual Studio Code - лично моё имхо-мнение, если бы 1С вложилась в разработку плагина для VSC, то мы бы жили в идеальном мире будущего. Этого нет, но есть крутые разработки энтузиастов. VSC я использую по мере необходимости, когда изменения кода минимальные и не требуют редактора форм. Ну или наоборот, когда нужно что-то ковырнуть в XML формы
Контроль качества кода
- Проверки конфигуратора. Не только “стандартные” (без прохождения которых вы просто не запустите приложение), но и “расширенные”, которые помогают найти потенциальные ошибки
- Проверки EDT. В EDT намного больше проверок, все они настраиваются в свойствах проекта.
- Строгая типизация EDT. Дополнительный режим контроля качества кода, о котором я недавно писал в статье. В своих проектах использую как маст хэв.
- BSL LS. Всем известный open-source проект, который помимо всего прочего умеет находить ошибки в вашем 1Сном коде. Можно использовать внутри VSC.
- Sonar BSL LS. Плагин для SonarQube. Я использую его для разработки своих проектов. Самый простой способ - развернуть локально сервер сонара и периодически запускать вручную проверки.
- Sonar Серебряная пуля. Платный плагин от Серебрянной пули. Используем его внутри компании Магнит. Не могу сказать, что какой-то из них однозначно лучше, но для своего личного проекта, конечно, легче использовать бесплатный BSL LS
- 1С: АПК. Конфигурация на 1С от компании 1С для анализа вашего кода на 1С. Функционально напоминает сонар. Я лично не использовал, но это, можно сказать, официальный вариант от вендора.
- Многие другие… На самом деле, такого рода инструментов много. По ссылке один из них, в описании которого есть ещё и таблица со сравнениями. В ней можно увидеть другие альтернативы
Подготовка расширения и возможные проблемы
Вот мы уже разработали свой продукт и готовы его поставлять. Какие же проблемы могут возникнуть на этом этапе?
- Лишние “галочки”. Как только мы создаем новое расширение, то в нём уже сразу “натыкано” много “галочек” по переопределению и контролю. Несовпадение значений может привести к тому, что конечный потребитель не сможет установить наше расширение через режим Предприятия. Получит список ошибок. И, возможно, уже на этом этапе задумается, а действительно ли наш продукт подходит к его конфигурации. Чтобы минимизировать риски и затраты при установке\обновлении, нужно снимать максимум “галочек”. Беспощадно отключаем всё то, что нам не нужно.
- Режим совместимости. Выбираем его тщательно. Критерием может быть, например, текущая версия на последних БСП. Или же минимальная версия платформы, которая содержит жизненно необходимую для вас возможность. Например, для моего расширения для доработки глобального поиска важно существование переопределяемых событий этого самого поля поиска. Без них пропадает сам смысл инструмента, а значит я выбираю режим совместимости из описания методов в СП.
- Проблемы мультиязычной разработки - на этапе разработки мы ещё не обо все стены ударились, поэтому платформа готовит для нас сюрпризы
- Языки сравниваются по GUID. Да, это очень странное решение. На скрине пример ошибки, когда в конфигурации есть язык Русский, в расширении есть язык Русский, их все свойства совпадают, но различается внутренний идентификатор (которого мы даже не видим). Из-за этого расширение нельзя применить в режиме предприятия, а в конфигураторе нужно будет каждый раз при обновлении выбирать соответствие “Русский” = “Русский”. Проблему усугубляет то, что гуид в конфигурации может создаваться любой. И даже типовые конфигурации могут содержать разные по гуидам “русские” языки.
А если мы поддерживаем английский язык? Ну тогда при каждом применении в обычной ру-конфе его придётся удалять вручную, иначе расширение не применится.
- Разные ветки под языки. Такой способ позволяет немного облегчить себе жизнь. Сама разработка ведется в основной ветке, в которой у расширения все нужные языки. А уже при подготовке релиза используются отдельные релизные ветки. В каждой из них точно такое же расширение, но из дерева метаданных удалён “лишний” язык.
Для простоты разработки у меня в GitHub есть развернутые проекты ru и en БСП
В каждом проекте есть свои отдельные ветки под разные версии платформы (готовые проекты EDT) + под разный состав языков. Таким образом, можно склонировать себе проект, переключиться на нужную ветку и сразу вести разработку в EDT
- Поставка с разным составом языков. Теперь из разных веток можно создавать разные варианты расширения. Они будут отличаться только отсутствием “лишнего” языка в дереве метаданных. Такие расширения будет легче применить конечному потребителю.
Ещё один вариант поставки - отсутствие языков как таковых. В конфигураторе можно удалить все языки (в ЕДТ придётся это делать через XML). И тогда все представления в расширении останутся, а при установке не будет контролей языков. Такое расширение легче установить, но есть минус - в нём нельзя будет править представления объектов. Просто все поля синонимов недоступны для редактирования. Поэтому вести разработку с таким вариантом поставки неудобно, а вот устанавливать можно без лишних проблем.
- Баги платформы - куда же мы без наших любимых багов?
- “Призрачный” режим - недавно обнаруженная “особенность” платформы, которую с боем удалось зарегать как ошибку (исправят через никогда).
На скрине видно, что у нас есть неактивный режим совместимости, который не используется, не контролируется и его нельзя вообще изменить. Вроде кажется, что он ни на что не влияет, но не тут-то было. Он блокирует возможность установки на версиях младше 8.3.23 (в данном случае). Причем не только в режиме предприятия, но и в конфигураторе. Такое расширение просто вообще невозможно загрузить в базу.
Т.е. у свойства есть флаг контроля. Он может быть снят, предупреждающий и блокирующий. Сейчас он снят. Но по факту блокирует. Когда он снят, то свойство изменить нельзя и оно “серенькое”. Вроде всё намекает на то, что свойство использоваться не должно. И так оно и есть - если мы попытаемся выгрузить расширение в XML, то свойства не будет. А если попытаемся загрузить из XML обратно, то оно установится таким значением, которое платформа сама выберет (исходя из текущей погоды и положения звёзд).
Это приводит к ситуации, когда вы ведёте разработку в EDT, то в данном случае это свойство компилируемого расширения вам не подвластно. И оно ставится таким, каким платформа захочет. Иногда это у меня 8.3.23, иногда 8.3.14, а иногда 8.3.24. Поэтому, проверяйте это свойство перед прикладыванием файла релиза расширения. И если нужно изменить - включайте контроль, меняйте свойство, а потом снова снимайте контроль.- Расширяемый метод отсутствует. Тоже неприятный баг, который блокирует возможность установки в режиме предприятия.
На скрине кусок справки:
Смысл в том, что если вы в расширении хотите подвязаться на событие приложения “ПриНачалеРаботыСистемы”, то существование созданного обработчика в конфигурации не обязательно. И это логично, если мы ведём разработку универсального расширения, а не просто делаем срочную залипуху для конкретной конфигурации.
Но по факту же в разных версиях платформы мы можем столкнуться с такими ошибками:Радует, что при установке через конфигуратор ошибки не появляются и мы всё же можем установить расширение.
- Отличия событий. Периодически события платформы изменяют состав параметров. Это на разных версиях может приводить к ошибкам переопределения. Просто учитывайте это, если столкнётесь со странным поведением.
- “Призрачный” режим - недавно обнаруженная “особенность” платформы, которую с боем удалось зарегать как ошибку (исправят через никогда).
Выводы
На скрине мои ответы на задаваемые изначально вопросы. Ваши могут быть совершенно другими. Это всё зависит от конкретной цели, требований и религиозных убеждений. А обсудить всё это можно в комментариях =)
Что я могу сказать под конец? Разработка фреймворка на 1С возможна. По умолчанию она сопровождается разными компромиссами, на которые мы идём из-за ограничений платформы. Но результат всё равно может быть достаточно гибким и удобным.
Ссылка на фреймворк Расширенный глобальный поиск