ADR простыми словами: как фиксировать архитектурные решения, чтобы ИИ не ломал проект
Основной чат
Чат для вайбкодеров: новости, гайды, поиск исполнителей, маркетплейс и разбор реальных кейсов.
Представьте проект, в котором команда хранит основные данные в PostgreSQL, использует Redis только как кеш и отправляет внешние уведомления через очередь. Это не случайный набор технологий. Возможно, PostgreSQL выбрали из-за транзакций, Redis запретили использовать как источник истины после потери данных, а очередь появилась из-за нестабильного API партнера.
Через полгода к проекту подключается новый разработчик или AI-агент. Он видит только текущий код. Причины решений ему неизвестны.
Агент получает задачу ускорить endpoint и предлагает:
- перенести состояние заказа в Redis;
- вызывать API партнера прямо из HTTP-запроса;
- удалить «лишнюю» очередь;
- объединить два похожих адаптера;
- заменить PostgreSQL на более простую базу.
Каждое предложение может выглядеть логично в пределах одного файла. Но оно нарушает ограничения, которые команда уже обнаружила на практике.
Проблема не в том, что ИИ плохо пишет код. Проблема в том, что код хранит результат решения, но не хранит ход рассуждений.
Для этого существуют ADR.
ADR, или Architecture Decision Record, - это короткий документ, который фиксирует одно значимое архитектурное решение, его контекст, рассмотренные варианты и последствия.
ADR отвечает не только на вопрос «что мы выбрали», но и на более важные вопросы:
- какую проблему решали;
- какие ограничения учитывали;
- какие альтернативы рассматривали;
- почему приняли именно этот вариант;
- какую цену и риски осознанно приняли;
- когда решение нужно пересмотреть.
Для разработки с ИИ это один из самых полезных видов документации. README объясняет, как запустить проект. Код показывает текущую реализацию. AGENTS.md задает правила работы. А ADR объясняет, почему архитектурные границы выглядят именно так.
Что такое Architecture Decision Record
Термин ADR обычно связывают с Майклом Найгардом и его статьей Documenting Architecture Decisions. Идея проста: архитектурно значимые решения нужно хранить как небольшие неизменяемые записи рядом с проектом.
Один файл описывает одно решение. Например:
docs/adr/
├── 0001-use-postgresql-as-source-of-truth.md
├── 0002-send-webhooks-through-outbox.md
├── 0003-isolate-ai-providers-behind-gateway.md
└── 0004-store-user-files-in-s3.md
ADR не обязан быть длинным. Хорошую запись часто можно прочитать за две минуты. Ее ценность не в объеме, а в сохраненном контексте.
Типичный ADR содержит:
- Название решения.
- Статус.
- Контекст и проблему.
- Принятое решение.
- Последствия.
- Рассмотренные альтернативы.
Главный принцип: ADR описывает решение, а не пересказывает устройство всей системы.
Почему одного кода недостаточно
Допустим, в проекте есть интерфейс:
interface TextGenerator {
generate(input: GenerateInput): Promise<GenerateResult>;
}
И две реализации:
class OpenAiTextGenerator implements TextGenerator {}
class LocalTextGenerator implements TextGenerator {}
По коду можно понять, что провайдеры изолированы общим контрактом. Но нельзя надежно понять, зачем это сделано.
Возможные причины:
- компания должна уметь отключить внешний API;
- часть данных нельзя отправлять в облако;
- стоимость моделей регулярно меняется;
- нужен fallback при сбое провайдера;
- разные клиенты используют разные модели;
- команда уже пережила сложную миграцию SDK.
Без этих причин AI-агент может решить, что интерфейс избыточен, и заменить его прямым вызовом SDK. Тесты останутся зелеными, задача будет закрыта, а важная архитектурная защита исчезнет.
Комментарии в коде тоже не решают проблему полностью. Комментарий объясняет локальный фрагмент. Архитектурное решение обычно затрагивает несколько модулей, инфраструктуру, эксплуатацию и будущие ограничения.
ADR сохраняет связь между проблемой и выбранной границей.
Какие решения действительно заслуживают ADR
Документировать каждую переменную и библиотеку не нужно. ADR полезен для решений, которые:
- дорого отменять;
- влияют на несколько частей системы;
- определяют долгосрочную границу;
- связаны с заметным компромиссом;
- ограничивают будущие реализации;
- могут снова вызвать спор через несколько месяцев;
- выглядят странно без знания контекста.
Хорошие кандидаты:
- выбор основной базы данных;
- правила разделения монолита и сервисов;
- способ аутентификации и хранения сессий;
- синхронная или асинхронная обработка событий;
- формат публичного API;
- стратегия мультитенантности;
- выбор источника истины;
- правила хранения персональных данных;
- граница между доменной логикой и внешними интеграциями;
- использование AI-gateway вместо прямых вызовов моделей;
- стратегия деплоя и обратной совместимости миграций.
Плохие кандидаты:
- переименование локальной функции;
- выбор названия переменной;
- форматирование кода;
- мелкая библиотека, которую легко заменить;
- временный эксперимент без влияния на остальную систему;
- решение, уже очевидное из стандартов проекта.
Простой фильтр:
Если через шесть месяцев разумный разработчик может удалить или изменить эту конструкцию, не понимая ее скрытую причину, решение стоит зафиксировать.
Готовый шаблон ADR
Универсального обязательного формата нет. Для большинства проектов достаточно такого шаблона:
# ADR-0007: Использовать PostgreSQL как источник истины для заказов
- Статус: принято
- Дата: 2026-07-11
- Авторы: команда backend
## Контекст
Какую проблему решаем? Какие ограничения, риски и требования важны?
## Решение
Что именно решили делать? Где проходит граница решения?
## Последствия
Какие преимущества получаем? Какую сложность и ограничения принимаем?
## Альтернативы
Какие варианты рассматривали и почему не выбрали?
## Условия пересмотра
При каких фактах или изменениях решение нужно открыть заново?
Последний раздел необязателен, но особенно полезен. Он превращает архитектурное решение из догмы в проверяемую гипотезу.
Например:
## Условия пересмотра
Пересмотреть решение, если:
- объем записей превысит 50 000 событий в секунду;
- появится требование автономной работы без центральной БД;
- стоимость эксплуатации станет выше согласованного бюджета;
- PostgreSQL перестанет выполнять требования по задержке после оптимизации.
Теперь будущий разработчик понимает не только запрет, но и условия, при которых его можно обоснованно снять.
Полный пример ADR для проекта с ИИ
Рассмотрим решение изолировать поставщиков моделей за внутренним интерфейсом.
# ADR-0003: Изолировать AI-провайдеров за внутренним gateway
- Статус: принято
- Дата: 2026-07-11
## Контекст
Приложение использует генерацию текста в трех сценариях. Сейчас код напрямую
зависит от SDK одного провайдера. Формат ошибок, tool calls и потоковой выдачи
распространился по бизнес-модулям.
Нужно сохранить возможность:
- менять модель без переписывания бизнес-логики;
- направлять чувствительные запросы в локальную модель;
- добавлять fallback при недоступности основного провайдера;
- централизованно учитывать стоимость, таймауты и трассировку.
## Решение
Бизнес-модули зависят от внутреннего интерфейса `TextGenerator`.
SDK провайдеров разрешены только внутри `infrastructure/ai/providers`.
Gateway нормализует ответы, ошибки и метрики, но не содержит бизнес-промпты.
## Последствия
Положительные:
- детали SDK не распространяются по проекту;
- провайдеры заменяются локально;
- тесты не требуют внешнего API;
- стоимость и ошибки наблюдаются в одном месте.
Отрицательные:
- внутренний контракт придется развивать;
- не все уникальные возможности провайдера удобно нормализовать;
- gateway становится критической частью системы.
## Альтернативы
1. Прямые вызовы SDK в каждом сценарии: проще на старте, но усиливают связанность.
2. Внешний универсальный proxy: ускоряет интеграцию, но добавляет зависимость
от отдельного сервиса и не решает правила маршрутизации домена.
## Условия пересмотра
Пересмотреть, если приложение останется с одним провайдером и одним сценарием,
а стоимость поддержки gateway будет выше стоимости прямой интеграции.
Такой документ дает AI-агенту важную информацию. Он может менять реализацию конкретного адаптера, но не должен переносить SDK в бизнес-модули без нового архитектурного решения.
Статусы ADR и жизненный цикл решения
ADR не должен исчезать после изменения архитектуры. Старый документ сохраняет историю и получает новый статус.
Обычно достаточно четырех статусов:
| Статус | Значение |
|---|---|
proposed |
Решение предложено и обсуждается |
accepted |
Решение принято и действует |
deprecated |
Решение больше не рекомендуется, но еще встречается в системе |
superseded |
Решение заменено другим ADR |
Некоторые команды добавляют rejected для важных отклоненных вариантов. Это полезно, если один и тот же спор регулярно возвращается.
Пример замены решения:
# ADR-0003: Изолировать AI-провайдеров за внутренним gateway
- Статус: заменено ADR-0014
Новый документ должен ссылаться на старый:
# ADR-0014: Перенести маршрутизацию AI-запросов во внешний gateway
- Статус: принято
- Заменяет: ADR-0003
Не стоит переписывать старый ADR так, будто команда всегда знала правильный ответ. Ценность записи именно в сохранении контекста на момент решения.
ADR, README, AGENTS.md и Memory Bank: что где хранить
Эти файлы решают разные задачи.
| Документ | Главный вопрос |
|---|---|
README.md |
Как понять, запустить и использовать проект? |
AGENTS.md |
Как AI-агент должен работать в этом репозитории? |
| Memory Bank | Каков текущий контекст, состояние и ближайшие цели проекта? |
| ADR | Почему принято конкретное архитектурное решение? |
| Task или issue | Что нужно изменить сейчас? |
Пример распределения:
README.md:
Основная база данных проекта - PostgreSQL.
AGENTS.md:
Не добавляй другие постоянные хранилища без архитектурного согласования.
Перед изменением слоя данных прочитай docs/adr/0001-use-postgresql.md.
ADR:
PostgreSQL выбран источником истины из-за транзакций между заказом,
оплатой и журналом операций. Redis используется только как восстановимый кеш.
Memory Bank:
Сейчас выполняется перенос таблицы платежей на новую схему.
Этап dual write включен на dev.
Не нужно копировать один и тот же длинный текст во все документы. Достаточно коротких правил и ссылок на источник контекста.
Подробнее о правилах репозитория рассказано в материале «AGENTS.md: единый источник истины для ИИ-агентов», а о текущем контексте - в статье про Memory Bank.
Как организовать ADR в репозитории
Для небольшого проекта достаточно простой структуры:
docs/
└── adr/
├── README.md
├── 0001-use-postgresql.md
├── 0002-use-s3-for-user-files.md
└── 0003-isolate-ai-providers.md
В docs/adr/README.md удобно хранить индекс:
# Architecture Decision Records
| ADR | Решение | Статус |
|---|---|---|
| [0001](./0001-use-postgresql.md) | PostgreSQL как источник истины | принято |
| [0002](./0002-use-s3-for-user-files.md) | S3 для пользовательских файлов | принято |
| [0003](./0003-isolate-ai-providers.md) | Gateway для AI-провайдеров | принято |
Практические правила:
- используйте последовательные номера;
- храните один вопрос в одном файле;
- пишите название как принятое действие, а не как общую тему;
- добавляйте ADR в тот же pull request, где реализуется решение;
- назначайте владельца или участников обсуждения;
- не удаляйте замененные записи;
- связывайте новый ADR со старым;
- держите документы рядом с кодом и проверяйте через обычное code review.
Название 0007-database.md слишком широкое. Название 0007-use-postgresql-as-order-source-of-truth.md сразу сообщает суть и границу решения.
Как подключить ADR к AI-агенту
Просто положить документы в репозиторий недостаточно. Агент может не открыть их, если задача выглядит локальной.
В глобальные или проектные инструкции нужно добавить маршрут чтения:
## Архитектурные решения
- Перед изменением архитектуры, хранилищ, очередей, API-контрактов,
аутентификации или AI-интеграций прочитай `docs/adr/README.md`.
- Действующие ADR имеют приоритет над предположениями из текущего кода.
- Не нарушай ADR со статусом `accepted` без явного предложения нового ADR.
- Для значимого решения сначала создай ADR со статусом `proposed`.
- Не переписывай историю: заменяй решение новым ADR со взаимными ссылками.
Полезно также потребовать от агента назвать затронутые решения до редактирования:
Перед реализацией:
1. Найди ADR, связанные с задачей.
2. Кратко перечисли ограничения из них.
3. Сообщи, соответствует ли предложенный план действующим решениям.
4. Если возникает конфликт, останови изменение архитектуры и предложи новый ADR.
Это снижает риск тихого архитектурного дрейфа, когда каждое отдельное изменение выглядит разумным, но система постепенно теряет исходные границы.
Как принимать ADR вместе с ИИ
ИИ полезен не только как читатель, но и как помощник при подготовке решения. Однако нельзя просить модель просто «выбрать лучшую архитектуру». Ей нужно дать критерии и заставить показать компромиссы.
Рабочий запрос:
Подготовь ADR со статусом proposed.
Проблема: нужно выбрать способ доставки событий о платежах во внешнюю CRM.
Сначала:
- собери ограничения из кода, документации и действующих ADR;
- перечисли decision drivers;
- предложи минимум три реалистичных варианта;
- для каждого оцени надежность, сложность, стоимость, наблюдаемость,
обратимость и влияние на текущую архитектуру;
- отдельно перечисли неизвестные факты, которые могут изменить выбор.
Не выбирай вариант, пока не покажешь сравнительную таблицу.
После выбора заполни контекст, решение, последствия, альтернативы
и условия пересмотра.
Особенно важен список неизвестных фактов. ИИ склонен уверенно заполнять пробелы предположениями. Хороший ADR должен отделять проверенные ограничения от догадок.
Что писать в последствиях
Слабый ADR выглядит так:
## Последствия
Архитектура станет надежнее и масштабируемее.
Это ничего не значит и не помогает будущему решению.
Последствия должны быть конкретными:
## Последствия
Положительные:
- HTTP-запрос больше не зависит от доступности CRM;
- неотправленные события сохраняются после перезапуска;
- повторная доставка контролируется idempotency key.
Отрицательные:
- появляется фоновый worker;
- доставка становится eventual consistent;
- нужны мониторинг очереди и процедура повторной обработки;
- порядок событий для одного клиента придется обеспечивать отдельно.
Архитектура почти всегда обменивает один вид сложности на другой. Если у решения нет отрицательных последствий, автор либо не закончил анализ, либо пишет рекламный текст вместо ADR.
Частые ошибки при ведении ADR
Решение записывают после реализации
Тогда документ часто превращается в оправдание уже написанного кода. Лучше создавать proposed ADR до крупного изменения и принимать его вместе с планом реализации.
В ADR нет альтернатив
Без альтернатив невозможно понять, был ли выбор осознанным. Достаточно двух или трех реалистичных вариантов с коротким объяснением.
Фиксируется только положительная сторона
У каждого архитектурного решения есть цена: задержка, сложность эксплуатации, зависимость, стоимость миграции или ограничение возможностей.
Один файл описывает всю архитектуру
Большой документ быстро устаревает и плохо показывает историю. ADR должен быть маленьким и посвященным одному решению.
Старые записи удаляют или переписывают
В результате команда теряет причины прошлых изменений и снова обсуждает уже отвергнутые варианты.
ADR превращают в закон навсегда
Архитектурное решение действует в конкретном контексте. Если контекст изменился, нужно создать новый ADR и заменить старый.
Агенту не указали, где искать решения
Наличие папки docs/adr не гарантирует, что модель прочитает ее перед локальной задачей. Маршрут должен быть записан в AGENTS.md или аналогичных инструкциях.
Когда ADR не поможет
ADR не заменяет:
- тесты;
- схемы данных;
- API-спецификации;
- runbook для эксплуатации;
- задачи и критерии приемки;
- актуальный код;
- обсуждение с владельцами системы.
Он фиксирует решение, но не доказывает, что реализация ему соответствует. Если в ADR написано «Redis только кеш», а новый модуль хранит там единственную копию заказа, документ сам по себе ничего не остановит.
Полезно добавить автоматические проверки там, где правило можно формализовать. Например, architecture test может запретить импорт SDK AI-провайдера вне каталога адаптеров. ADR объясняет причину, а тест обеспечивает границу.
Минимальный процесс без бюрократии
Для небольшой команды или личного проекта достаточно пяти шагов:
- Заметить решение, которое дорого отменять или легко неправильно понять.
- Создать короткий ADR со статусом
proposed. - Сравнить альтернативы и явно записать компромиссы.
- Принять ADR в том же pull request, где начинается реализация.
- При изменении контекста создать новый ADR и пометить старый как
superseded.
Не требуется архитектурный комитет, отдельная база знаний или длинное согласование. Один Markdown-файл на решение уже сохраняет больше контекста, чем переписка в чате, которую никто не найдет через полгода.
Чек-лист хорошего ADR
Перед принятием записи проверьте:
- заголовок сообщает конкретное решение;
- контекст описывает проблему, а не готовый ответ;
- требования отделены от предположений;
- перечислены реальные альтернативы;
- понятно, почему выбран этот вариант;
- записаны положительные и отрицательные последствия;
- указана область действия решения;
- есть условия пересмотра;
- новый ADR не противоречит действующим без явной замены;
- реализация и тесты могут быть связаны с решением;
- AI-агент знает, когда обязан прочитать этот документ.
Частые вопросы
Что такое ADR простыми словами?
ADR - это короткий файл, который объясняет одно важное архитектурное решение: какую проблему решали, что выбрали, какие альтернативы отклонили и какие последствия приняли.
Как расшифровывается ADR?
ADR расшифровывается как Architecture Decision Record, то есть запись об архитектурном решении. Набор таких записей иногда называют Architecture Decision Log.
Где хранить ADR?
Для большинства проектов удобно хранить ADR рядом с кодом в каталоге docs/adr. Тогда документы версионируются Git, проходят code review и доступны AI-агенту в том же рабочем контексте.
Когда нужно создавать ADR?
ADR нужен для значимого, долгосрочного или дорогого в отмене решения: выбора базы, границы сервиса, модели аутентификации, способа доставки событий, источника истины или изоляции внешнего API.
Нужно ли обновлять старые ADR?
Фактические опечатки исправлять можно, но историю решения лучше не переписывать. Если контекст изменился, создайте новый ADR, пометьте старый как superseded и свяжите документы ссылками.
Чем ADR отличается от технического задания?
Техническое задание описывает требуемый результат конкретной работы. ADR фиксирует архитектурный выбор и его причины, которые могут влиять на множество будущих задач.
Чем ADR полезен AI-агентам?
AI-агент видит код, но не знает историю обсуждений и скрытые ограничения. ADR дает ему причины существующих границ и снижает риск удалить важную конструкцию как «лишнюю».
Главный вывод
Архитектура разрушается не только из-за плохих решений. Она разрушается и потому, что хорошие решения со временем теряют объяснение.
Код сообщает, что система использует очередь. ADR объясняет, что очередь появилась после потери webhook при сбое партнера. Код показывает интерфейс AI-gateway. ADR сохраняет требования по приватности, fallback и учету стоимости. Код можно переписать за один запрос к агенту. Контекст без отдельной записи восстановить намного сложнее.
Хороший ADR не пытается предсказать всё будущее. Он честно фиксирует текущую проблему, выбранный компромисс и условия, при которых решение перестанет быть правильным.
Начните с одного файла для самого важного решения проекта. Добавьте ссылку на него в AGENTS.md и потребуйте от AI-агента проверять действующие ADR перед архитектурными изменениями. Этого уже достаточно, чтобы решения переживали смену людей, инструментов и моделей.
Основные источники: