Почему я использую doc-as-a-code

В этой статье я постараюсь рассказать и показать, почему я использую подход doc-as-a-code, как помогает git системному аналитику и зачем это всё. И «почему не confluence?»

Процесс разработки

Начнём с простого. Процесс разработки.

Процесс разработки цикличен и более-менее стандартизирован от компании к компании. При этом мы применяем принцип «documentation-first».

disignProcess.svg
Процесс разработки

Давайте проговорим его:

  1. Приходит заказчик, садится с бизнес аналитиком (БА) и рассказывает, что же они хотят от системы. Или с продактом. Или с продуктовым аналитиком. По разному называют эту роль в разных компаниях. Результат примерно одинаковый. На выходе у БА должны быть бизнес требования, в виде текстового описания «что система делает», BPMN схем бизнес процесса, описания пользовательского пути, прорисованные макеты, постановки в виде user-story. В зависисимости от опыта БА и требуемого качества это может быть целевой документ, а могут быть разрозненные кусочки в виде задач.

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

  3. Архитектор переносит бизнес процессы и накладывает их на архитектуру. Используя к примеру Archimate, он отрисовывает бизнес слой и проектирует, как он будет реализовываться на уровне приложений. Опять-таки, в разных компаниях — по-разному. Иногда роль архитектора передают в команду разработки и этим занимается ведущий аналитик или тех лид. Сути это не меняет: перед детальной проработкой необходимо выбрать архитектурное решение и задокументировать его не только в виде ADR, но и в целевой архитектуре, в чем бы она не велась.

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

  5. Когда готовы бизнес требования и архитектура, команда приступает к работе. Если Архитектор и БА работали над эпиком и декомпозировали его на стори, то команда разработки берет стори и реализует её. Стори — это какая-то минимальная бизнес ценность, которая может быть доставлена.

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

  7. После того как спецификация готова (или изменена) проводится ревью. На ревью обсуждается, какие именно изменения в какие части кода и системы должны быть внесены. Про ревью спеки тоже поговорим подробнее чуть позже. Если необходимо, в спецификацию вносятся изменения. Главное: Если вы исповедуете «documentation first», то следите за этим строго! Сначала правка в спеку, потом правка в код. И никак иначе.

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

  9. Каждый разработчик выполняет свою задачу (task, subtask и т.п. в зависимости от того, как вы работаете с доской). В задаче описаны детали, касаемые функционала системы, который необходимо разработать. Например «Добавить поле в эндпоинт и сохранить его». Только выполнив все задачи в этой стори бизнес ценность будет доставлена.

  10. Тестирование может быть организовано как по отдельным задачам, так и всей стори целиком. Детали организации тестирования я опущу.

  11. Когда все работы по сторе завершены, проводится демонстрация заказчику. В случае успеха — ценность доставляется на прод. В случае неудачи — цикл повторяется сначала.

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

