Задать вопрос Поделиться знаниями Редактировать страницу

Реестр архитектурных решений

Architecture Decision Record (ADR) — это короткая запись одного архитектурно значимого решения: что команда выбрала, почему выбрала именно это, какие варианты отвергла и какие последствия принимает. Набор ADR образует журнал архитектурных решений — Architecture Decision Log (ADL). ADR не заменяет архитектурную документацию, RFC или design doc. Его задача уже: сохранить контекст выбора так, чтобы через полгода новый разработчик, тимлид или AI-ассистент не гадали по коду, почему система устроена именно так.

ADR полезен там, где цена забывания выше цены записи. Например, команда выбрала брокер сообщений, запретила прямые обращения к базе другого сервиса, оставила модульный монолит вместо микросервисов, ввела правило версионирования API или решила хранить архитектурные знания рядом с кодом. В каждом таком случае важно сохранить не только итог, но и обстоятельства: ограничения, конфликтующие требования, рассмотренные альтернативы, последствия и условия пересмотра.

Идею легковесных ADR популяризировал Michael Nygard в статье Documenting Architecture Decisions. Его основной аргумент до сих пор актуален: большие архитектурные документы быстро устаревают, а небольшие модульные записи имеют шанс жить вместе с проектом.

Какую проблему решает ADR

Код показывает, что реализовано сейчас. Диаграмма показывает, как компоненты связаны сейчас. Но ни код, ни диаграмма обычно не объясняют, почему команда отказалась от другого варианта, какие риски считала приемлемыми и при каких условиях решение нужно пересмотреть.

ADR превращает это знание в доступный артефакт:

  • снижает зависимость от памяти конкретного архитектора или старшего разработчика;

  • ускоряет онбординг новых участников команды;

  • предотвращает повторные споры вида "а почему мы не сделали иначе?";

  • помогает при ревью, передаче владения системой и планировании миграций;

  • связывает архитектурные решения с кодом, задачами, инцидентами и другими документами;

  • делает знания пригоднее для поиска и RAG-систем, потому что у решения появляются явные границы, статус и ссылки.

Это не означает, что ADR заменяет живое обсуждение. Часть экспертного знания все равно остается неявной: в опыте людей, навыках диагностики, понимании домена. Но ADR хорошо фиксирует устойчивое ядро: факты, trade-offs и последствия, которые потом трудно восстановить.

Когда писать ADR

ADR нужен не на каждую строку кода и не на каждую библиотеку. Запись оправдана, если решение хотя бы частично отвечает "да" на один из вопросов:

  • решение влияет на структуру системы, границы модулей или сервисов;

  • меняет важные quality attributes: надежность, безопасность, производительность, сопровождаемость;

  • вводит долгоживущую зависимость, платформу, фреймворк или инфраструктурный стандарт;

  • определяет публичный API, контракт интеграции, модель данных или способ версионирования;

  • затрагивает несколько команд или репозиториев;

  • его дорого откатить;

  • по нему уже повторно спорили или оно вызывает вопросы у новых людей;

  • его нарушение можно ожидать в будущих pull request.

Не стоит писать ADR на локальный implementation detail, который можно заменить в одном PR без влияния на других. Если решение не будет интересно будущей команде, оно не архитектурно значимо.

Spotify Engineering в материале When Should I Write an Architecture Decision Record предлагает практичный ориентир: ADR стоит писать при значимом влиянии решения, а команде нужно договориться, что именно в ее контексте считается значимым.

ADR, RFC, design doc и decision log

Артефакт Главный вопрос Когда создается Как связан с ADR

ADR

Что решили, почему, при каких ограничениях и с какими последствиями?

Во время принятия решения или сразу после него

Фиксирует устойчивый итог и rationale одной значимой развилки.

RFC

Какое изменение предлагается и согласны ли заинтересованные стороны?

До решения и до существенной реализации

RFC организует обсуждение. Итог RFC можно сжать в ADR. В больших open-source проектах, например Rust, RFC является отдельным governance-процессом.

Design doc

Как будет устроена реализация?

До разработки или в начале крупной инициативы

Design doc может содержать API, план миграции, диаграммы и несколько решений. ADR вытаскивает из него долгоживущее архитектурное решение.

Decision log / ADL

Какие решения существуют, каковы их статусы и где их найти?

Обновляется по мере появления ADR

