Skip to content
PПромтбук
RUEN
04Документация

ADR-практика: lifecycle, что туда писать, что НЕ

Когда писать ADR (architectural, не каждый PR), формат, lifecycle (proposed/accepted/superseded), как сделать живым, что НЕ ADR.

Запусти ADR-практику в {{project}}. Это про процесс и lifecycle, не про шаблон одного документа.

Базовая аксиома: ADR — это не «вся документация». Это архивные snapshots выбора между альтернативами в момент принятия решения. Они отвечают на вопрос «почему 2 года назад выбрали X а не Y» когда автор уже ушёл. Если этого вопроса не возникнет — ADR не нужен.

1. Когда писать ADR (а когда нет)

Пиши ADR когда:

  • Выбираешь между 2-3+ реальными альтернативами, и выбор не очевиден
  • Решение архитектурное: затронет несколько сервисов / модулей / команд
  • Дорого откатиться (БД, фреймворк, протокол, схема событий, провайдер)
  • Внешний интерфейс / контракт публикуется
  • Принципиально нарушается существующий паттерн в кодовой базе
  • Решение принято на встрече / переписке — нужно зафиксировать
  • Будущему разработчику стопудово непонятно «почему так»

НЕ пиши ADR для:

  • Implementation details (как именно назвать переменную, какой алгоритм сортировки)
  • Bugfix / refactor без альтернатив
  • Choosing library X over Y когда обе одинаково подходят (запиши одной строкой в README)
  • Изменение которое легко откатить (git revert и забыли)
  • «Решений по умолчанию» которые следуют существующему гайдлайну
  • Просто чтобы было — формальный ADR который никто не прочитает хуже отсутствия

Тест: «Через 2 года новый разработчик читает код и спрашивает: почему так сделано? Если ответ нетривиален и требует контекста — был нужен ADR. Если ответ "это очевидно" или "стандартный паттерн" — не нужен.»

2. Формат: четыре обязательных раздела

# ADR-NNN: <короткое название в активном залоге>

**Status:** Proposed | Accepted | Superseded by ADR-NNN | Deprecated | Rejected
**Date:** YYYY-MM-DD
**Authors:** @alice, @bob
**Deciders:** @cto, @tech-lead-payments

## Context

[Какую проблему решаем. Без вариантов. Без решения. Только проблема и ограничения.]

- Бизнес-требование: ...
- Технический контекст: что уже есть в системе
- Ограничения: бюджет, время, навыки, существующая инфра
- Стейкхолдеры: кто заинтересован

## Decision

Мы выбираем **<краткое имя варианта>**.

[1-3 параграфа: что именно делаем. Не «почему», а «что».]

## Alternatives considered

### Option A: <имя> — ВЫБРАНО
- Описание (1-2 строки)
- Плюсы (3-5 пунктов)
- Минусы (3-5 пунктов)
- Cost: время / деньги / поддержка
- Risks: что может пойти не так

### Option B: <имя> — отклонено
... тот же блок ...
**Почему отклонено:** <конкретная причина>

### Option C: <имя> — отклонено
... тот же блок ...
**Почему отклонено:** <конкретная причина>

## Consequences

**Positive:**
- ...

**Negative (сознательно принятые):**
- Минус 1 — живём с этим потому что ...
- Минус 2 — митигируем через ...

**Что становится сложнее:**
- ...

**Что становится легче:**
- ...

**Что мы согласны пересмотреть, если:**
- <условие> → revisit ADR

Объём: 1-3 страницы. Длиннее — никто не читает. Короче — нет контекста.

3. Lifecycle статусов

Proposed → Accepted → Superseded by ADR-NNN
                   → Deprecated
       → Rejected

Proposed — черновик в PR. Команда обсуждает в review. Файл уже в репо в docs/adr/, но статус указывает что это драфт.

Accepted — merged. С этого момента это истина для команды. Если кто-то делает иначе — он либо нарушает ADR (нужен новый ADR с superseded), либо это bug.

Rejected — обсуждалось, но не приняли. Оставь в репо! Будущие люди увидят: «уже пробовали, обоснованно отказались». Это спасает от повторных попыток.

Superseded by ADR-NNN — устарело, заменено новым. НЕ удаляй файл. В заголовок добавь ссылку на ADR-NNN. История — это ценность.

Deprecated — больше не применяется (фича удалена, паттерн запрещён), но замены нет.

