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
- Trigger: возникает решение которое попадает под критерии п.1
- Draft: автор создаёт ADR со статусом Proposed в feature branch
- PR + review: команда читает, комментирует, спорит — но в PR, не в чатах
- Decision meeting: если в PR консенсуса нет — 30-минутная встреча с deciders
- Merge: статус → Accepted, merge в main
- Announce: ссылка в #engineering / weekly digest — все должны знать
- Implementation: обычные PRs ссылаются на ADR: «implements ADR-014»
- 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 reference | OpenAPI / Swagger / docs generator |
| Runbook | docs/runbooks/ |
| RFC для обсуждения идеи | docs/rfcs/ (можно ADR после accept) |
| Implementation guide | README / 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 из этого проекта для образца
Документация компонента
Документация по компоненту: API, варианты, состояния, доступность, использование.
Multi-agent: координатор и специалисты
Архитектура из координатора и специализированных агентов: передача контекста, дедупликация, race conditions.
Переезд в новый чат: handoff контекста
Когда контекст переполнен и пора в новый чат — не «начать заново», а сгенерировать один артефакт HANDOFF, после которого новая сессия стартует с продакшен-готовым пониманием всего что было.