Что важно в этом процессе:

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

  2. Строго соблюдать принцип documentation first. Если он не соблюдается, то очень часто из-за спешки, документирования откладывается в тех долг. В результате у вас есть работающий код, но нет документации на него. В большинстве компаний, где роли системного аналитика нет, или под SA понимают бизнес аналитика, разработка идет без документации. В результате, когда команда меняется и вся экспертиза остается в головах ушедших сотрудников, компании надо в два раза больше ресурсов, чтобы доработать такой код.

  3. Все артефакты документирования — обязательны.

    • Без бизнес-постановки не понятно, какой результат ожидает заказчик. И как заказчик будет принимать работу.

    • Архитектура связывает воедино бизнес требования и системную спецификацию и прорабатывает взаимодействие на более высоком уровне.

    • Системная аналитика (спецификация) подробно рассказывает, что происходит под капотом системы. Как работает и как будет работать система и её отдельные части.

    • Тесткейсы позволяют стабильно проверять работоспособность кода после любых изменений и не допускать баги на прод. Если вы опускаете какой-то из артефактов — у вас разрыв в требованиях. Например, без документированной архитектуры сложно понять, как и в каких системах реализованы определённые бизнес требования.

  4. Артефакты документации нельзя смешивать. Один из частых примеров это работа фулстек аналитиков. Бизнес-системных-аналитиков. В производимых ими документах часто нет границы между бизнес сущностями и системными сущностями. В них можно увидеть рассуждения, что сущность «Заказ» хранится в БД. Хотя «Заказ» это бизнес сущность, у которой есть бизнес атрибуты. А в БД хранятся записи в таблицах, которые соответствую этой бизнес-сущности. Это два разных уровня абстракции, которые нельзя смешивать. В системе работа происходит с системными объектами. Записи в БД, объекты запросов, сообщения и т.п. Бизнес оперирует своими понятиями и «Заказ» это не обязательно одна запись в БД. Это может быть множество связанных записей и объектов, передаваемых и хранящихся внутри системы. Обратная сторона — это системы без продуктовой аналитики. Знаете, когда все постановки спрятаны где-то в задачах и конечной документации вообще нет. При восстановлении бизнес процессов вместо использования бизнес понятий начинают использовать системные. Вместо «Платеж передается в систему расчёта начислений» в бизнес постановке написано «Платеж отправляется в очередь kafka» У этого правила есть особенность: Да, смешивать документы нельзя. В бизнес требованиях не должно быть системных атрибутов. Но есть особенность описания системных требований. В системных требованиях хорошим тоном считается не только описания системного действия (отправьте сообщение в такой-то журнал), но и какому бизнес действию оно соответствует. Например «Получите список заказов клиента. Для этого выполните запрос …» Это облегчает понимания документации и её сверки с бизнес постановкой.

Системная документация

Основные принципы мы проговорили. Понимаем, что речь дальше пойдёт о системной документации, спецификациях на сервисы, описании эндпоинтов, страниц фронта, сообщениях в очередях и структуре БД.

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

Даже если у вас крутится Camunda, которая реализует какой-то бизнес процесс, помните: Есть схема бизнес процесса в бизнес требованиях. И есть BPMN схема с обработчиками в коде.

Это две разные схемы, хоть одна и реализует другую.

Как структурирована идеальная документация в моем мире и при чем здесь doc-as-a-code

Вообще, со мной произошёл странный казус, который в корне поменял мое представление о системной документации. Когда я первый раз услышал термин doc‑as‑a-code я понял это так:
«Структура документации соответствует структуре кода». Ну как понял, так и пошел писать, дабы учителя понимали так же.

В результате структура документации на обычный backend REST сервис состоит из следующих артефактов:

  • Swagger для описания контрактов взаимодействия. Или proto-схема, если у вас grpc.

  • Спецификация каждого эндпоинта, состоящая из:

    • Пути запроса и его параметров

    • Примеров тела запроса и ответа

    • Sequence-диаграммы со всеми интеграциями

    • Логика исполнения эндпоинта, в которой указывается

      • какие запросы выполняются в какой последовательности

      • какие данные и как сохраняются

      • какие сообщения в какие журналы передаются

      • какие компоненты сервиса вызываются

    • Если логика сложная — activity диаграмма

    • Маппинга полей для сохраняемых и передаваемых данных

  • Описание всех таблиц в виде DDL файлов или DBML (если реляционная БД) или коллекций в виде yaml-файлов (для нереляционок)

  • Если сервис читает сообщения в журналах, то описывается логика каждого консьюмера.

  • и readme файл, содержащий общую информацию о сервисе со ссылками на все его компоненты

Если есть frontend, то спецификация аналогичная:

  • на каждую страницу — артефакт документации, включающий:

    • макеты экранных форм

    • мапинг предзаполнения полей

    • мапинг отправляемых данных

    • логика обработки получаемых данных

    • логика работы элементов формы

Если у вас сервис, на котором крутится camunda, то документация будет содержать:

  • bpmn схему

  • описание логики получения событий

  • описание логики задач

  • описание шлюзов

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

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

При этом есть один важный момент: такие артефакты как swagger, описание сообщений в asyncApi и таблицы, описанные на DDL — это часть работы разработчика, которая передаётся аналитику.

У этой парадигмы есть плюсы и минусы.

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

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

Теперь по настоящему doc as code