Важно: ADR — append-only. Не редактируй принятое ADR (опечатки можно). Изменение мнения → новый ADR со статусом «Supersedes ADR-XX».

4. Где хранить

project-root/
  docs/
    adr/
      0001-record-architecture-decisions.md
      0002-use-postgres-as-primary-storage.md
      0003-async-jobs-via-rabbitmq.md
      0004-superseded-by-0015-event-store.md
      ...
      INDEX.md   ← список всех ADR с статусами
      TEMPLATE.md ← шаблон для нового

Принципы:

  • Рядом с кодом, в том же репо (не Confluence — отстанет за неделю)
  • Markdown, plain text (грепаемо, diff-able)
  • Numeric prefix (0001-) для сортировки и стабильных ссылок
  • Имя в slug — короткое, действие («use-X», «adopt-Y», «replace-Z»)
  • Не переименовывать после accept

INDEX.md — таблица: номер | название | статус | дата | автор. Генерится скриптом из заголовков.

5. Workflow

  1. Trigger: возникает решение которое попадает под критерии п.1
  2. Draft: автор создаёт ADR со статусом Proposed в feature branch
  3. PR + review: команда читает, комментирует, спорит — но в PR, не в чатах
  4. Decision meeting: если в PR консенсуса нет — 30-минутная встреча с deciders
  5. Merge: статус → Accepted, merge в main
  6. Announce: ссылка в #engineering / weekly digest — все должны знать
  7. Implementation: обычные PRs ссылаются на ADR: «implements ADR-014»
  8. Revisit: периодически проверять по trigger conditions из самого ADR

6. Что делает ADR живым

  • Ссылки из кода: комментарий // See ADR-014 for rationale рядом с нетривиальным решением
  • Ссылки из PR: «implements ADR-N» — связь PR ↔ ADR
  • Onboarding: новый человек читает docs/adr/ за первую неделю
  • Architecture review: раз в квартал — проходим INDEX, помечаем устаревшие
  • Tooling: adr-tools или свой скрипт для создания / нумерации / индекса
  • Шаблон + примеры в репо — снижает порог входа

7. Что НЕ ADR (распространённые ошибки)

НЕ ADRЧто вместо
Описание текущей архитектурыARCHITECTURE.md / C4 diagrams
API referenceOpenAPI / Swagger / docs generator
Runbookdocs/runbooks/
RFC для обсуждения идеиdocs/rfcs/ (можно ADR после accept)
Implementation guideREADME / inline docs
Тикет / задачаJIRA / Linear
Решение которое тривиальноnothing — не нужно
Решение которое уже implemented без обсужденияне пиши post-hoc, кроме редких случаев документирования принципа
Личное предпочтение автораstyle guide / linter

8. Anti-patterns

  • ❌ ADR на каждый PR — превращается в формальность, никто не читает
  • ❌ ADR без альтернатив (только «выбрали X») — не объясняет почему НЕ Y
  • ❌ ADR без context — через год не понять что решали
  • ❌ ADR без consequences — нет понимания цены решения
  • ❌ Описание «как» вместо «почему» — это design doc, не ADR
  • ❌ Hidden ADR в Confluence / Notion — оторвано от кода, устареет
  • ❌ Удаление superseded ADR — теряется история, повторим ошибку
  • ❌ Edit accepted ADR — переписывание истории, нужен новый ADR
  • ❌ ADR пишется одним человеком без review — это не решение команды
  • ❌ ADR без deciders / даты — не понять кто и когда подписался
  • ❌ ADR на 20 страниц — никто не дочитает, главное теряется
  • ❌ Implementation details («использовать Map вместо Object») — это code review, не ADR
  • ❌ Post-hoc ADR на каждое старое решение — заполняет шум, оставь только важные
  • ❌ ADR без revisit conditions — не понять когда пересматривать
  • ❌ Игнорирование Rejected — следующая команда снова попробует то же
  • ❌ ADR создан, но никто не делает по нему — нет enforcement (CI check, code review reference)

На выходе

  • Папка docs/adr/ с шаблоном и INDEX
  • Стартовая порция: 5-10 ADR на ключевые существующие решения проекта
  • Критерии «когда писать ADR» в CONTRIBUTING.md
  • Onboarding mention: «прочитай docs/adr/ за первую неделю»
  • Скрипт / Makefile target для создания нового ADR (make adr title=...)
  • Календарь квартального architecture review (revisit superseded candidates)
  • 2-3 примера хороших ADR из этого проекта для образца
К подразделу «Документация»
Похожие промты