Это индекс: id, заголовок, статус, область действия и ссылка на полный ADR. Microsoft описывает такой подход как design decision log.

Архитектурная документация

Как система устроена сейчас?

Живет вместе с системой

ADR объясняет происхождение текущего устройства и ограничения, которые не видны из схемы.

Главное — не название файла, а распределение функций. Где команда обсуждает предложение? Где хранит принятое решение? Где показывает текущую архитектуру? Где ищет список всех решений? Если эти вопросы не разделены, ADR быстро превращается либо в слишком длинный design doc, либо в таблицу без контекста.

Минимальный workflow

Рабочий процесс должен быть легче самого решения:

  1. Любой участник команды может предложить ADR, если видит архитектурно значимую развилку.

  2. У записи есть owner: человек, который собирает контекст и доводит запись до статуса.

  3. Черновик получает статус proposed и обсуждается в pull request, design review или короткой сессии.

  4. После согласования запись получает accepted или rejected.

  5. Если контекст изменился, старый ADR не переписывают молча, а создают новый ADR со ссылкой supersedes.

AWS в ADR process рекомендует начинать ревью с короткого silent reading: 10-15 минут на чтение и комментарии, затем обсуждение. Это хороший антидот против презентаций, где решение принимают по харизме докладчика, а не по содержанию.

Где хранить ADR

Для инженерной команды лучший default — хранить ADR рядом с кодом: docs/adr/, doc/adr/ или architecture/decisions/. Тогда запись проходит через pull request, имеет историю изменений и легко связывается с кодом. Так устроены многие публичные примеры: Backstage ADR и GOV.UK GDS Way.

Но Git-only подход не всегда достаточен. Если решение действует на десятки репозиториев, нужен центральный индекс: id, заголовок, статус, область, команда-владелец, ссылка на оригинал. Полный текст можно оставить рядом с системой, а индекс опубликовать в wiki, Backstage, портале документации или базе знаний.

Практичный компромисс:

  • локальные решения — в репозитории системы;

  • межкомандные стандарты — в центральном каталоге или отдельном architecture repository;

  • во всех случаях — стабильные id, статусы и ссылки между решениями.

Шаблон ADR

Не начинайте с самого полного шаблона. Начните с ядра Nygard: title, context, decision, status, consequences. Если решение сложное, добавьте поля из MADR: драйверы, альтернативы, участники, проверка соблюдения и условия пересмотра. MADR описан в Markdown Architectural Decision Records.

---
id: ADR-0042
title: Краткое название принятого решения
status: proposed
date-created: 2026-08-01
date-decided:
owners:
  - team-or-person
decision-makers: []
consulted: []
informed: []

scope:
  systems: []
  components: []
  repositories: []

tags: []
supersedes: []
superseded-by: []
related-adrs: []
related-rfcs: []
related-design-docs: []
related-issues: []
related-code: []
review-or-revisit:
---

# ADR-0042: Краткое название принятого решения

## Контекст и проблема

Какую проблему решаем?
Какие факты, ограничения и противоречивые силы действуют?
Что находится вне области решения?

## Драйверы решения

- Какое качество или ограничение наиболее важно?
- Какие условия обязательны?
- Какие критерии позволяют сравнить варианты?

## Рассмотренные варианты

1. Вариант A.
2. Вариант B.
3. Ничего не менять.

## Решение

Мы будем ...

Почему выбранный вариант лучше соответствует драйверам?

## Последствия

Положительные:
- ...

Отрицательные:
- ...

Операционные:
- ...

## Проверка соблюдения

Как убедиться, что реализация соответствует решению?
Какие тесты, метрики, ревью или архитектурные правила это проверяют?

## Условия пересмотра

При каком изменении нагрузки, требований, стоимости, команды
или регуляторных ограничений решение нужно пересмотреть?

## Дополнительные материалы

Ссылки на RFC, design docs, задачи, код, инциденты и связанные ADR.

Обязательные поля: id, title, status, context, decision, consequences. Остальное добавляйте только если этим будут пользоваться. Слишком полный шаблон легко превращает ADR в бюрократическую анкету.

Пример 1. Выбор базы данных

---
id: ADR-0012
title: Использовать реляционную БД как основное хранилище сервиса заказов
status: accepted
date-created: 2026-08-03
date-decided: 2026-08-07
owners: [orders-team]
scope:
  systems: [order-management]
  components: [order-service]