«Ну хорошо» — скажете вы — «всё то же самое делается в конфе. При чём здесь Git?»

Про сам подход уже много чего написано. Наверное, я не буду здесь пионером и во многом повторюсь.
Суть:

  • Документация ведется в репозитории Git.

    • может лежать в репозитории сервиса и быть его частью

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

  • для спецификаций используются:

    • swagger / openApi — контракты REST сервисов

    • protobuf схемы — контракты сервисов grpc

    • asyncApi — требования к журналам сообщений

    • markdown, asciidoc — спецификация артефактов

    • plantUML, mermaid — диаграммы

    • ddl sql, dbml, yaml — требования к БД

  • Правки в документацию вносятся через merge/pull request

  • Возможность распределённой работы с документацией

  • Версионирование средствами Git

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

На живом примере

Теперь самое интересное.

Давайте соберем это всё в кучу, и посмотрим, как это ложится на процесс разработки и как будет работать. Заодно поймем, почему в конфе такого сделать не получится.

За спецификацию у нас отвечает системный аналитик, про его работу и поговорим.

Представьте:
У нас есть некая система, состоящая из Фронта, промежуточного слоя BFF (back for front) и глубокого бэкэнда.
И есть функционал «Создание заказа».
На фронте пользователь нажимает кнопку «сохранить», отправляется POST запрос в BFF который проверяет данные и передает их в бэк. Бэк сохраняет их в БД и отправляет сообщение в какой‑нибудь журнал.
Такая вот нехитрая архитектура.
Это всё у нас уже разработано и работает. И задокументировано!

И вот к нам приходит продакт с постановкой: добавьте на форме чекбокс «срочный заказ». Если пользователь его устанавливает, то меняется стоимость заказа, и менеджер должен получить особое уведомление.

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

Наша команда отвечает только за первую часть бизнес процесса — «Создание заказа». Уведомление менеджеров и взаиморасчёты — это другие команды.

Обсудили решение, и системный аналитик взял сторю в работу.

Напоминаю, что мы строго придерживаемся принципа «documentation first» (включая api).

По результатам работы он внесёт изменения в следующие артефакты:

  • Спецификация формы «Создание заказа» на фронте

  • Спецификация эндпоинта createOrderBFF в BFF

  • Swagger BFF

  • Спецификация эндпоинта createOrderBE на бэке

  • Swagger BE

  • DDL-скрипт таблицы orders (или описание таблицы, если постановка на БД ведётся по старинке)

  • Спецификация журнала OrderCreated

  • asyncApi журнала OrderCreated

и добавить ещё два артефакта:

  • Спецификация журнала UrgentOrderAppointment

  • asyncApi журнала UrgentOrderAppointment

Итого у нас затронуто 10 артефактов.
В Git это будет 10 разных файлов.
В конфе это будет 5 статей и 5 приложенных к ним файлов.

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

Используем классический подход

Как будет выглядеть процесс, если у нас документация ведется в системах а-ля wiki, или даже word:

proceeWithoutGit.svg
proceeWithoutGit.svg

Т.е. аналитик должен:

  1. Внести изменения в 10 артефактов. (Я встречал подход, в котором изменения маркируются в тексте спецификации разными цветовыми маркерами. После разработки маркеры надо удалять.)

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

  3. Согласовать эти изменения. Если будут замечания (разработчики решили, что нэйминг поля не соответствует регламенту) — повторить всё ещё раз.

  4. Выписанные изменения перенести в задачи.

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

Как, в таком случае, отличить правки одного аналитика от другого? Помечать разными цветами? А как потом эти цветовые маркеры удалять? И в какой момент?

А теперь представьте, что в момент согласования задачи с разработчиками пришел продакт и сказал: стоп ребятки! У нас есть более важная задача: добавить в заказ поле «Комментарий сборщику».

Или быть может эту сторю уже делает второй аналитик, и работает параллельно.
Что делать? Откатывать документацию? Оставлять как есть с надеждой, что сделаем в следующем спринте? А какая версия свагера поедет в релиз? С обоими полями?

Используем doc-as-a-code

