Команда начинает дорабатывать сервис, который несколько лет работает в production, и обнаруживает, что он использует две базы данных. Заказы хранятся в PostgreSQL, а история их статусов - в MongoDB. В коде нет объяснения, почему данные разделили именно так. Возможно, MongoDB выбрали из-за объёма записей. Возможно, проект начинался как эксперимент. А может быть, ограничение давно исчезло, но никто не решается менять систему.
Спросить уже некого. В новой задаче нужно только добавить статус заказа, а в Git видны изменения кода, но не причины решения. Команде приходится заново разбираться в архитектуре или вслепую продолжать старый подход.
Architecture Decision Record, или ADR, сохраняет не всю архитектуру, а одно значимое решение вместе с контекстом, рассмотренными вариантами и последствиями. Хороший ADR позволяет будущей команде понять, почему решение было разумным в момент принятия и какие изменения контекста дают повод его пересмотреть.
ADR не устраняет спор и не гарантирует правильный выбор. Он делает рассуждение видимым. Этого уже достаточно, чтобы не начинать один и тот же спор каждые полгода.
Что такое ADR
Архитектурное решение меняет устройство системы или заметно ограничивает будущий выбор. Например, команда решает:
- хранить события в Kafka не меньше 30 дней;
- использовать один экземпляр PostgreSQL вместо отдельной базы для каждого сервиса;
- дать внешним клиентам доступ к API по REST, а не по gRPC;
- выполнять аутентификацию на API gateway;
- принимать платежи через одного провайдера и предусмотреть переход на другого.
Architecture Decision Record - это короткая запись об одном таком решении. Набор записей образует журнал решений, или decision log. Сообщество ADR определяет ADR как фиксацию одного архитектурного решения и его обоснования.
Майкл Найгард популяризовал этот формат в статье Documenting Architecture Decisions в 2011 году. Он предложил хранить небольшие текстовые файлы рядом с кодом и описывать в каждом четыре вещи: статус, контекст, решение и последствия.
Формат намеренно мал. Архитектурная документация часто устаревает не потому, что команде не хватает разделов в шаблоне. Она устаревает потому, что обновление большого документа требует отдельного проекта. ADR размером в одну-две страницы можно написать и проверить в том же pull request, где команда готовит изменение.
Решение важнее технологии
Фраза «используем PostgreSQL» ещё не описывает решение. Непонятно, какую проблему решала команда, с чем сравнивала PostgreSQL и какие ограничения приняла.
Полезная формулировка звучит конкретнее:
Храним заказы и историю их статусов в PostgreSQL. Записываем новый статус в той же транзакции, что и текущий статус заказа. Не вводим отдельное документное хранилище, пока объём истории не превышает заранее заданных пределов.
Здесь видны граница решения и его механизм. Можно проверить, соблюдает ли код договорённость. Можно заметить изменение условия: например, история выросла настолько, что мешает рабочей нагрузке.
Название продукта само по себе быстро теряет смысл. Решение и причина живут дольше.
Какие решения стоит фиксировать
Записывать каждое техническое действие не нужно. Выбор имени функции легко изменить, а его причина обычно видна из кода. ADR нужен там, где решение дорого отменить, оно влияет на несколько частей системы или накладывает заметные ограничения на дальнейшую работу.
Полезно задать четыре вопроса:
- Придётся ли следующей команде спрашивать, почему система устроена именно так?
- Есть ли у выбора несколько разумных вариантов с разными компромиссами?
- Повлияет ли решение на надёжность, безопасность, производительность, стоимость или скорость изменений?
- Потребует ли отмена решения миграции данных, изменения публичного контракта или координации нескольких команд?
Если хотя бы на один вопрос ответ «да», короткий ADR, скорее всего, окупится.
Найгард относит к архитектурно значимым решениям те, которые затрагивают структуру, нефункциональные свойства, зависимости, интерфейсы или способы создания системы. Руководство AWS по ADR использует похожую границу и добавляет примеры: отказоустойчивость, API, фреймворки и процессы разработки.
Но значимость решения зависит от конкретной системы. Выбор библиотеки сериализации в небольшом внутреннем сервисе может быть обычной деталью реализации. Тот же выбор для публичного SDK закрепляет формат данных у клиентов и становится архитектурным.
Правило простое: фиксируйте не самые дорогие технологии, а решения с долгими последствиями.
Минимальная структура ADR
Для начала достаточно шаблона Найгарда. Более подробные форматы, например MADR, добавляют явный список вариантов, критерии выбора и подтверждение результата. Эти поля полезны, но шаблон не должен быть сложнее самого решения.
# 0007. Хранить историю статусов заказа в PostgreSQL
Дата: 2026-08-31
## Статус
Предложено
## Контекст
Что происходит в системе? Какую проблему решаем?
Какие технические и организационные ограничения действуют?
Какие свойства решения для нас важны?
## Рассмотренные варианты
1. PostgreSQL.
2. MongoDB.
3. Kafka как постоянное хранилище истории.
## Решение
Что именно команда решила сделать?
## Последствия
Что станет проще? Что станет сложнее?
Какие риски, расходы и новые обязанности появляются?
Как поймём, что решение больше не подходит?
Команда может добавить авторов, участников обсуждения, связанные задачи и ссылки на измерения. Но четыре смысловые части остаются прежними: проблема, варианты, выбор и результат выбора.
Контекст: описать силы, а не подвести к ответу
Контекст объясняет условия в момент выбора. В него входят не только технологии:
- ожидаемая нагрузка и характер запросов;
- требования к доступности и времени восстановления;
- ограничения безопасности и законодательства;
- опыт команды;
- сроки и бюджет;
- уже работающие системы и контракты;
- неизвестные, которые пока нельзя устранить.
Плохой контекст заранее оправдывает любимый вариант:
Нам нужна надёжная промышленная база данных с SQL, поэтому выбираем PostgreSQL.
Фраза скрывает альтернативы и не объясняет, что означает «надёжная». Полезнее записать наблюдаемые условия:
Создание заказа и добавление записи в историю должны завершаться атомарно. Сервис обрабатывает до 300 операций записи в секунду. Команда уже обслуживает PostgreSQL, а новая база потребует отдельного мониторинга, резервного копирования и дежурств.
Такой контекст не доказывает выбор автоматически. Он даёт критерии, по которым варианты можно сравнить.
Рассмотренные варианты: сохранить реальные альтернативы
ADR не обязан содержать каталог всех существующих баз данных. Достаточно вариантов, которые команда действительно могла выбрать. Для каждого полезно коротко указать, как он отвечает на главные критерии.
В нашем примере команда сравнила три подхода:
| Вариант | Что даёт | Что усложняет |
|---|---|---|
| PostgreSQL | Одна транзакция для заказа и истории, знакомая эксплуатация | История конкурирует с основной нагрузкой за ресурсы |
| MongoDB | Гибкая модель документа, независимое масштабирование истории | Придётся поддерживать две независимые записи данных и ещё одну базу |
| Kafka | Естественная последовательность событий, возможность повторного чтения | Запросы истории и длительное хранение требуют дополнительных компонентов |
В таблице нет универсального победителя. PostgreSQL подходит при текущей нагрузке и требовании атомарности. При других условиях команда могла бы выбрать другой вариант.
Если вариант отклонили из-за измерения, приложите результат теста. Если из-за организационного ограничения, назовите его прямо. «Не подходит нашей архитектуре» ничего не объясняет.
Решение: назвать действие и границу
Раздел решения лучше писать активным залогом: «мы храним», «сервис публикует», «команда использует». Формулировка должна позволять проверить реализацию.
Например:
Храним текущий статус заказа и неизменяемую историю статусов в PostgreSQL. Добавляем запись истории и обновляем текущий статус в одной транзакции. Разделяем таблицы и индексы, но не вводим отдельное хранилище. Пересматриваем решение, если семь дней подряд больше 5% записей выполняются дольше 100 мс или объём истории не позволяет завершить резервное копирование за четыре часа.
Последнее предложение особенно полезно. Оно превращает «когда-нибудь посмотрим» в наблюдаемый сигнал. Решение остаётся привязанным к контексту, а не объявляется вечной истиной.
Последствия: записать цену выбора
У любого содержательного решения есть отрицательные последствия. Если в ADR перечислены только преимущества, перед нами, скорее всего, презентация выбранной технологии.
После выбора PostgreSQL команда получает атомарную запись и не добавляет новую базу. Одновременно растут таблицы, резервные копии занимают больше времени, а аналитические запросы могут мешать обработке заказов. Команде придётся следить за размером таблиц, планами запросов и длительностью резервного копирования.
Последствия - не список рисков для порядка. Они превращаются в конкретную работу:
- добавить метрики времени записи и размера таблицы;
- ограничить тяжёлые запросы к production;
- проверить восстановление из резервной копии;
- определить политику хранения истории;
- создать новый ADR, если условия пересмотра выполнятся.
Хороший ADR не только объясняет выбор, но и показывает, за что команда теперь отвечает.
Жизненный цикл: предложить, принять, заменить
У записи должен быть статус. Минимальный набор выглядит так:
proposed- решение предложено и открыто для обсуждения;accepted- команда согласилась работать по решению;rejected- вариант рассмотрели, но не приняли;superseded- новое решение заменило старое.
Некоторые команды используют deprecated, когда решение больше не рекомендуется, но ещё действует в части системы. Названия не так важны, как одинаковое понимание статусов.
После принятия ADR лучше не переписывать под новое настоящее. Иначе команда потеряет историю: старое решение начнёт выглядеть так, будто оно всегда учитывало новые обстоятельства. Руководство AWS рекомендует считать принятые записи неизменяемыми. Если контекст изменился, команда создаёт новый ADR, а старый помечает как заменённый и добавляет ссылку.
Допустим, через два года история заказов выросла до нескольких терабайтров, резервное копирование перестало укладываться в окно, а аналитика регулярно перегружает основную базу. Команда принимает ADR 0024, переносит историю в отдельное хранилище и указывает:
Заменяет: ADR-0007
В 0007 появляется обратная ссылка:
Статус: заменено ADR-0024
Старая запись остаётся полезной. Она объясняет, почему исходное решение работало несколько лет и какое условие заставило команду его изменить.
Где хранить ADR
Для команды, которая меняет систему через Git, удобная отправная точка - каталог рядом с кодом:
docs/
└── decisions/
├── 0001-use-postgresql.md
├── 0002-publish-events-through-outbox.md
└── 0003-keep-order-history-in-postgresql.md
Текстовые файлы проходят обычный review, меняются вместе с реализацией и остаются доступными без отдельного сервиса. Thoughtworks включила lightweight Architecture Decision Records в Technology Radar и отдельно отметила преимущество простого формата под управлением версий.
Но репозиторий не всегда доступен всем участникам решения. Если архитектуру обсуждают разработчики, безопасность, эксплуатация и владельцы продукта, закрытый каталог конкретного сервиса может оказаться слишком узким местом. Тогда записи можно публиковать во внутреннем портале или хранить в общем репозитории. Важно сохранить три свойства: понятный владелец, история изменений и стабильные ссылки.
Нумерация помогает ссылаться на решения, но создаёт конфликты, когда в нескольких ветках одновременно появляются ADR. Уникальный идентификатор UUID здесь обычно избыточен. На практике достаточно номера, даты или короткого уникального имени файла. По имени файла должно быть понятно, какое решение описано внутри.
Как встроить ADR в работу команды
ADR приносит пользу не в момент создания файла, а когда становится частью принятия решения.
Рабочий процесс может быть коротким:
- Автор создаёт ADR со статусом
proposedдо первого необратимого шага в реализации. - Участники, которых затрагивает решение, проверяют контекст, варианты и последствия.
- Команда принимает или отклоняет запись. Ответственный меняет статус.
- Команда вносит необходимые изменения в код и инфраструктуру.
- В pull request автор ссылается на ADR, а при изменении архитектурного ограничения создаёт новую запись.
ADR не требует отдельного архитектурного комитета. Решение может принять команда сервиса, если последствия остаются внутри её границ. Чем шире последствия, тем больше участников нужно привлечь: владельцев соседних сервисов, специалистов по безопасности, инженеров эксплуатации или представителей продукта.
На ревью проверяют не литературное качество, а само рассуждение:
- проблема и границы решения понятны;
- существенные ограничения названы;
- реальные варианты рассмотрены;
- выбор можно проверить по коду и инфраструктуре;
- отрицательные последствия не спрятаны;
- у решения есть владелец и условия пересмотра.
Если обсуждение занимает недели, проблема обычно не в формате ADR. Возможно, у решения не определён владелец, неизвестны критерии или участники пытаются получить полную уверенность там, где возможен только ограниченный эксперимент.
ADR и RFC решают разные задачи
Request for Comments, или RFC, организует обсуждение до принятия сложного решения. В нём может быть подробное предложение, план миграции, открытые вопросы, результаты экспериментов и комментарии участников. ADR фиксирует результат: что выбрали, почему и с какими последствиями.
Для небольшого решения одного ADR со статусом proposed достаточно и для обсуждения, и для фиксации. Для изменения публичного API или миграции нескольких команд удобнее подготовить RFC, провести обсуждение, а затем сохранить итог в коротком ADR. Thoughtworks описывает lightweight RFC как процесс, который в том числе может использоваться для проверки и принятия ADR.
Не стоит копировать двадцатистраничный RFC в журнал решений. Через год читателю нужны итог, причины и последствия. Подробности обсуждения останутся по ссылке.
Почему ADR перестают работать
Самая заметная проблема - записи появляются после решения. Автор уже знает ответ и строит контекст так, чтобы выбранный вариант выглядел неизбежным. Такой ADR сохраняет оправдание, а не рассуждение.
Есть и другие типичные сбои.
Команда документирует всё подряд
Журнал быстро заполняется решениями об именах пакетов и версиях небольших библиотек. Значимые записи теряются в шуме, а создание ADR воспринимается как бюрократия.
Согласуйте простую границу архитектурной значимости и разрешите автору объяснить выбор прямо в pull request, если последствия локальны и обратимы.
ADR превращается в учебник
Половина документа объясняет устройство Kafka, но две строки говорят о проблеме проекта. Общие знания лучше вынести в отдельную документацию и дать ссылку. ADR должен описывать конкретный выбор в конкретном контексте.
Последствия не проверяются
Команда написала, что решение увеличит задержку или расходы, но не добавила метрику и владельца. Через полгода никто не знает, сбылось ли предположение.
Для значимого риска полезно указать способ проверки: нагрузочный тест, бюджет облачных расходов, целевой уровень сервиса (SLO), срок эксперимента или дату пересмотра.
Старые записи молча редактируют или удаляют
История становится аккуратной, но ложной. Сохраняйте прежний ADR и заменяйте его новым. Архитектура развивается не по прямой, и журнал должен это показывать.
Решение нельзя найти
Файлы существуют, но на них не ссылаются из задач, кода и документации. Новые участники не знают о журнале, а review не проверяет соблюдение решений.
Добавьте короткий индекс со статусами, ссылайтесь на ADR из pull request и указывайте связанные записи в документации компонента. Поиск - часть формата, а не косметика.
Итог
Пишите ADR до того, как решение растворится в коде. Сохраняйте контекст без подгонки под ответ, называйте цену выбора и оставляйте старые записи в истории. Тогда журнал решений станет не архивом архитектурных обещаний, а картой ограничений, по которой действительно можно менять систему.
Дополнительные материалы
- Documenting Architecture Decisions - исходная статья Майкла Найгарда с минимальным шаблоном ADR.
- Architectural Decision Records - обзор терминов, шаблонов, инструментов и дополнительных материалов.
- MADR - подробный Markdown-шаблон с вариантами и критериями выбора.
- Using architectural decision records - практическое руководство AWS по жизненному циклу и review.
- Lightweight Architecture Decision Records - описание техники в Thoughtworks Technology Radar.
Комментарии в Telegram-группе!