Architecture Decision Records
ADR фиксирует одно архитектурное решение — контекст, силы, выбор и последствия — чтобы будущие инженеры знали ПОЧЕМУ, а не только что было решено. Легковесный формат, версионируемый рядом с кодом, неизменяемый после принятия: superseded, но не удалён.
Через шесть месяцев после того, как B2B биллинговая платформа переключилась с REST-взаимодействия между модулями на событийную модель, новый инженер спросил — почему. Команда три дня просматривала Slack, Confluence и pull request’ы и нашла фрагменты: тред «обсуждали на мартовском митинге», описание PR «переходим на события», Jira-тикет «технический долг». Никто не смог восстановить силы, которые обусловили решение: болтливые REST-вызовы, вызывавшие каскадные отказы при биллинговых запусках; три рассмотренные альтернативы; причину, по которой отклонили очередь сообщений в пользу доменных событий; трейдоффы, которые сознательно приняли. Когда проявился режим отказа, с которым событийная модель не справлялась, команда снова начала спорить об исходном решении — без контекста. Двое хотели откатиться, двое — двигаться вперёд. Записи о том, что уже рассматривалось, не было.
Написать Architecture Decision Record занял бы тридцать минут. Вместо этого потребовалось три дня раскопок и неразрешённый архитектурный спор.
Что такое ADR и чем он не является
Architecture Decision Record — короткий документ, как правило одна-две страницы, фиксирующий одно значимое архитектурное решение. Формат предложил Майкл Найгард в 2011 году. Ключевой инсайт: само решение менее важно, чем обоснование — контекст, сделавший решение необходимым, силы, тянувшие в разные стороны, рассмотренные альтернативы и принятые последствия.
ADR — это не:
- Проектный документ (он описывает, как что-то построено)
- Документ требований (он описывает, что должно делаться)
- Постмортем (он описывает, что пошло не так)
- Живой документ (ADR неизменяем после принятия: он superseded, но не редактируется)
Формат Найгарда состоит из пяти разделов:
Заголовок. Короткая фраза в повелительном наклонении: «Использовать доменные события для межмодульного взаимодействия», а не «Решение о событийно-ориентированной архитектуре».
Статус. Proposed → Accepted → Superseded (by ADR-NNN) | Deprecated. Статус никогда не бывает «rejected» для принятых решений — они superseded, когда более новое решение их заменяет. Отклонённые предложения остаются Proposed ADR’ами, которые так и не были приняты.
Контекст. Силы и обстоятельства, сделавшие это решение необходимым. В чём была проблема? Какие ограничения существовали? Какова была текущая ситуация?
Решение. Сделанный выбор, изложенный прямо: «Мы будем использовать доменные события, публикуемые на внутрипроцессной шине, для всей кросс-модульной коммуникации».
Последствия. Принятые трейдоффы. Что стало проще? Что стало сложнее? Какие новые риски введены?
Почему ПОЧЕМУ — это ценность
Рассмотрим две записи об одном решении:
Запись A (коммит-сообщение): «Переключить кросс-модульное взаимодействие на доменные события».
Запись B (ADR): «Контекст: модуль billing вызывает REST API модуля ordering синхронно во время генерации инвойсов. При всплесках объёма заказов это вызывает каскадные таймауты. Мы оценили три варианта: (1) добавить очередь между REST-вызывающими, (2) переключиться на доменные события на внутрипроцессной шине, (3) переработать billing так, чтобы он владел read-моделью данных заказов. Мы отклонили (1), потому что он добавляет операционную сложность (брокер для управления) без устранения зацепления. Мы отклонили (3), потому что ownership данных заказов в billing нарушает принципы владения данными (ADR-004). Решение: принимаем доменные события на внутрипроцессной шине (без брокера). Последствия: кросс-модульные вызовы становятся асинхронными; логика billing должна обрабатывать события, приходящие не по порядку; мы принимаем, что billing не может немедленно подтвердить текущий статус заказа».
Запись B позволяет будущему инженеру понять: (a) почему проблема существовала, (b) что рассматривалось и отклонялось и почему, (c) какие трейдоффы были сознательно приняты.
▸Why this works
Почему ADR должен фиксировать отклонённые альтернативы? Потому что именно они предотвращают повторное открытие вопроса. Без записи о том, почему вариант (1) был отклонён, следующий инженер, столкнувшись с проблемой, самостоятельно предложит вариант (1). Имея запись, обсуждение начинается с «мы отклонили это по причине X — изменилось ли X?», а не с нуля. Отклонённый путь столь же информативен, что и выбранный.
У команды биллинговой платформы есть принятый ADR (ADR-007) «использовать доменные события для кросс-модульного взаимодействия». Год спустя профилирование производительности показывает, что внутрипроцессная шина создаёт узкое место при 50 000 конкурентных заказов. Старший инженер предлагает заменить её Kafka-брокером. Как правильно поступить с ADR'ами?
ADR как артефакт первого класса: система контроля версий и расположение
Легковесный формат ADR специально разработан для хранения рядом с кодом в системе контроля версий. Исходное предложение Найгарда помещает их в doc/arch/adr-NNN-title.md. ThoughtWorks Radar (2016) включает Lightweight Architecture Decision Records в список техник, рекомендованных к внедрению, именно потому, что они дёшевы и версионируемы.
Преимущества совместного хранения ADR’ов с кодом:
- История изменений: когда меняется код, история ADR показывает, когда и почему было принято решение, коррелируемое с коммитом реализации.
- Обнаруживаемость: инженеры, изучающие кодовую базу, находят ADR’ы там, где работают (в репозитории), а не в вики, которая может устареть.
- Workflow pull request’ов: ADR можно предложить в pull request’е, рассмотреть вместе с изменением реализации и слить при принятии решения.
- Долговечность: вики дрейфуют, страницы Confluence устаревают, Slack-треды архивируются. ADR в репозитории живёт столько, сколько существует кодовая база.
▸lesson.inset.note
Формат ADR намеренно минимален. Некоторые команды добавляют разделы (таблицы за/против, оценки рисков, ссылки на RFC-обсуждения). Это нормально, пока присутствует основная информация: контекст, решение, последствия. Формат Найгарда — минимум, а не максимум. Провальный режим — усложнить формат до такой степени, что написание ADR’ов становится настолько обременительным, что никто их не пишет. Двухабзацный ADR бесконечно лучше отсутствия ADR.
Команда хранит архитектурные решения в Confluence. Инженер утверждает, что Confluence лучше ADR'ов в репозитории, поскольку предлагает богатое форматирование, поиск и комментарии. Старший инженер не согласен. Каков наиболее важный структурный аргумент против Confluence для записей решений?
Какие решения требуют ADR
Не каждое решение нуждается в ADR. Сигнал: потребовалось бы опытному инженеру, присоединившемуся к команде через два года, знать, почему это решение было принято — и смог бы он это понять из кода?
Решения, требующие ADR:
- Выбор архитектурного стиля (событийно-ориентированный vs request-response, modular monolith vs микросервисы)
- Значимые технологические выборы (конкретное хранилище событий, брокер сообщений, ORM)
- Отклонённые альтернативы, которые скорее всего будут предложены снова («мы рассматривали X и отклонили, потому что…»)
- Решения с неочевидными последствиями или принятыми трейдоффами
- Решения, ограничивающие будущие опции («мы не сможем перейти на X, не переделав Y»)
Решения, не нуждающиеся в ADR:
- Рутинные решения реализации (соглашения об именовании, структура файлов внутри модуля)
- Идиоматические паттерны фреймворка (использование DI, потому что фреймворк его использует)
- Решения, очевидные из кода и домена
Пример для биллинговой платформы: «Использовать PostgreSQL» вероятно не требует ADR, если команда — Rails-шоп с PostgreSQL по умолчанию. «Использовать PostgreSQL event sourcing вместо специализированного хранилища событий типа EventStoreDB» — точно требует ADR, поскольку есть неочевидные силы (операционная привычность к PG, стоимость эксплуатации EventStoreDB, проблема удаления при GDPR), которые будущие инженеры не смогут вывести из кода.
Технический лид биллинговой платформы просматривает список кандидатов на ADR и находит четыре варианта. Какой из них наиболее явно требует ADR?
- 01Каковы пять разделов формата ADR по Найгарду и почему раздел «Контекст» наиболее важен?
- 02Каков жизненный цикл статуса ADR и почему принятые ADR'ы никогда не удаляются и не редактируются?
- 03Почему ADR'ы должны храниться в репозитории кода, а не в вики или системе управления проектами?
Трёхдневные «раскопки» команды биллинговой платформы — восстановление решения, принятие которого заняло час — это режим отказа, который ADR’ы предотвращают. Журнал решений — не бюрократия; это институциональная память, сделанная явной и долговечной.
Формат намеренно минимален: контекст, решение, последствия. Неизменяемость намеренная: принятые ADR’ы superseded, а не редактируются. Расположение намеренное: рядом с кодом в системе контроля версий, там, где работают инженеры и где запись переживёт любую вики.
Важнейшая часть ADR — отклонённые альтернативы. Без них каждый инженер, столкнувшийся с той же проблемой, заново предложит те же альтернативы. С ними команда может начать с существующего анализа и спросить: «Достаточно ли изменился контекст, чтобы пересмотреть это?»
ADR’ы — мост между архитектурой в её нынешнем виде и архитектурой в её становлении. Без них каждое структурное решение выглядит неизбежным. С ними инженеры понимают, что каждое решение было трейдоффом — и могут оценить, применимы ли силы, его обусловившие, по сей день.
Практика
Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.
Что-то непонятно?
Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.
Примени это
Примени этот урок в реальном проекте.