tags: [database, consistency, orders]
related-issues: [ORD-418]
review-or-revisit: 2027-02-01
---

# ADR-0012: Использовать реляционную БД как основное хранилище сервиса заказов

## Контекст и проблема

Сервис должен хранить заказ, позиции, платежное состояние и историю
переходов. В рамках одного заказа нужно атомарно менять связанные
сущности и однозначно восстанавливать состояние. Основные запросы
идут по заказу, клиенту или временному диапазону.

Решение не определяет аналитическое хранилище и полнотекстовый поиск.

## Драйверы решения

- Транзакционная целостность.
- Понятная модель миграций схемы.
- Операционный опыт команды.
- Воспроизводимые интеграционные тесты.
- Предсказуемое резервное копирование.

## Рассмотренные варианты

1. Реляционная БД как system of record.
2. Документная БД как system of record.
3. Event store как единственный источник состояния.

## Решение

Мы будем использовать управляемую реляционную БД как основное
хранилище order-service. События для других систем публикуются
через transactional outbox.

## Последствия

Положительные:
- Инварианты заказа можно обеспечивать в транзакции.
- Команда использует знакомые миграции и диагностику.

Отрицательные:
- Online-миграции крупных таблиц требуют отдельной дисциплины.
- Сложную аналитику нельзя переносить на operational DB.

## Проверка соблюдения

- Интеграционные тесты проверяют атомарность изменения заказа и outbox.
- Code review проверяет отсутствие dual writes.
- Архитектурный тест запрещает запись в таблицы order-service из других сервисов.

## Условия пересмотра

Пересмотреть, если профиль нагрузки потребует разделения данных
или транзакционные границы изменятся.

Пример 2. Интеграция с внешней системой

---
id: ADR-0021
title: Изолировать интеграцию с партнерской системой через асинхронный адаптер
status: accepted
date-created: 2026-08-10
date-decided: 2026-08-14
owners: [integration-team]
scope:
  systems: [partner-fulfilment-integration]
tags: [integration, resilience, idempotency]
related-rfcs: [RFC-007]
review-or-revisit: 2026-11-01
---

# ADR-0021: Изолировать интеграцию с партнерской системой через асинхронный адаптер

## Контекст и проблема

После подтверждения заказа нужно передать партнеру заявку на выполнение.
Внешний API имеет собственное окно доступности, timeout-ответы не всегда
однозначны, а модель состояний партнера отличается от нашей.

Пользовательский checkout не должен зависеть от мгновенной доступности партнера.

## Драйверы решения

- Не терять подтвержденные заявки.
- Поддерживать идемпотентные повторы.
- Видеть состояние интеграции.
- Не протаскивать внешнюю модель данных в checkout.

## Рассмотренные варианты

1. Синхронный вызов партнера из checkout.
2. Асинхронная очередь и выделенный adapter component.
3. Периодическая пакетная выгрузка.

## Решение

Мы будем записывать локальное намерение интеграции в рамках транзакции
заказа и асинхронно передавать его adapter component. Adapter назначает
idempotency key, преобразует модель данных и управляет retry-политикой.

Checkout возвращает результат после сохранения заказа, не ожидая
внешнего подтверждения.

## Последствия

Положительные:
- Недоступность партнера не блокирует оформление заказа.
- Внешний контракт изолирован в одном компоненте.

Отрицательные:
- Возникает eventual consistency.
- Нужны reconciliation job, dead-letter queue и интерфейс поддержки.

## Проверка соблюдения

- Запрещены прямые вызовы partner API из checkout package.
- Contract tests проверяют преобразование данных.
- Метрики отслеживают возраст очереди, повторы и DLQ.

## Условия пересмотра

Пересмотреть, если партнер даст гарантированную transactional messaging-интеграцию
или продукт потребует синхронного подтверждения.

Пример 3. Модульный монолит

---
id: ADR-0030
title: Развивать продукт как модульный монолит с явными доменными границами
status: accepted
date-created: 2026-08-17
date-decided: 2026-08-21
owners: [platform-team]
scope:
  systems: [core-product]
tags: [architecture-style, modularity, deployment]
review-or-revisit: 2027-02-01
---

# ADR-0030: Развивать продукт как модульный монолит с явными доменными границами

## Контекст и проблема

Продукт быстро меняется, доменные границы еще уточняются, а несколько
команд регулярно меняют одни и те же пользовательские сценарии.
Платформа для эксплуатации большого числа сервисов пока не создана.

При этом нужно предотвратить рост неструктурированного монолита.

## Драйверы решения

- Скорость изменения сквозных сценариев.
- Низкая операционная сложность.
- Явные границы ownership.
- Возможность будущего выделения модулей.
- Единый deployment для транзакционных изменений.

## Рассмотренные варианты

1. Микросервисы по предполагаемым доменным областям.
2. Неструктурированный монолит.
3. Модульный монолит с контролируемыми зависимостями.

## Решение

Мы будем использовать единый deployable, разделенный на доменные модули.
Каждый модуль имеет публичный application interface и не обращается
к внутренним пакетам или таблицам другого модуля. Выделение модуля
в отдельный сервис требует нового ADR.

## Последствия

Положительные:
- Сквозные изменения не требуют координации нескольких deployments.
- Границы можно уточнять по мере изучения домена.

Отрицательные:
- Независимое масштабирование ограничено.
- Дисциплину границ нужно обеспечивать тестами и ревью, а не договоренностями.

## Проверка соблюдения

- Architecture tests проверяют допустимые направления зависимостей.
- Модули не импортируют internal packages друг друга.
- Прямой доступ к чужим таблицам запрещен review checklist и тестом.

## Условия пересмотра

Выделять модуль в сервис, если ему нужен независимый lifecycle,
изолированное масштабирование или автономная команда с устойчивой границей.

ADR и AI-ассистенты/RAG

AI-ассистенты повышают ценность ADR, но только если записи структурированы. Человек часто понимает из контекста, что "это решение про billing", а RAG-система без метаданных может применить его ко всему монорепозиторию.

Для AI-ready ADR важны:

  • стабильный id для цитирования и дедупликации;

  • короткий конкретный title;

  • status, чтобы retrieval не подсовывал устаревшие или отклоненные решения как действующие;

  • scope: система, компонент, репозиторий, каталог;

  • supersedes и superseded-by;

  • ссылки на код, тесты, задачи, RFC и design docs;

  • confirmation: как проверить, что решение соблюдается.

Не нужно загружать весь журнал ADR в prompt AI-агента. Лучше разделить знания на два слоя:

  • ADR хранит историю и объяснение: контекст, варианты, решение, последствия.

  • AGENTS.md, CLAUDE.md или .github/copilot-instructions.md хранят краткие действующие правила для агента.

Например, ADR объясняет, почему checkout не должен напрямую вызывать API партнера. Инструкция для агента говорит: "в каталоге checkout/ не добавляй прямые вызовы partner API; используй integration adapter". Тест или архитектурный линтер проверяет, что правило не нарушено.

Это соответствует подходу современных инструментов: GitHub описывает repository-level и path-specific custom instructions for Copilot, а Anthropic в документации Claude Code memory прямо отмечает, что такие файлы являются контекстом, а не жестким enforcement. Для обязательного контроля нужны tests, hooks, linters или policy-as-code.

В RAG-пайплайне короткий ADR можно индексировать целиком. Длинный ADR лучше chunk’ить по смысловым разделам, сохраняя у каждого chunk метаданные: adr_id, status, scope, date, tags, связи supersession. Microsoft Azure Architecture Center в руководствах по RAG chunking и chunk enrichment отдельно подчеркивает роль структуры документа и metadata для поиска.

Что может пойти не так

Анти-паттерн Чем опасен Как исправить

ADR на 20 страниц

Его не читают, решение тонет в деталях

Оставить summary, rationale и последствия; benchmarks и миграционный план вынести ссылками.

Только название технологии

Непонятно, почему выбор был разумным

Добавить контекст, драйверы, варианты и последствия.

ADR пишет только архитектор

Возникает очередь, команда не чувствует ownership

Разрешить инициировать ADR любому участнику, owner отвечает за процесс.

Нет статусов

Непонятно, действует ли решение

Ввести proposed, accepted, rejected, deprecated, superseded.

Accepted ADR редактируют молча

Теряется история

Существенное изменение оформлять новым ADR со ссылкой supersedes.

ADR не связан с кодом

Его не вспоминают в момент изменения системы

Ссылаться на ADR из PR, issues, tests и review checklist.