А теперь представим, что у вас doc-as-a-code. В этом случае процесс работы аналитика заметно упрощается. Пункты практически те же, но их качество кардинально другое.

GitProcess.svg
GitProcess.svg
  1. В начале работы с задачей SA создает новую ветку в репозитории спецификации.

  2. Все правки в документацию вносятся в эту ветку и по завершению работы создаётся один Merge/Pull Request (MR). Если у вас документация на все сервисы лежит в одной репе, а не в репозитории кода — то это один MR.

  3. Созданная ветка живёт своей жизнью. Пока MR не слит — она не затрагивает текущую версию вашей документации. Даже если вы решите не делать эту сторю, наработанные изменения не попадут в основную ветку, но их можно будет «прикопать» на будущее.

  4. Если несколько аналитиков параллельно работают над разными задачами, то каждый вносит правки в свою ветку. И пока MR не слит, эти правки не влияют друг на друга.

  5. При согласовании с разработчиками обсуждается DIFF в этом MR, который генерируется автоматически. А в нём видны все внесенные изменения. Если надо что-то поменять — правки идут отдельными комитами в ту же ветку и DIFF автоматически обновляется.

  6. После согласования MR сливается. Документация в целевой ветке обновляется. При этом вам по прежнему доступен DIFF. А также вы можете легко откатить всё внесенные изменения, если работу пришлось отменить.

  7. В созданных задачах указывается ссылка на конкретный файл в DIFF, относящейся к конкретной задаче на разработку.

Таким образом, системный аналитик делает свою работу один раз и получает всё необходимое:

  • обновленную целевую документацию

  • перечень, что надо изменить со ссылками на изменяемые артефакты

Даже если после согласования с командой есть необходимость в правках, то исправляется всё в одном месте.

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

Ах да, у нас же пришел продакт и попросил «сделать другое»…
Что ж… это тоже достаточно просто:

  1. Откатываем MR. Это одно простое действие. Вам не надо бегать по всем артефактам и вспоминать, «а как было до этого».

  2. Делаем новый MR для новой задачи.

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

Парам-пам-парам-пам! Всё!

Ещё пара слов

Doc as a code это не только упрощение процесса ведения вашей документации.

Хочу отметить ещё несколько моментов:

  1. Артефакты документации могут быть преобразованы в артефакты кода. Что это значит:

    • используя swagger и asyncApi можно автоматически генерировать DTO в коде

    • используя DDL SQL можно генерировать миграции

  2. Для написания кода используется IDE. Это позволяет:

    • работать в offline

    • использовать специализированные плагины, вместо онлайн ресурсов (тот же swagger, plantuml)

    • использовать ИИ-ассистенты. Это реально ускоряет написание спецификации процентов на 20…

    • использовать ту IDE, которая удобна вам, а не ограничиваться возможностями вашей wiki системы

  3. Более продвинутое версионирование, чем в confluence.

    • если вы используете правильный процесс изменения спецификации через MR, то для каждой измененной строки можно найти MR, в котором она была изменена. А MR привязан к задаче.

    • используя специальные инструменты IDE вы можете видеть, что этот же артефакт сейчас исправляет другой аналитик.

  4. Продвинутое использование артефактов документации.

    • PlantUml с операцией include позволяет вести разные представления диаграмм из одного источника в нескольких публикациях. Вам не придётся поддерживать одинаковые диаграммы в нескольких местах.

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

Резюме

Не могу сказать, что для меня ведение системной документации в Git стало чем‑то революционным. Я просто попробовал, и больше не смог вернуться на старые рельсы.
Да,  был период косяков с MR‑ами, освоения markdown, plantUml, DDL SQL, работы с ветками и т. д.

Да, на освоение новых инструментов нужно время. По моим прикидкам, если у вас уже есть гуру doc‑as‑a-code, то за месяц аналитики перейдут на новый процесс.

Если нет — то за три. Да, будут набиваться шишки. Да, иногда будет не хватать красивого форматирования, и придётся оттачивать подход другими способами.

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

И перейдя на этот процесс, будете задаваться вопросом: «а как мы до этого всё это делали?»

© Habrahabr.ru