Как я подружил BPMN и Bitbucket

    Привет, Хабр! Я техлид в компании ДомКлик. В основном занимаюсь backend-разработкой. Мне периодически приходится погружаться и во front-разработку, но этого не происходило уже более двух лет. Сегодня я расскажу, как мне пришлось заняться front-разработкой для создания плагина для Bitbucket, с какими сложностями я столкнулся и как их решал. Также поделюсь результатом своей работы: надеюсь, он окажется полезен кому-нибудь ещё. Эта статья не является руководством по написанию плагинов для продуктов Atlassian и не описывает всех возможностей системы плагинов.

    Проблема


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

    • Отличный инструментарий. Сюда входят инструменты для моделирования, мониторинга, анализа бизнес-процессов.
    • Отличная документация, полная и подробная.
    • Возможность тонкой настройки под свои нужды благодаря огромному количеству настроек среды исполнения.
    • Возможность расширения базовой функциональности через реализацию своих плагинов.
    • Сообщество. Разработчики Camunda организуют конференции, митапы, записывают обучающие видео, ведут тематические блоги, поддерживают диалог на форуме и, конечно, выкладывают свой код на GitHub.

    И всё было бы хорошо, но есть одна существенная проблема. Нотация BPMN использует XML для описания всех шагов, связей и расположения всех элементов схемы бизнес-процесса. Существуют различные инструменты визуального проектирования схем BPMN. Одно из самых удобных — Camunda Modeler. Любое изменение визуального представления влечет за собой изменение XML-описания. Мы в командах придерживаемся практики обязательных code review, которые проводятся средствами Bitbucket в рамках пулл-реквестов. Но рецензировать изменения в большом XML-файле, который описывает визуальное представление, практически невозможно. Попробую проиллюстрировать проблему на примере стандартного сравнения текстовых файлов, которое производит Bitbucket:



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

    До сих пор мы вынуждены были скачивать две версии файла (старую и новую) на локальную машину, открывать их в среде визуального просмотра и сравнивать вручную. Очень неудобно. И из-за такого подхода в прод уже просачивалось несколько багов. Актуальность этой проблемы растет вместе с количеством людей и команд, которые используют BPMN.

    Долгое время меня не покидала мысль, что необходимо как-то облегчить жизнь командам, вынужденным вручную сравнивать схемы. И хорошо бы иметь встроенный в Bitbucket визуальный инструмент. Я начал изучать вопрос расширения возможностей Bitbucket с помощью плагинов. Ничего подходящего я не нашел, но зато натолкнулся на такое демо возможностей JavaScript-библиотек от разработчиков Camunda. Это ведь то, что надо! На свой вопрос о планах разработки плагина для Bitbucket на форуме я получил отрицательный ответ. Поэтому пришлось собраться с мыслями и сделать плагин самому.

    Разработка плагина для Bitbucket


    На момент начала разработки плагина я понятия не имел о том, как это делать, поэтому, как настоящий разработчик, сначала спросил у Google: «bitbucket plugin development». Google первым же результатом выдал страницу Beginner guide to Bitbucket Server plugin development. На этой странице мы узнаём, что есть две версии продукта: Bitbucket Server и Bitbucket Cloud. Нас интересовал Bitbucket Server. Поэтому дальнейшие шаги будут относиться только к разработке для него.

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

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

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

    Существует два способа добавления своих элементов в UI Bitbucket на стороне клиента: Client Web Fragments и Client-side Extensions (aka CSE). Второй способ появился в Bitbucket Server 7 и предполагает постепенное замещение первого способа. Пока CSE доступны только на страницах, связанных с пулл-реквестами.

    В CSE входят пять типов расширений: кнопка, ссылка, модальное окно, панель, страница. Все типы описаны на соответствующих страницах с примерами использования. Чтобы определить, какие элементы страницы предполагают расширение с помощью CSE, достаточно добавить ?clientside-extensions к URL страницы. При переходе на такой URL подходящие места будут подсвечены специальной иконкой, при нажатии на которую можно узнать:

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

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

    Client Web Fragments я подробно рассматривать не буду, так как при реализации плагина этим инструментом воспользоваться не пришлось.

    Помимо расширений на стороне клиента разработчику доступен механизм Plugin modules с разнообразным функционалом. Например, можно добавить свои ресурсы (CSS, JS и т.д.) и таким образом адаптировать поведение и UI под свои нужды.

    Трудности


    Первая трудность, с которой я столкнулся при попытке запустить шаблонный проект, заключалась в том, что расширения, реализованные в проекте, не появляются в UI Bitbucket. В логах старта обнаружилась ошибка, которая сообщала, что плагин не запускается из-за какого-то несоответствия версии библиотеки. После достаточно продолжительной медитации, гугления и исследования админки Bitbucket, причина нашлась: шаблонный проект требовал библиотеку обработки CSE версии 1.2.3. При этом на сервере оказалась установлена библиотека версии 1.0.0. Для решения этой проблемы необходимо модифицировать шаблонный проект, добавив следующий фрагмент в конфигурацию bitbucket-maven-plugin:

    <plugin>
       <groupId>com.atlassian.maven.plugins</groupId>
       <artifactId>bitbucket-maven-plugin</artifactId>
        …
        <configuration>
            ....
            <pluginArtifacts>
                <pluginArtifact>
                    <groupId>com.atlassian.plugins</groupId>
                    <artifactId>atlassian-clientside-extensions-page-bootstrapper</artifactId>
                    <version>1.2.3</version>
                </pluginArtifact>
            </pluginArtifacts>
        </configuration>
    </plugin>
    

    Трудность № 2. Мне необходимо было реализовать следующую логику на стороне клиента: получение двух версий содержимого BPMN-файла через REST API Bitbucket, построение модели BPMN, сравнение, отрисовка и раскраска схем. Отрисовка и раскраска требует возможности добавления собственного HTML-кода и подключения собственных стилей.

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

    1. У модального окна есть несколько предустановленных размеров и нельзя указать произвольный размер. В частности, нельзя нарисовать модальное окно на весь экран, что является желательным для отрисовки схем.
    2. Сейчас нет возможности привязать свои ресурсы к расширениям CSE. Либо я не обнаружил такого способа. Можно попробовать добавить JS-код и CSS-классы внутрь кода модального окна (и я даже смог это сделать и отрисовать схемы), но в результате получается совершенно неподдерживаемый кусок кода, который было бы стыдно показывать людям. К тому же это не решает первую проблему.

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

    Промучившись какое-то время, мне пришло в голову, что у Atlassian должна быть какая-то поддержка, форум для разработчиков. Форум быстро обнаружился и я задал в подходящем разделе свой вопрос: https://community.developer.atlassian.com/t/alternative-diff-view-plugin/43717. Однако, ответа так и не дождался. И это трудность № 3, с которой я столкнулся: низкая активность сообщества в целом и представителей Atlassian в частности. Спустя 17 дней после того, как я задал вопрос, я сам же на него и запостил ответ. Заодно ответил на вопрос другого разработчика в соседней теме, который также ждал 17 дней.

    В конце концов мне удалось решить свою задачу. Я использовал кнопку CSE на странице сравнения, которая открывает новую вкладку со страницей, где отрисовывается графическое сравнение схем. Для отдельной страницы я использовал Servlet plugin module, который поддерживает подключение статических ресурсов. А для самого подключения я применил Web Resource plugin module.

    Чтобы использовать Servlet plugin module, необходимо реализовать свой сервлет, генерирующий HTML-код страницы. Очевидно, что отдавать контент сервлет должен только аутентифицированным пользователям. Но как это обеспечить? Если покопаться в примерах кода на ресурсах Atlassian, то можно обнаружить необходимый код для Jira с использованием её библиотеки, которая не подходит для Bitbucket. Но этот код наводит на мысль, что подобный API должен быть и у Bitbucket (хотя прямого описания в документации я не обнаружил). После некоторых поисков обнаружилась нужная библиотека:

    <dependency>
       <groupId>com.atlassian.bitbucket.server</groupId>
       <artifactId>bitbucket-api</artifactId>
       <version>${bitbucket.api.version}</version>
       <scope>provided</scope>
    </dependency>
    

    В этой библиотеке есть класс AuthenticationContext с искомым методом isAuthenticated(). Осталось только заавтовайрить этот класс в классе сервлета.

    Аналогичная проблема с библиотекой генерации HTML по шаблону (в моем случае это шаблон Velocity). Необходимо подключить библиотеку:

    <dependency>
       <groupId>com.atlassian.templaterenderer</groupId>
       <artifactId>atlassian-template-renderer-api</artifactId>
       <version>${atr.version}</version>
       <scope>provided</scope>
    </dependency>
    

    И далее использовать ее в сервлете:
    templateRenderer.render(TEMPLATE_PATH, params, response.getWriter());

    Трудность № 4 заключалась в том, что совершенно непонятно, что за библиотеки тебе нужны для решения вполне обычных задач. В документации это либо не описано, либо находится где-то очень глубоко (поправьте меня, если я вдруг ошибаюсь).

    И последний совет. Опытным frontend-разработчикам, наверное, это покажется очевидным, но я дошел до этого не сразу. Используйте режим инкогнито в браузере для тестирования своих плагинов. Это сэкономит много времени и нервов, которые были бы потрачены на поиски «странных» багов.

    Результат


    У меня получился плагин для Bitbucket Server версии 7. Плагин добавляет кнопку «BPMN Visual Diff» в шапку панели сравнения:



    Кнопка отрисовывается только в том случае, если для сравнения выбран файл с расширением .bpmn. Таким образом, пользователи, не использующие BPMN, даже не заметят изменений.

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



    Исходный код проекта плагина доступен на GitHub под лицензией MIT. Пожелания, критика и пулл-реквесты приветствуются. В ближайших планах — адаптация плагина для Bitbucket Server версии 6.
    ДомКлик
    Место силы

    Comments 15

      0

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

        +1

        В ваших аргументах против BPMN есть зерно истины. Но визуальное представление логики — это далеко не всё (и не главное), ради чего BPMN используется. Есть ещё несколько аргументов за. Например, прозрачная обработка ошибок и политика попыток повторного исполнения (организовать то же самое только в коде значительно сложнее). Бизнесс-процессы могут иметь довольно сложную и разветвлённую структуру. Это все можно организовать на уровне кода, но поддерживать становится довольно затратно. Ещё организация таких штук, как SAGA.
        А по поводу конфликтов золотой пули нет. Большинство таких проблем можно решить организационно: над одним бизнесс-процессом не могут работать параллельно несколько человек.

          0

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


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

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

            Вы вот сейчас BPMN описали. Серьёзно.
              0

              Не графические языки. Вот эти 17-20 узлов, что на картинке есть — их ну пусть в 30 строк на экране — никак выразить нельзя? Пользователи и разработчики этих схем способны выучить графическую нотацию но не способны — текстовую?


              А саму диаграмму, если это кому-то улучшает понимание, можно по этому тексту дополнительно нарисовать в соседнем окне.

                0

                Мне такие не известны. В такой схеме непонятно как обеспечить соответствие описания и графического представления.

                  0

                  В смысле, как? Графическое представление генерируется на ходу из текста. Т.е. текст — первичен, а картинка — иллюстрация для облегчения понимания.


                  Ну вот если диаграмму в plantuml рисовать в IDE — рядом можно открыть окошко, где эта диаграмма и будет нарисована. Но если картинки нет, а у меня текстовый diff изменения показывает — я все равно смогу понять, что тут узел вставили.

                  +1
                  Видимо, имеются в виду языки типа Gherkin. И даже есть тулзы, генерящие модели по feature-файлам (не уверен, правда, что в BPMN).
                  Но у автора статьи визуальное моделирование — часть процесса автоматизации, а схемы BPMN получаются как артефакты этого моделирования, поэтому их нельзя заменить на что-то.
                    0

                    Все верно: схемы BPMN — артефакты, которые можно распространять между членами команды с разными ролями и между командами.

          0
          Хорошо бы сделать последнюю картинку кликабельной.
            0
            Честно говоря, понятия не имею как тут это сделать. Оригинальная картинка имеет довольно большое разрешение, поэтому её можно открыть в новой вкладке и там будет все хорошо видно.
            0
            Красиво, но:
            1. визуальное отображение может пропустить детали изменений в BPMN (к примеру, добавили условие в decision table)
            2. вместо решения проблемы с diff-viewer для xml (очевидно, он лажает), вы создали проблему поддержки нового решения.

            Резюме: спорная выгода.
              0
              1. Про поддержку DMN я ничего не говорил. Но можно и DMN поддержать. Вообще, я упоминал в статье, что в основе лежат библиотеки от создателей Camunda (см. https://bpmn.io/). Эти библиотеки отвечают за отрисовку и за вычисление diff двух моделей. Я уверен, что подавляющее большинство кейсов они покрывают. Практика покажет насколько точно они это делают. Но ручное сравнение уже показало свою несостоятельность.
              2. Тут вопрос цены. Допустим в компании 100 человек задействованы в разработке бизнесс-процессов. Что дешевле: одному человеку поддерживать плагин (скорее всего очень редко что-то придется реально делать) или сотне людей ежедневно проходить через боль ручного сравнения и риски связанных с этим ошибок?
                0
                Согласен — решение ситуативно.
                В моем случае выгода показалась спорной из-за пунктов выше. В вашем случае, уверен, были причины за создание решения.
                Спасибо что поделились.
              0
              Очень интересная идея. Сам сталкивался с ручным мержем процессов. К сожалению, используем в работе gitlab.

              Only users with full accounts can post comments. Log in, please.