Считают количество ADR главным KPI

Команда пишет записи ради объема

Измерять использование: ссылки из PR, онбординг, поиск, снижение повторных споров.

Как запустить за 2-4 недели

  1. Выберите одну пилотную область: сервис, платформенный стандарт или активную архитектурную развилку.

  2. Согласуйте trigger-критерии: когда решение считается значимым.

  3. Создайте docs/adr/ и короткий decision-log.md.

  4. Напишите ADR-0001: "Мы используем ADR для фиксации архитектурных решений".

  5. На реальном текущем решении проведите 60-90 минутную сессию: контекст, drivers, alternatives, decision, consequences.

  6. За следующие две недели создайте еще 2-4 ADR только по настоящим решениям.

  7. Добавьте ссылки на ADR в PR и задачи.

  8. Через месяц проведите ретроспективу: какие поля не заполняются, что не находится, где запись помогла.

Не начинайте с backfill всей истории системы. Исследование Using Architecture Decision Records in Open Source Projects показывает, что сам факт наличия нескольких ADR еще не означает устойчивой практики. Более сильный сигнал — несколько авторов, продолжение практики во времени и реальное использование записей.

Метрики полезности

Минимальный dashboard пилота:

  • доля значимых решений, для которых есть ADR;

  • медианное время от появления развилки до записи;

  • число активных авторов и reviewers;

  • доля ADR со ссылками на код, issue, тест или design doc;

  • число ссылок на ADR из PR, onboarding, incident review или архитектурных обсуждений;

  • повторные споры по уже принятому решению без нового контекста;

  • доля вопросов, где человек или RAG-система быстро находит правильный действующий ADR.

Не используйте "количество ADR" как главную метрику. Это vanity metric. Ценность ADR проявляется тогда, когда запись помогает принять следующее решение быстрее и осознаннее.

FAQ

Нужно ли писать ADR на выбор каждой библиотеки?

Нет. ADR нужен, если библиотека становится долгоживущей зависимостью, определяет публичный контракт, влияет на безопасность, данные, эксплуатацию или становится организационным стандартом. Утилиту, которую можно заменить в одном PR, обычно не нужно документировать как ADR.

Кто должен писать ADR?

Тот, кто ближе всего к проблеме и может собрать контекст: разработчик, tech lead, SRE, security specialist, product engineer. Важнее назначить owner и reviewers, чем закрепить авторство только за архитектором.

Когда писать ADR: до или после решения?

Черновик полезно начать в момент развилки. Proposed ADR структурирует обсуждение. Accepted ADR фиксирует итог. Для крупного изменения сначала может быть RFC или design doc, а ADR появится как компактная запись принятого решения.

Можно ли документировать старые решения?

Да, если они продолжают влиять на работу и вызывают вопросы. Но такой ADR нужно пометить как retrospective/backfilled, указать дату восстановления и отделить известные факты от реконструкции.

Можно ли менять accepted ADR?

Опечатки, битые ссылки и уточнение formatting — да. Изменение смысла лучше оформлять новым ADR и связывать его через supersedes. Так история остается честной.

Git или wiki?

Для решений, связанных с кодом, Git обычно лучше: pull requests, история, ссылки на implementation. Wiki удобнее для неинженерной аудитории и межрепозиторного поиска. Практичный вариант — Git как source of truth и опубликованный каталог в wiki/портале.

Чем ADR отличается от RFC?

RFC помогает обсудить предложение и собрать согласие до решения. ADR хранит принятое решение и причины. В маленькой команде один документ может выполнять обе функции, но статус и канонический итог должны быть ясны.

Чем ADR отличается от design doc?

Design doc описывает будущую реализацию и может содержать API, план миграции, диаграммы и несколько решений. ADR атомарнее: одно значимое решение, его контекст и последствия.

Как избежать бюрократии?

Ограничьте ADR значимыми решениями, оставьте короткое ядро шаблона, встроите ревью в существующий pull request или design review и регулярно удаляйте поля, которыми никто не пользуется.

Как использовать ADR с AI coding agent?

Индексируйте только релевантные accepted ADR с metadata scope, status и supersession links. Действующие ограничения переносите в краткие scoped-инструкции для агента, а критичные правила закрепляйте тестами или архитектурными проверками.

Лицензия Creative Commons | by Igor Tsupko, Lana Novikova, Rodion Nagornov & community