lenec ru

← все посты

ADR vs RFC vs design doc: чем отличаются и когда что писать

10K

Каждое неочевидное архитектурное решение через год задают повторно. «А почему мы используем Postgres, а не MongoDB?». «Почему очередь на Redis, а не на Kafka?». «Почему всё в одном репозитории, а не в микросервисах?». Каждый раз это разговор на полчаса с тем, кто принимал решение пять лет назад. Если он уже не работает в компании — разговор не получится.

Решение этой проблемы — фиксировать архитектурные решения в репозитории. Под этим зонтиком живут три похожих, но разных формата: ADR, RFC и design doc. Названия путаются, команды используют их как синонимы, и в итоге на проекте есть «папка с архитектурными документами», в которой всё перемешано. Разберу, чем они отличаются, когда что использовать, и как не превратить процесс в бюрократию.

ADR — Architecture Decision Record

ADR фиксирует одно архитектурное решение в максимально лаконичной форме. Не предложение, не дискуссия, а уже принятое решение, со всем контекстом.

Стандартный шаблон Майкла Найгарда — пять секций:

# ADR-007: Use PostgreSQL for primary storage

## Status

Accepted (2026-03-15)

## Context

We need a primary data store for the user service.
Requirements:
- Strong consistency for financial data.
- ACID transactions across multiple tables.
- Team familiarity (we don't have time to learn new tech).
- Operational maturity (backups, monitoring, scaling).

## Decision

Use PostgreSQL 16 as the primary store.

## Consequences

Positive:
- Team is fluent, no learning curve.
- Mature tooling: pgbackrest, postgres_exporter, pgbouncer.
- ACID transactions out of the box.

Negative:
- Vertical scaling beyond ~100k QPS will require sharding.
- For event-heavy workloads, will need to add Kafka separately.

## Alternatives Considered

- MongoDB: rejected due to lack of multi-document transactions in our use case.
- DynamoDB: rejected, vendor lock-in to AWS.

Свойства хорошего ADR:

  • Короткий. Один-две страницы. Не книга.
  • Иммутабельный. Принят — не редактируется. Если решение пересматривается — новый ADR со ссылкой «Supersedes ADR-007».
  • Хранится в репозитории, рядом с кодом, в папке docs/adr/ или architecture/decisions/.
  • Нумерация сквозная и не переиспользуется.

ADR — для уже принятых решений. Если вопрос «что выбрать» ещё открыт, ADR не пишут — пишут предложение, обсуждают, и только после консенсуса оформляют ADR.

RFC — Request for Comments

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

Структура RFC обычно длиннее ADR:

  1. Summary. О чём предложение, в трёх предложениях.
  2. Motivation. Зачем это нужно.
  3. Detailed design. Как именно предлагается сделать.
  4. Drawbacks. Почему может не получиться.
  5. Alternatives. Что ещё рассматривалось и почему отклонено в первоначальной редакции.
  6. Unresolved questions. На что нужен ответ команды.

RFC живёт цикл:

  • Draft. Автор пишет, ходит в коридоре с ноутбуком, собирает первые мнения.
  • Review. Опубликован, открыт для комментариев, обычно 1-2 недели.
  • Accepted/Rejected. Команда приняла или отклонила. Если принят — превращается в ADR (или ссылается на новый ADR с принятым решением).

RFC — это процесс, ADR — артефакт. Когда RFC становится «принятым», его не выбрасывают — он остаётся как контекст, но реальный документ-источник правды на проекте — уже ADR.

На моей практике большие команды используют RFC для крупных решений (новый сервис, перевод на новую платформу), мелкие команды могут обойтись без них и сразу обсуждать в чате/PR. Бюрократия RFC оправдана, когда решение затрагивает несколько команд.

Design doc

Design doc — это технический проект, обычно для реализации фичи или сервиса. Он отвечает на вопрос «как мы это построим», а не «что мы выбираем».

Типичная структура:

  1. Goals и non-goals.
  2. Background — что уже есть, ограничения.
  3. Architecture overview — диаграмма, основные компоненты.
  4. Detailed design — структура данных, API, модули.
  5. Failure modes — что может пойти не так и как обрабатывается.
  6. Migration plan — как переходим на новое (если есть существующее).
  7. Testing plan — как валидируем.
  8. Rollout plan — как раскатываем.
  9. Monitoring и alerting — что мерим, на что алертим.
  10. Open questions — что ещё не решено.

Design doc — самый длинный из трёх. Может быть 10-20 страниц для крупного сервиса. Используется на крупных проектах в Google, Stripe, Notion. Меньше — на стартапах, где скорость важнее формальности.

Главное отличие от RFC: design doc не фокусируется на «выборе между альтернативами». Альтернативы там тоже могут быть, но основа — про то, как реализовать выбранный подход подробно.

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

Самый частый вопрос команды, переходящей на формализацию решений.

ADR — пишем, когда:

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

Примеры: «Используем Postgres вместо MySQL», «Применяем soft-delete для всех пользовательских данных», «Все API возвращают JSON, не XML», «Микросервисы синхронно через HTTP, события асинхронно через Kafka».

RFC — пишем, когда:

  • Предлагаем большое изменение, нужен консенсус нескольких команд.
  • Решение еще не принято, нужно обсуждение.
  • Хотим письменно зафиксировать аргументы за и против.

Примеры: «Мигрируем на новый message broker», «Переходим на TypeScript для бэкенда», «Меняем формат API с REST на gRPC».

Design doc — пишем, когда:

  • Реализуем фичу или сервис размером больше пары спринтов.
  • Нужно согласовать детали реализации с командой.
  • Хотим иметь документ для onboarding-а будущих разработчиков.

Примеры: «Сервис нотификаций v2», «Система прав доступа на основе RBAC», «Pipeline для обработки event log-а».

Анти-паттерн: всё подряд через RFC

Команды, которые увлекаются формальностями, начинают писать RFC на каждое решение. «Изменить таймаут с 5 до 10 секунд — заводим RFC». Через полгода у команды папка из 200 RFC, ревью занимает дни, и реальные большие изменения тонут в шуме.

Эвристика: если решение можно изменить за час, не нужен RFC. Если изменение займёт неделю — стоит подумать, нужен ли RFC. Если месяц — RFC оправдан.

Анти-паттерн: ADR-«паспорт»

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

Эвристика: ADR пишется, когда без документа решение будет переспрашиваться. Если решение очевидное и никем не оспаривается («использовать NumPy для математики в Python-проекте»), ADR не нужен.

Хранение и навигация

Все три типа лучше хранить в репозитории, в Markdown:

docs/
├── adr/
│   ├── 0001-record-architecture-decisions.md
│   ├── 0002-use-postgresql.md
│   └── ...
├── rfc/
│   ├── 0001-migrate-to-typescript.md
│   └── ...
└── design/
    ├── notification-service.md
    └── ...

В корне — индексные файлы (README.md в каждой папке), которые перечисляют документы со статусами. Можно генерировать автоматически из metadata в frontmatter каждого документа.

Альтернатива «всё в Confluence/Notion» работает хуже. Confluence-страницы устаревают быстрее, чем команда успевает обновлять. Markdown в репо ревьюится как код, версионируется, не теряется при ребрендинге wiki.

Workflow в виде PR

RFC и большие design docs обычно идут через PR-процесс.

  1. Автор создаёт branch rfc/migrate-to-typescript.
  2. Кладёт файл rfc/2026-XX-migrate-to-typescript.md со статусом Draft.
  3. Открывает PR, помечает reviewers.
  4. Команда комментирует прямо в PR.
  5. Автор обновляет документ, иногда несколько раундов.
  6. Достаточно approvals — PR мержится со статусом «Accepted» в документе.
  7. Если решение отвергнуто — PR закрывается, документ можно сохранить в rfc/rejected/ для истории.

Это работает в командах, привыкших к code review. Если культура ревью слабая, RFC будет либо аппрувится автоматически, либо висеть месяцами без feedback.

Что делать с устаревшими документами

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

Не удаляй устаревшие. Они часть истории. Но обозначь:

# ADR-007: Use PostgreSQL for primary storage

## Status

Superseded by ADR-042 (2026-08-01)

## Context
...

В шапку ADR-042 — обратная ссылка: «Supersedes ADR-007». Так читатель видит цепочку решений и понимает, какое актуально.

Кто пишет

Не «технический писатель». ADR, RFC и design doc пишет тот, кто принял решение или предлагает его — обычно архитектор, ведущий инженер или команда сервиса. Технический писатель может помочь с формулировками, структурой, единством стиля по проекту, но не подменяет автора.

Это важно, потому что суть документа — позиция автора с аргументами. Чужими словами она не передаётся.

Чек-лист, что у вас всё по делу

  • Есть папка docs/adr/ в репозитории, нумерация сквозная.
  • Каждый ADR — короткий, по шаблону Найгарда или похожему.
  • Устаревшие ADR помечены Superseded, есть ссылки на актуальные.
  • RFC используется для крупных предложений, требующих консенсуса.
  • RFC проходит через PR-процесс с явным статусом.
  • Design doc используется для проектирования крупных сервисов и фич.
  • В индексной странице — список документов со статусами.
  • Авторы — те, кто принимает решения, не отдельные писатели.
  • Нет «ADR-паспортов» на каждый чих и нет 200 RFC за полгода.

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

Комментарии 0

  • Будьте первым, кто оставит комментарий.

Войдите, чтобы оставить комментарий.