Документация как код 15.06.2024

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

Предисловие

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

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

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

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

Требования

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

Доступность

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

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

Простота создания

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

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

Форматирование

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

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

Также из предыдущего требования вытекает, что все эти форматирования не должны требовать от разработчика каких-то особенных знаний, а в идеале IDE должна предоставлять горячие клавиши для типовых действий, например CTRL+B для полужирного.

Медиафайлы

Документация — это не только текст, заголовки и блоки с кодом. Это также схемы: BPMN, Event Storming, UML, ERD и так далее. Мы хотим видеть их в том же самом тексте, чтобы не переключаться между разными ресурсами и сопоставлять между собой.

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

Более того, мы не хотим рисовать схемы руками. Мы хотим декларативно описать результат через Mermaid, D2 или подобные им языки и ожидать, что диаграмма сама нарисуется, не заставляя нас экспортировать как картинки и вставлять в текст также как картинки. Или файл drawio, который внутри XML, автоматически преобразовался в диаграмму внутри текста без ручных экспортов в PNG.

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

Структурирование

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

В идеале иметь поисковую строку в дополнение к навигации и оглавлению, лишним уж точно не будет.

Проверка и утверждение

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

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

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

Своевременность доставки

В какой момент времени мы должны внести изменения в документацию? До того, как отдадим в тестирование? До того, как отправим выполненную задачу в подготавливаемый релиз? После всего этого?

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

Здесь важно понимать, что документация — это точно такой же код (отсюда и подход documentation as code), который должен разворачиваться в отдельном тестовом окружении и попадать в релиз вместе с остальным кодом. Своевременно.

Что документировать?

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

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

Для себя я однозначно определил следующие моменты, которых мне наиболее сильно не хватает при работе с разного рода проектами:

  • бизнесовые определения и сокращения в виде словарика;
  • цель проекта, чтобы понимать, о чем вообще проект и что мы тут решаем;
  • схема взаимодействия всех подсистем, включая базы данных, телеметрию и прочее;
  • принцип работы — высокоуровневое описание со схемами, показывающее точки интеграции (API) с сервисом, какие-то внутренние фоновые процессы, openapi для HTTP;
  • безопасность, включая верификацию, аутентификацию и авторизацию;
  • мониторинг, в который входят как бизнесовые метрики, так и прикладные и инфраструктурные;
  • ADRы, чтобы понимать, почему архитектура именно такая;
  • ссылки на все куски проекта, включая URI тестовых контуров, мониторинги и так далее;
  • ограниченные контексты и их подконтексты — крупнопланово хотя бы в виде карты контекстов;
  • агрегатные сущности, их ValueObject'ы, описание полей с предусловиями, доменные и прикладные юзкейсы;

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

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

В качестве послесловия

Мы остановились на MkDocs, который позволяет описывать всю документацию в привычном Markdown, а конфигурация описывается в простом YAML-файле. Он полностью подошел под требования, имеет возможности для расширения через плагины, но, конечно, не претендует на роль самого идеального инструмента. Попробовали, понравилось, внедрили, используем.

А на этом я закончу, надеюсь, кому-то данная статья будет полезной.