Минимальный фреймворк для ведения документации

Думаю, никому не стоит объяснять, что документация к проекту такая же важная часть этого самого проекта, как и его код. Однако почему-то о качестве кода заботятся многие, а о доке - единицы. Мы пишем тесты, оставляем комментарии к неочевидным местам в коде, рассказываем и слушаем выступления про чистые архитектуры. А об описании системы не думаем…

Вы вот знали, что есть разные фреймворки для ведения документации12? Я вот нет :)
Но на самом деле, когда узнал, легче не стало, и об этом далее.

Классическая документация #

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

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

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

Мем Pepe Silvia: мужчина с сигаретой объясняет запутанную схему на доске с бумагами и красными нитями
Новый разработчик восстанавливает знания о системе по коду

Хорошая документация #

А что это?

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

I. Она есть #

Во-первых, как я упоминал выше, она должна быть и быть актуальной.

К сожалению, актуальность поддерживать непросто, и тут придется договориться с командой: «при значимых изменениях в проекте мы меняем и описание этой системы». Все. Других способов поддержания актуальности нет.

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

II. Простая #

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

Тут-то мне и не зашел arc42. 12 сущностей - это, конечно, круто. Можно, наверное, описать любую систему. Но я вот добавил новую крону в систему, мне куда ее разместить? Именно этим вопросом задастся младший специалист и просто забьет на ведение доки, ведь «это что-то для senior’ов». Так что чем проще структура, тем лучше.

Способ повествования тоже относится к этому пункту. Если для описания какого-то процесса вам хватило 2-х предложений, не надо пытаться придумать больше: со временем этот текст обрастет подробностями, если это будет необходимо. Тем более не надо вставлять AI-слоп на 3 экрана. Если уж вы при написании поленились прочитать все и сократить, остальные инженеры тем более не будут вникать в происходящее.

III. Рассказывает что-то новое #

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

«Когда сумма покупки превышает 7462 рубля и в корзине есть носки, мы дарим пользователю перчатки» - такая себе дока. Сегодня сумма одна, а завтра другая. Сегодня проверяем носки, а завтра не носки. При каждом изменении кода придется менять и это описание.

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

Не пытайтесь пересказывать код. Пытайтесь рассказать то, что из кода малоочевидно. Вместо описания носков и перчаток лучше зафиксировать саму механику подарков за покупки.

Что я придумал #

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

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

Представляю вашему вниманию минималистичный фреймворк имени Алана Смитти:

docs/
├── architecture.md
├── adr/
│   ├── 0001-use-redis-pub-sub.md
│   └── 0002-migrate-from-mongodb.md
└── features/
    ├── gifts.md
    └── wish_lists.md

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

Но вернемся к сути. Почему именно такой набор?

Архитектура #

Во-первых, архитектуру по коду зачастую сложно восстановить. Особенно если микросервисы и нет монорепы. А даже если у вас монорепа или монолит, с ходу понять, кто какую Kafka читает - сложно.

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

Я рекомендую для описания архитектуры начать с какого-то очень простого способа. Например, Mermaid4 и C45. Это позволит команде потренироваться описывать систему и со временем выработать свои требования.

В этом разделе не размещайте только диаграммы. Не стесняйтесь использовать и буквы для передачи смыслов. Например, можно кратко описать, зачем нужна какая-то крона, и приложить ссылки на features/. Или можете указывать для внешних систем ответственные за них команды.

Architecture Decision Record #

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

Бывало у вас, что вы смотрите на новую систему и не понимаете, зачем тут воткнули какой-то Redis pub/sub вместо всем любимой Kafka? Кафка ведь в разы лучше подходит и уже используется в системе. Повезет, если в компании остался разработчик, который принимал это решение и сможет рассказать вам: «Раньше команда была маленькая, и мы экономили на чем могли. Редис у сервиса уже был, а Kafka для компании была сильно дорогой, не было devops, кто мог бы ее поддерживать».

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

Форматов в интернете для описания этих records великое множество, но я снова предлагаю начать с чего-то минималистичного и позже нарастить мясцо:

# 0001. Использование Redis Pub/Sub

## Статус

Принято.

## Описание

Системе нужна шина данных для передачи сообщений между компонентами. Средств и возможностей нет для
поднятия Kafka, а Redis уже есть. Поэтому решено использовать pub/sub.

## Последствия

- компоненты системы могут обмениваться сообщениями;
- Redis для кэша сервиса X превратился в коммунальный редис нескольких систем, нужно мигрировать на
  Kafka [TASK-123]

Обращаю внимание на Статус. Мне кажется, стоит фиксировать не только принятые решения, но и отклоненные, чтобы снова не возвращаться к уже решенным вопросам.

Важный нюанс при ведении ADR: если все остальные сущности вы можете описать у уже существующей системы без доки, то эту не получится. Не надо пытаться придумать, почему тут используется Redis. Если не помните / не знаете, ничего не пишите! Иначе документация рискует стать ошибочной и вводящей в заблуждение. Вам может казаться, что Redis тут используется из-за модели fire & forget, а на самом деле «так исторически сложилось».

Функции системы #

В каталоге features/ предлагаю размещать основные фичи вашей системы. Не обязательно дробить систему на миллион маленьких функциональных особенностей, например, на «подтверждение профилей», «права администратора», «блокировка аккаунтов» и т. п. Лучше описать 1 раздел «система прав», где упомяните, что есть и подтверждение, и блокировка. Если читателю нужна будет конкретика, он всегда может занырнуть в код (мы все-таки для инженеров пишем доку).

Также стоит помнить, что 1 ручка != 1 функция. Как правило, к конкретной функциональности относятся несколько ручек/микросервисов/кронов.

Если архитектура отвечает на вопрос «как система устроена», ADR - «почему система устроена именно так», то features отвечают на не менее важный вопрос «что вообще система делает?».

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

Плюс новеньким на проекте не надо проводить онбординг, если есть этот раздел :)

Как этим пользоваться? #

Мем о совещании: на вопрос об улучшении документации предлагают arc42, все четыре уровня C4 или три .md-файла рядом с кодом. Автора последнего предложения выбрасывают из окна

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

Также стоит понимать, что это не жесткие требования к способу ведения технической документации. Это лишь минимальный набор сущностей, который, по моему мнению, стоит описывать в первую очередь. Если ваша система настолько сложная, что нужен глоссарий - добавляйте. Если вся архитектура не помещается в 1 .md-файл, превращайте его в папку со слоями или отдельными сервисами.

Начните с архитектуры, зафиксируйте границы существующей системы. При ее описании в формате C45 не пытайтесь восстановить все 4 слоя. Начните с первых двух. Не понимаете, как система выглядит на втором уровне? Опишите только первый! Со временем появится конкретика и детали - дополните.

Пообщайтесь с бизнесом, потыкайте систему палочкой, определите, какие фичи есть, и зафиксируйте их. Нет конкретики про ролевую систему? Опять же, ничего страшного: со временем появятся подробности. Помните, что 3 поверхностно описанные фичи лучше, чем 0.

Когда принимаете какие-то архитектурные решения, фиксируйте их в adr и требуйте того же от коллег.

Ну и самое главное:

Пиши, бумага все стерпит

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


  1. Например, arc42 - довольно известный фреймворк для инженерной документации. ↩︎

  2. Или нынче модный-молодежный OpenSpec  ↩︎ ↩︎

  3. Simon Brown на dev.to описывает очень похожую структуру. ↩︎

  4. Mermaid  ↩︎

  5. C4 model  ↩︎ ↩︎