Всем привет! Меня зовут Артем, я аналитик, занимаюсь автоматизацией бизнес процессов и учета, преимущественно в крупных производственных холдингах.
В этой статье я буду рассуждать о графических артефактах в технической документации. О том, какие существуют визуальные языки, о подходе «docs as code», задачах которые нужно решать применительно к графике в рамках этого подхода и инструментах которые пробовал использовать. Также рассмотрю возможные, на мой взгляд, улучшения процесса работы с графическими артефактами и расскажу о попытке спроектировать и реализовать свой собственный язык разметки.
Зачем нужна графика в документации?
Думаю что многие из практикующих аналитиков (а возможно и разработчиков) согласятся, что одна из главных сложностей делания чего либо нового с нуля на заказ это добиться взаимопонимания внутри команды проекта. Под командой проекта здесь понимается вся совокупность людей, принимающих участие в проекте. Вот неполный список кто это может быть:
бизнес-эксперты заказчика;
IT заказчика (специалисты занимающиеся архитектурой, поддержкой эксплуатируемых систем);
команда непосредственно занимающаяся разработкой;
сторонние подрядчики (аудит, ИБ, разработчики выделенной функциональности внутри проекта);
вендоры готовых используемых/интегрируемых решений;
специалисты из команд соседних (связанных) проектов.
Организовать обмен информацией между специалистами, имеющими разные профессии, разные интересы (в рамках проекта), да и просто разные личные качества - задача одновременно сложная и важная.
В индустрии выработано множество методологий и практик, позволяющих управлять такими рисками, в рамках этой статьи хотелось бы поговорить о совсем небольшой но, на мой взгляд, важной части: использовании графики в документации.
Дело в том, что люди, как правило, легко вовлекаются в потребление графического контента, поэтому есть смысл составлять проектную документацию с использованием графических представлений информации (схемы, эскизы, диаграммы). Это повысит степень погружения участников проекта в документацию, как за счет привлечения внимания при самостоятельном изучении, так и при демонстрации на встречах или при общении один на один. По моему личному опыту, наличие хорошей, предметной графики снижает уровень абстракции в любом диалоге.
Еще раз оговорюсь, в статье не рассматриваются методологические аспекты выполнения проектов, рассматриваются только отдельные виды артефактов и способы их изготовления. О назначении каждого вида графической нотации и его роли на разных этапах проекта и в разных видах документов можно почитать отдельно, каждый из них заслуживает отдельного цикла статей.
Какие языки используются для визуализации?
Графических языков, общепринятых соглашений и просто приемов визуализации существует довольно много, вот некоторые из них, которые использую лично я:
-
BPMN для документации бизнес процесса. Этот язык удобно использовать для формализации бизнес-процессов. Он помогает ответить на вопросы:
Какие роли пользователей используют прикладное решение?
Что конкретно пользователи будут делать, в какой последовательности и как их действия зависят друг от друга?
Что и в какой момент система должна делать автоматически?
Какие действия не подлежат автоматизации?
Как устроены информационные потоки в рамках автоматизируемых процессов?
Эскизы интерфейсов. Это упрощенные наброски внешнего вида графических интерфейсов будущей системы. Иногда (и довольно часто) пользователю удобнее понимать вас глядя на конкретные экраны и кнопки, с которыми он потом и будет фактически взаимодействовать. Сюда же можно отнести такие приемы визуализации пользовательского опыта как User-flow, Screen-flow, которые, по своей сути, представляют собой гибрид схемы бизнес-процесса и макетов экранов приложения: пользователь может связать последовательность своих действий со внешним видом интерфейсов.
UML. Этот почтенный язык предоставляет нам набор видов диаграмм, которые позволяют документировать то как технически устроена система. Этим языком мы можем описать архитектуру системы на уровне ее компонентов, описать атрибуты, методы и отношения сущностей, описать последовательность событий происходящих в системе и многое другое.
Docs as code
Итак, допустим мы понимаем важность графики, знаем спецификации BPMN, UML, знаем как базово устроены UI. Дело за малым: осталось внедрить процесс изготовления графики в свой процесс изготовления документации.
Для того чтобы создавать такие артефакты, необходимо использовать специализированное программное обеспечение. Как правило, это графические редакторы, предлагающие пользователям (условно, аналитикам) рисовать схемы, а не описывать их текстом. У такого подхода существуют проблемы. Попробую аргументировать:
Когда ты рисуешь схему или макет, ты занимаешься отдельно рисованием и отдельно размышлением о смысле того что ты пытаешься изобразить. Ты вынужден тратить время (и значительное) на рисование как таковое (выровнял элементы на макете, чтобы они располагались ровно? решил изменить текст? Отлично! Выровняй все еще раз). Более того, рисование не просто забирает время, оно отвлекает от размышлений о предмете.
В процессе общения внутри команды проекта, возникают уточнения / корректировки (и это классно, потому что мы хотим эффективно вскрыть максимум проблем при проектировании а не отложить их до разработки, тестирования или даже запуска). Насколько удобно вносить эти изменения в графику? Насколько удобно отслеживать внесенные изменения?
Для решения этих (и некоторых других) проблем, в индустрии существует подход «Documentation as code». В широком смысле, этот подход предназначен для создания, хранения, версионирования всей документации (а не только графики) в виде кода (используются специализированные языки разметки, как правило язык «Markdown» и его расширения) и последующей генерации готовых документов из текстового представления.
Нас же интересует вопрос «Как работать с графикой если мы хотим в «Documentation as code»?
Представление графических артефактов в виде разметки
Для того, чтобы работать с графикой как с текстом, нам нужны:
язык разметки, позволяющий задать все необходимые атрибуты каждого элемента каждой отдельно взятой графической нотации;
средство для автоматического преобразования текстовой разметки в готовую для вставки в документацию картинку.
Отдельный момент это интеграция языков разметки, отличных от «markdown» в пайплайн сборки итоговых файлов документации, его мы в этой статье рассматривать не будем (но возможно, рассмотрим в следующих если тема вообще зайдет).
Окей, мы хотим писать текст и генерировать картинки, что нам предлагает рынок? Давайте посмотрим на виды графической нотации, которые выбрали ранее. Я поделюсь той информацией которую нашел сам пока пытался решать проблему, так что прошу вас отнестись к этому как к одной из версий правды, а не как к конечной истине.
BPMN.
В случае с BPMN, есть подробная спецификация в которой, в числе прочего, содержатся исчерпывающие указания о том, как описывать бизнес процессы в XML. Понятно, что мы не хотим вручную писать и поддерживать XML представления и не хотим знать спецификацию наизусть, тем не менее, задача генерации BPMN по формальному XML представлению, кажется решена: существуют как open-source так и коммерческие продукты решающие ее. Поэтому остается вопрос «как сгенерировать XML описание, соответствующее спецификации по более дружелюбному текстовому представлению».
И действительно, на рынке есть сервисы, которые предоставляют нам, во-первых, более дружелюбное json-представление для работы с BPMN и, во-вторых, позволяют автоматизировать мэппинг json на xml. То есть, мы можем взять, например, сервис «Camunda», настроить в нем правила, которые позволят нам управлять схемами через условный rest - интерфейс в веб, передавая в него json представление, которое уже будет автоматически трансформироваться в XML (и, конечно же, в конечную картинку, иначе зачем вообще все это).
Таким образом, мы можем генерировать BPMN схемы по описанию в JSON. Однако, это потребует от нас времени на настройку системы, подписки на сервис, а также знания синтаксиса json и спецификации BPMN, так как у нас не будет контекстных подсказок. Организация контекстных подсказок - отдельная тема. Как вариант, мы можем создать свой DSL язык для BPMN и настроить автодополнения в редакторе кода, однако это не выглядит как простой путь готовый к использованию.
Эскизы интерфейсов и UML
Очевидный способ описать пользовательский интерфейс - создать его HTML разметку. Однако, стилизация HTML под UI бизнес приложения требует базовых знаний верстки и самого HTML и в целом для аналитика это не быстрее чем рисовать, поскольку он не специализируется на написании кода.
Существуют сервисы, предоставляющие функциональность генерации элементов UI по текстовому описанию, например в свое время я пользовался «Balsamiq», он позволяет редактировать отдельные элементы по текстовому описанию, но не позволяет генерировать весь макет по текстовому описанию.
Также существует сервис PlantUML, который позволяет формировать и эскизы интерфейсов и UML.
Горячо люблю этот сервис, о нем есть множество статей на хабре, в том числе с примерами описаний UX Flow и различных видов UML диаграмм. Это open source проект, с развернутым публичным сервером, который предоставляет функционал генерации схем по API в веб. Работает так: вы преобразуете разметку схемы в специальный хэш (для этого есть готовые библиотеки), отдаете хэш на API и получаете готовый svg или png. Хорошо работает с небольшими схемами. Для больших (действительно больших) схем придется развернуть свой сервер, но сначала, пожалуйста, спросите себя, действительно ли вам так нужны большие схемы. Также публичный сервер предоставляет простой текстовый редактор в котором можно производить разработку графики. Сервис неплохо документирован (документация есть на сайте сервиса).
Подытожим
Если вы хотите генерировать BPMN по текстовому описанию, то вы можете выбрать и купить BPM - сервис, настроить json - представление в этом сервисе, сделать или развернуть клиента который позволит вам передавать текст по API и получать графическое представление.
Если вы хотите генерировать эскизы UI или UML схемы, вы можете использовать PlantUML.
В обоих случаях вам придется писать текст на domain specific languages, без контекстных подсказок, синтаксических помощников и автодополнения. Зато со скобочками и латинскими токенами (а вам нравится переключать язык?). На мой субъективный вкус, это лучше чем рисовать, но по прежнему не удобно.
Как я пытался решать проблему
По каким то нерациональным причинам мне пришла в голову идея попробовать сделать свой язык разметки и элементарную среду, которая поможет работать с этим языком.
Язык должен был удовлетворять моим субъективным требованиям, под которые я не смог найти готовое решение:
быть максимально похож на естественный: содержать минимальное количество специальных символов, реализующих разметку;
простота набора в русской раскладке, в том числе с учетом доступности спецсимволов;
поддержка типов для описания различных элементов;
поддержка совместимости со спецификацией BPMN и с HTML, в части преобразования моей разметки в эти предоставления;
поддерживать вложенность, необходимую для описания наших артефактов;
поддерживать объявление типов объектов.
На этом все, из этих требований должно было следовать, что полученный артефакт будет легко описывать и это описание будет легко читать и изменять.
Среда должна была удовлетворять требованиям:
текстовое поле ввода
парсинг и подсветка вводимого кода «на лету»
плавающую за курсором менюшку с вариантами подбора и автодополнение выбранным вариантом по «Tab»
сохранение стейта на сервере в привязке к идентификатору клиента
конфигурирование языка для конкретных видов описываемой графики (списки токенов, ограничение допустимых значений атрибутов, значения атрибутов по умолчанию)
У меня нет опыта в таких задачах, за изучение матчасти никто не платил, поэтому все использованные решения наивны. Итак, дизайн решения я поделил на дизайн языка и дизайн приложения, реализующего среду для этого языка.
Дизайн языка
Чтобы с чего то начать, принял за отправную точку такие гипотезы:
В языке разметки сложно изобрести что то новое (по крайней мере я на это не претендую);
Для моих целей меня бы устроил XML, если бы из него можно было выкинуть все что мешает его быстро писать, читать и редактировать. Особенно с учетом того что описание BPMN и структура интерфейса в HTML это подмножества XML.
Давайте посмотрим на структуру XML тега.
<имяТега атрибут1="значение_атрибута">содержимое тега</имяТега>
Для покрытия наших требований нужно, чтобы один тег целевого языка содержал:
тип объекта (должен определять что собой представляет конкретный, описываемый этим тегом компонент графического артефакта)
имена атрибутов объекта (должны определять, какой именно специфический признак описываемого элемента сейчас будет задан)
значение атрибута объекта (само значение, определяющее признак)
к содержимому можно применить ограничение, что в нем будет хранится только набор других тэгов, потому что примитивный тип у нас будет только один – строка (в требованиях про примитивы ничего нет!) и эту строку мы всегда можем хранить в отдельном атрибуте. Таким образом, содержимое тега будем использовать только для обозначения вложенности.
Давайте посмотрим на конкретном примере, как на эту структуру смэпится описание небольшой формы с таким содержанием:
надпись (имя формы)
два поля ввода
две вкладки, одна из которых активна
внутри активной вкладки расположена надпись и еще один реквизит
снизу есть кнопка отправки формы
Описание такого артефакта в XML может выглядеть как то так:
<форма имя="Имя формы">
<надпись значение="Привет, заполни форму!"></надпись>
<реквизит имя="Реквизит 1" значение="foo"></реквизит>
<реквизит имя="Реквизит 2" значение="bar"></реквизит>
<вкладка количествоВкладок="2" номерАктивнойВкладки="1">
<надпись значение="Не имею представления, зачем это здесь" цвет="#00FF00"></надпись>
<реквизит имя="Заполните, пожалуйста"></реквизит>
</вкладка>
<кнопка имя="Отправить"></кнопка>
</форма>
Теперь попробуем оставить в тексте этой разметки все, что важно для человека и убрать все, что нужно для парсера и не востребованных нами фич языка XML.
форма имя Имя формы
надпись значение Привет, заполни форму!
реквизит имя Реквизит 1 значение foo
реквизит имя Реквизит 2 значение bar
вкладка количествоВкладок 2 номерАктивнойВкладки 1
надпись значение Я не имею представления, зачем это здесь цвет #00FF00
реквизит имя Заполните, пожалуйста
кнопка имя Отправить
Такой текст легко писать? Очень. Его легко читать? Не сложнее, чем писать. Такой текст можно распарсить обратно в XML? Если договориться о дополнительных ограничениях, то да.
Есть некоторое лукавство, связанное с тем, что переносы строк и отступы в XML добавляет человек, это не требование синтаксиса XML, но, кажется, это здорово сыграло. Для нас как людей пробелы, переносы строк и отступы это как раз то, чем мы пользуемся когда хотим структурировать текст на естественном языке. Давайте закрепим переносы строк и табуляцию в нашем синтаксисе и будем по ним разделять компоненты внутри артефакта и определять вложенность, соответственно.
Допущения и ограничения дизайна языка:
первый токен в строке это всегда имя типа объекта;
один объект описывается одной строкой;
табуляция определяет вложенность: если следующая строка имеет больший отступ, чем предыдущая, значит объект описываемый текущей строкой вложен в предыдущий;
после указания на тип объекта всегда следует имя атрибута объекта;
типы объектов и имена атрибутов не могут содержать пробелы;
непосредственно за именем атрибута всегда должно следовать его значение, после одиночного пробела;
перед именами атрибутов должна стоять лидирующая точка. Этот пункт вкусовой, мне показалось что начинать ввод имени с лидирующей точки - удобно в русской раскладке. Совсем без разделителей язык спланировать не удалось.
Кажется, мы не потеряли ни одно из преимуществ: такая разметка легко пишется, читается и изменяется. И еще кажется, что парсеру этот синтаксис тоже достаточен, чтобы однозначно разобрать текст на токены.
Итак, у нас есть наш наивный дизайн, теперь его нужно как то реализовать.
Дизайн среды
Что потребовалось в целом. Довольно быстро выяснилось, что основная сложность такой среды лично для меня, это необходимость поддержки сразу нескольких представлений для графического артефакта. Вот эти представления:
текстовое представление – это непосредственно тот текст который пользователь вводит с клавиатуры;
языковое представление (текст разобранный на токены с учетом их типов) – для подсветки синтаксиса;
HTML / CSS / JS представление – для отображения в браузере и поддержки интерактивности элементов (да, мне захотелось чтобы пользователь, помимо генерации из текста, при необходимости имел возможность редактировать графику вручную);
JSON представление - для сбора стейта на клиенте, и его отправки на сервер;
SVG представление – для экспорта в виде изображения;
.vsdx представление – заказчики довольно часто хотят видеть BPMN схемы не как картинки, а как редактируемые visio файлы, поэтому нужен экспорт в .vsdx файл
Для реализации переходов между этими представлениями, запланировал такую схему:
Пунктиром обозначены вещи без которых среда может работать как прототип, то есть которые допустимо отнести на вторую очередь разработки. Таким образом, система в базовом варианте сможет:
размечать текст при вводе (разбирать на токены и подсвечивать их в UI)
генерировать JSON представление из размеченного текста
генерировать HTML ( / CSS / JS ) из JSON представления для последующей отрисовки и исполнения логики браузером
опрашивать DOM для актуализации JSON стэйта
Окей, как видно, нужно реализовать парсер, транспилятор, рендерер и сериализатор, что и было сделано. Большая часть времени, ожидаемо, ушла на рендерер, а именно на реализацию алгоритмов размещения графических элементов (мы же не хотим прописывать координаты, ПО должно разместить элементы за нас) и на реализацию самой генерации кода элементов для браузера из их JSON представления.
Далее на это все нужно реализовать пользовательские интерфейсы, вот состав основных интерфейсных вещей на которые ушло время:
-
редактор кода:
текстовое поле ввода с подсветкой синтаксиса
контекстная подсказка (выпадающее меню) для ввода разметки, предоставляющая выбор из списка токенов для ожидаемого в данном контексте ввода типа
интерфейсы для редактирования DOM (дрэг энд дроп, изменение атрибутов представленных на схеме графических элементов)
-
вспомогательный функционал:
периодическая и принудительная отправка стэйта на сервер
генерация и хранение уникального идентификатора клиента, механизмы для логина (через форму и по ссылке)
локальная работа со стейтом и идентификатором
изменение настроек редактора
разделение схем на экраны и навигация между ними
копирование экранов и отдельных схем
Что получилось?
Ниже примеры разметки и рендеров, которые можно делать в получившемся приложении.
Что дальше?
закончить экспорт в .svg и .vsdx;
доработать алгоритм авторасстановки BPMN схем для части важных фич языка: ролей, граничных событий, вложенных подпроцессов. С наскоку реализовать не получилось;
перенос в веб механизма генерации доки : md + plantuml + разметка эскизов и процессов –> .docx.
механизм транспиляции в язык PlantUML
Заключение
Использую генератор UI в текущей работе, работать довольно удобно, макеты хорошо выглядят (на мой вкус). В принципе, вся разработка заняла приемлемое время. В целом, шалость удалась!
Правила Хабра запрещают оставлять ссылку на сервис, но если кому то интересно посмотреть или использовать, пожалуйста, пишите мне в телеграм: @ArtyomKonovalov
Спасибо за внимание если дочитали и удачи на проектах!
Комментарии (6)
vagon333
10.10.2024 11:42Идея красивая, чем-то напоминает Mermaid, но для BPMN.
Если предполагается формировать текстовое описание вручную, то для правильного форматирования нужна среда с IntelliSense и валидацией полученного текстового файла.
Иначе, не зная синтаксиса и не получая подсказок, процесс будет сплошная боль.
Если же вы предполагаете формировать текстовый файл на основании формочек, как в примере с 1С, то формат может быть лучше сделать более машиночитаемым, например JSON.
1287c13 Автор
10.10.2024 11:42Спасибо! Да, похоже на Mermaid или на PlantUML (вдохновлялся PlantUML).
Попытался сделать улучшение опыта в части написания/чтения самой разметки, а для синтаксиса сделал простенький редактор, он предоставляет подсветку и контекстную подсказку с автодополнением.
Ну то есть работает как везде: начинаем писать - под курсором появляется менюшка в которой выбраны варианты, подходящие с точки зрения ожидаемых типов токенов (например, если пишем имя атрибута для тэга "событие", то будут предложены все допустимые имена атрибутов этого тэга). Мы можем дописать руками или выбрать вариант и нажать "Tab" - произойдет автодополнение.
Выглядит так:
Если же вы предполагаете формировать текстовый файл на основании формочек, как в примере с 1С, то формат может быть лучше сделать более машиночитаемым, например JSON.
Пока что разметка сохраненных схем и формочек хранится и в JSON и "сырым" введенным текстом, но сам текст из формочек не генерируется, только из ручного ввода (как дойдут руки, планирую добавить чтобы генерировался). Выше в статье рисовал схемку, см. ниже: то что пунктиром - не работает. То есть если пользователь сделал форму руками в граф редакторе то текстового описания на нее не будет, только JSON, а если сгенерировал по текстовому описанию, то будет сохранено и оно и JSON.
sshmakov
Чем это лучше описания на yaml, для которого достаточно создать нужную json-cхему?
Читаемый
Легко передавать людям, не знакомым с нотацией
Может содержать markdown
Верифицируемый
Не надо создавать специальное приложение для цветовой разметки текста, т.к. есть куча сред, которые уже это умеют, и даже умеют в подсказку на основе схемы
Имеет фатальный недостаток
1287c13 Автор
Пытался в этом направлении думать, остановился на таких доводах (могу быть не прав, такое часто случается, поправьте меня пожалуйста):
Тип объекта в случае xml указывается в имени тэга, а в случае json или yaml нужно выносить его отдельный атрибут + имя объекта не уникально в пределах одного уровня вложенности. В совокупности это мне показалось не интуитивным, в том числе с точки зрения реализации набора с автодополнением. Ну то есть, если первое слово в строке это указание на тип, то в тот момент, когда система ожидает ввод типа мы просто предлагаем пользователю выбрать нужное имя и оно же печатается в редактор. А если тип указывается как атрибут, то возникают вопросы по дизайну (в связке с эргономикой) - не смог их решить.
Разделители для атрибутов в yaml это переносы строк => визуально сложно читать (ориентировался исключительно на свои ощущения). Ниже запись в ямл-подобном синтаксисе с игнорированием требования к уникальности имени объекта (вопрос с неуникальностью можно решить добавлением "-", то есть использованием неименованных списков, не стал записывать). Возможно, у меня просто нет глубоких знаний о фичах ямл, исходил из того что описание на нем будет выглядеть примерно так (ниже такое же описание как в примере в статье, для демонстрации читаемости):
Понимаю что плохой аргумент, но в рамках каприза: двоеточие в русской раскладке нужно набирать через shift.
Про фатальный недостаток, допускаю что он есть, можете подсветить пож-та?
sshmakov
Так же, как у вас: "процесс" = это тип объекта, и он стоит в начале описания объекта. Или вы о чем?
атрибут "тип" определяется в схеме с перечнем (enum) допустимых типов, тогда редактор предложит значение из перечня
Поскольку yaml - это тот же json, то нельзя в одном объекте иметь одинаковые ключи.
То есть вот так нельзя:
Можно вместо объекта сделать массив:
И, на мой взгляд, это более читаемое, т.к. состояния и задачи четко сгруппированы в отдельные элементы, каждый элемент списка имеет описанную структуру, порядок элементов определяется списком
https://yandex.ru/search/?text=фатальный+недостаток
https://neolurk.org/wiki/Фатальный_недостаток
https://www.rsdn.org/forum/dotnet/8558237.hot
https://ru.wikipedia.org/wiki/Синдром_неприятия_чужой_разработки
1287c13 Автор
Да, спасибо за замечание.
По использованию массивов вместо именованных объектов размышлял (в комменте выше писал об этом), мне показалось что писать ямл с таким допущением сложнее, чем разметку из примера, и читать, в свою очередь, тоже сложнее, потому что она занимает больше места по вертикали и мозгу нужно как то интерпретировать черточки и отступы. Плюс еще есть аргумент, которые писал выше про указание типов объектов (задача/событие/шлюз и т.п.) в свойствах сущностей а не в тэгах, как в xml.
Ну то есть вместо
нужно будет написать
Однако, вероятно, я не прав. Записал себе на развитие все таки сделать ямл.
По велосипедам - каюсь, грешен. Даже в названии статьи попытался обыграть "yet another" :) Мне действительно показалось что есть какие то улучшения, поэтому сделано то что сделано.