qvib.pro
EN

ADR (Architecture Decision Record)

Скелет записи об архитектурном решении — чтобы «почему так» не терялось.

бесплатно профи

Назначение

ADR (Architecture Decision Record) фиксирует значимое решение и его причины — коротко и навсегда. Цель: чтобы через полгода никто не спрашивал «почему так сделано, давайте переделаем», а откатывались к записи. ADR хранят рядом с кодом (docs/adr/), нумеруют, не удаляют (помечают superseded). Пишут только на значимые/необратимые развилки, не на каждую мелочь.

Подробный шаблон

# ADR-<NNN>: <короткое имя решения>

- **Дата:** <YYYY-MM-DD>
- **Статус:** proposed | accepted | deprecated | superseded by ADR-<M>

## Контекст
Какую проблему решаем, какие ограничения и силы действуют (нагрузка, сроки, команда, существующий стек).

## Рассматриваемые варианты
- **A — <название>:** плюсы / минусы.
- **B — <название>:** плюсы / минусы.
- **C — <название>:** плюсы / минусы.

## Решение
Выбрали <вариант> потому что <ключевая причина с опорой на контекст>.

## Последствия
Плюсы: <что выигрываем>.
Минусы / цена: <что усложняется, какой долг берём>.
Риски и как смягчаем: <…>.

Пример 1 — хранилище

# ADR-003: Хранение персонального ядра в IndexedDB (не localStorage)

- **Дата:** 2026-05-20
- **Статус:** accepted

## Контекст
Персональное ядро (избранное, заметки, коллекции) растёт; нужно надёжно хранить локально, переживать перезагрузку и поддержать экспорт. localStorage ограничен ~5 МБ и синхронный.

## Рассматриваемые варианты
- **A — localStorage:** просто, но лимит ~5 МБ, синхронный (блокирует UI), только строки.
- **B — IndexedDB:** больше объём, асинхронный, структурированные данные; сложнее API.
- **C — только облако:** нет офлайна, зависимость от сети и бэкенда с первого дня.

## Решение
Выбрали B (IndexedDB), потому что объём и асинхронность критичны для роста ядра и плавности UI, а офлайн-first — требование продукта.

## Последствия
Плюсы: запас по объёму, не блокирует UI, удобно для экспорта/импорта.
Минусы: сложнее API — обернём в тонкий слой-обёртку. Риск: разные браузеры — покроем тестами.

Пример 2 — суперсед

# ADR-007: Перейти с REST на tRPC для внутреннего API

- **Дата:** 2026-06-01
- **Статус:** accepted (supersedes ADR-002 «REST + ручные типы»)

## Контекст
Фронт и бэкенд на TS, контракт часто расходился (фронт ждал одно — бэк отдавал другое). ADR-002 (REST + ручная типизация) приводил к рассинхрону и багам.

## Рассматриваемые варианты
- **A — оставить REST + OpenAPI-кодоген:** надёжно, но лишний шаг генерации и конфиг.
- **B — tRPC:** end-to-end типы из коробки, без кодогена; привязка к TS-монорепо.

## Решение
Выбрали B (tRPC): монорепо на TS уже есть, end-to-end типобезопасность убирает целый класс багов рассинхрона.

## Последствия
Плюсы: контракт не разъедется, меньше ручной работы. Минусы: привязка к TS (не для внешнего публичного API — там оставим REST). ADR-002 помечен superseded.

Чек-лист качества

  • Одно решение на запись (не «10 решений в одном ADR»).
  • Видны отвергнутые альтернативы (минимум A/B), а не только выбранное.
  • Причина выбора явная и опирается на контекст.
  • Последствия названы, включая минусы и взятый долг.
  • Есть статус и дата; устаревшее помечено superseded, а не удалено.

Частые ошибки

  • Только решение, без альтернатив. → Без вариантов спор вернётся; покажи, что рассматривал.
  • Замолчали минусы. → Честно зафиксируй цену и долг — иначе «обманул будущего себя».
  • ADR на каждую мелочь. → Только значимые/необратимые развилки.
  • Удалили устаревший ADR. → Помечай superseded; история решений ценна.
  • «Решили на созвоне», нигде нет. → Не зафиксировано = не было; через полгода переобсудят с нуля.

Read in English →