После релиза в коде остаётся небольшой обходной путь: запрос к источнику идёт через отдельный слой, хотя прямой вызов выглядит проще. В обсуждении было несколько вариантов, один из них снимал риск устаревших данных, другой уменьшал число обращений. Через полгода PR уже закрыт, участники заняты другими задачами, а в коде виден только итог. Симптом — reviewer спрашивает «зачем это здесь», но ответ живёт в чате и памяти двух человек. Цена ошибки — не одна лишняя встреча. Можно удалить защиту, которая всё ещё покрывает ограничение, или оставить дорогую схему, хотя её исходная предпосылка давно исчезла.
ADR, architecture decision record, нужен не для того, чтобы объявить решение правильным. Это короткий контракт: какая ситуация наблюдалась, что сравнили, что решили, какие последствия приняли и кто вернётся к вопросу. Он отделяет причину выбора от реализации. Поэтому запись нельзя подменять ссылкой на ticket, а commit нельзя выдавать за аргументацию: оба могут быть полезными артефактами, но отвечают на другой вопрос.
Симптом → причина → проверка → действие
- Симптом. В code review возникает спор о старом условии, queue или boundary, а авторы исходного change уже не помнят детали.
- Причина. В переписке был контекст и альтернативы, но после принятия решения они не стали отдельной проверяемой записью.
- Проверка. Найдите один выбор, который меняет структуру, интерфейс, зависимость, non-functional constraint или способ доставки. Сформулируйте, какой факт он должен сохранить для следующего человека.
- Действие. Создайте proposed ADR до реализации: один context, две-три альтернативы, выбранный вариант, последствия, owner, status и дата пересмотра. После acceptance ссылка на ADR идёт рядом с code, но не заменяет test и operational evidence.
Как отличить ADR от хорошей заметки в переписке
Переписка полезна, пока все участники в ней находятся. В ней могут быть raw logs, варианты формулировок, эмоции, неверные гипотезы и локальные договорённости. ADR делает из этого компактный результат. Он не пересказывает каждую реплику. Он отвечает на вопрос, который сможет повторить reviewer: какая сила или constraint столкнулась с какой; какие варианты действительно рассматривались; почему выбранный вариант получил статус; какая цена остаётся после выбора. Если на эти вопросы нельзя ответить без поиска по мессенджеру, записи ещё нет.
Michael Nygard описывал ADR как короткий record для значимых решений с context, decision, status и consequences. В versioned template MADR есть status, date, people involved, decision drivers, considered options, outcome, consequences и validation. Не нужно переносить в проект каждую строку template. Но пропускать owner и review boundary опасно: тогда record сохраняет прошлое, но не даёт понять, кто проверит, что прошлое ещё применимо.
| Поле | Что записать | Что проверить перед acceptance | Чего поле не доказывает |
|---|---|---|---|
| Контекст и проблема | наблюдаемый симптом, constraint и цена неверного выбора | факты отделены от предположений; scope ограничен одним решением | что implementation уже корректна |
| Варианты | два-три реально обсуждаемых пути и отказ от невыбранных | каждый вариант сравним по одному набору criteria | что список исчерпывает будущее |
| Решение и status | выбранный вариант, Proposed или Accepted, дата | есть явный автор или owner и понятный acceptor | что решение будет работать во всех окружениях |
| Последствия | что станет проще, дороже, обратимее или требует нового контроля | названы отрицательные последствия и граница rollback | что цена уже оплачена или измерена |
| Связи и review date | link на code, contract, metric question и дату пересмотра | ссылка ведёт к артефакту, а не заменяет его чтение | что текущий code соответствует ADR автоматически |
Короткий ADR лучше длинного пересказа
Практический record можно удержать в одной-двух страницах, если в нём один вопрос. Например: где держать ограниченный cache для internal read path. Контекст не обязан рассказывать историю всего продукта. Достаточно назвать границу: source contract, допустимую freshness, data class, owner и то, что произойдёт, если hypothesis окажется неверной. Вариант «не делать cache» тоже должен быть записан. Иначе через месяц он вернётся в discussion как новая идея, хотя уже сравнивался.
# ADR-0042: держать bounded cache у BFF boundary
Status: Proposed
Owner: application owner
Review by: 2025-03-31
## Context
Synthetic read contract допускает bounded freshness. Прямой read повторяет вызовы.
## Options
1. Direct source read.
2. Bounded cache at BFF boundary.
3. Shared cross-service cache.
## Decision
Предлагаем вариант 2: expiry и rollback принадлежат application owner.
## Consequences
Нужны явные freshness bound и проверка удаления cache. Это не approval production.
Этот пример специально короткий и synthetic. В нём нет реального cache, repository, SQL, dashboard или service metric. Его цель — проверить форму: decision не прячет owner, consequences не выглядят как рекламный список плюсов, а review date не является обещанием, что кто-то автоматически выполнит проверку. Для настоящего ADR вместо слова synthetic должны появиться проверяемые ссылки и владелец, которому разрешено собирать evidence.
Сначала записываем границу, затем implementation
Частая ошибка — писать ADR после merge. Тогда решение уже видно в diff, а record превращается в оправдание. Иногда так приходится восстанавливать старый контекст, но нормальный путь другой: owner создаёт proposed record, reviewers уточняют scope и alternatives, затем принимают решение и только после этого меняют code или configuration. Это не делает процесс медленным. Небольшой record уменьшает число вопросов в diff: reviewer видит, какой compromise обсуждается, и проверяет конкретное implementation against него.
Полезно написать в ADR явную пару «реализуем» и «не реализуем». Для cache это может быть: создаём bounded local state с named expiry; не создаём shared invalidation system и не называем fixture измерением hit ratio. Такая отрицательная часть защищает от постепенного расширения. Следующая команда сможет добавить новый вариант отдельным ADR, а не превратить незаметное поле configuration в новую policy.
Последствия — это цена, а не обязательный раздел для галочки
Фраза «решение упрощает поддержку» ничего не позволяет проверить. Лучше назвать цену как действие: owner должен хранить expiry рядом с policy; rollback возвращает direct read только после проверки contract; source change должен открыть reassessment. У positive consequence тоже есть boundary: local cache может уменьшить повторение read в целевом сценарии, но не доказывает throughput, latency или экономию. Если нет разрешённого измерения, не добавляйте число. Это честнее и делает будущую проверку возможной.
Первичный текст Nygard объясняет ADR как разговор с будущим developer: record передаёт не только what, но и why. Важная оговорка: передать контекст не означает получить бессрочный запрет на изменение. Когда assumption перестаёт выполняться, именно record помогает сформулировать новый вопрос. Старый ADR остаётся историей принятого compromise, а successor объясняет, почему он больше не подходит.
Порядок работы с одной перепиской
- Ограничьте вопрос. Не пишите «архитектура export». Напишите конкретнее: «как caller получает status, если synchronous boundary не выполняется».
- Выпишите факты отдельно. Контракт, constraint, owner и evidence question идут в context. Догадки не маскируйте под факт.
- Сравните варианты одинаково. Для каждого назовите reversibility, cost ownership, evidence gap и constraint fit. Не делайте выбранный вариант подробным, а остальные карикатурными.
- Зафиксируйте статус. Proposed разрешает review и правки. Accepted фиксирует record, а не останавливает развитие code.
- Добавьте последствия и stop condition. Назовите rollback, отсутствующее evidence и signal, который заставит вернуться к решению.
- Свяжите, но не склеивайте. После implementation добавьте link на ADR в relevant code review или documentation. Проверка compliance живёт отдельным test, query или human review.
Ограничения и следующий проверяемый шаг
ADR не заменяет design document, threat model, migration plan, benchmark, test plan, runbook или incident review. Он не превращает consensus в факт и не гарантирует, что reviewer увидит все альтернативы. Form из Nygard и MADR задаёт полезную структуру, но не определяет naming, retention, approval workflow и срок review для любой организации. Если decision имеет legal, security или data boundary, эти проверки остаются отдельными обязательствами с собственными владельцами.
Следующий проверяемый шаг: возьмите одну свежую technical discussion до merge и создайте proposed ADR на 20–30 минут. Заполните пять строк: symptom, cost, alternatives, chosen compromise, review signal. Попросите reviewer ответить не «нравится ли текст», а «какой fact или consequence отсутствует». Если в ответе появляется новый вариант или owner, record уже принёс пользу: он нашёл неопределённость до того, как она стала невидимой частью implementation.
Историческая граница сентября 2024
Материал использует датированный snapshot первичного текста Nygard от 22 августа 2024, immutable Git snapshot его template и immutable commit MADR 3.0.0 от 9 октября 2022. Все ссылки закрепляют состояние, доступное к сентябрю 2024. Из них взята узкая идея: ADR сохраняет context, choice, status, consequences, alternatives и validation boundary. Синтетический пример, scores и outcomes в учебной fixture не являются историей команды, production data, интервью, Git history, CI result или измерением качества решения.
Проверяемые источники
- Michael Nygard: Documenting Architecture Decisions, snapshot 22.08.2024 — Датированный снимок первичного текста автора ADR: короткий record с context, decision, status и consequences, а также сохранение старого record при supersede. Snapshot закрепляет историческую версию до сентября 2024; это формат и аргументация, а не policy конкретной команды.
- Nygard ADR template mirror, immutable commit 93f7e465, 18.10.2023 — Неизменяемый Git snapshot template, который явно ссылается на формат Michael Nygard и фиксирует Title, Status, Context, Decision и Consequences. Это cross-check формы, а не первичный текст и не обязательный process команды.
- MADR 3.0.0 template, immutable commit 97fb8ed, 09.10.2022 — Неизменяемый первичный артефакт Markdown ADR, доступный до сентября 2024. В template есть status, date, deciders, decision drivers, options, outcome, consequences и validation. Это пример формы, не обязательный набор полей и не измерение качества решения.