Add architecture decision record templates
This commit is contained in:
@@ -0,0 +1,81 @@
|
|||||||
|
---
|
||||||
|
name: adr
|
||||||
|
description: >-
|
||||||
|
Создаёт и сопровождает Architecture Decision Records (ADR) в docs/adr/.
|
||||||
|
Используй, когда уже сделанное архитектурное или инфраструктурное
|
||||||
|
изменение нужно зафиксировать постфактум: выбор инструмента/подхода,
|
||||||
|
структурное решение, намеренный отказ от очевидного варианта, либо
|
||||||
|
прямая просьба «записать решение / завести ADR». А также когда старую
|
||||||
|
ADR нужно пометить заменённой или устаревшей. ADR пишут ПОСТФАКТУМ;
|
||||||
|
идеи, планы и обсуждения — это drafts, а не ADR.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Работа с ADR
|
||||||
|
|
||||||
|
ADR живут в `docs/adr/`. Формат и соглашения — `docs/adr/README.md`,
|
||||||
|
шаблон — `docs/adr/template.md`. Читай README перед первой записью в
|
||||||
|
сессии: правила там — источник истины, эта инструкция лишь даёт порядок
|
||||||
|
действий.
|
||||||
|
|
||||||
|
Язык записей — **русский**, стиль — как в `docs/drafts/`: конкретно,
|
||||||
|
по делу, без воды. Калибровка под личный хобби-сервер: не раздувай
|
||||||
|
запись, не предлагай корпоративные процессы.
|
||||||
|
|
||||||
|
## Сначала реши, нужен ли ADR
|
||||||
|
|
||||||
|
Заводи, если изменение **уже сделано** и это: выбор технологии/
|
||||||
|
инструмента, структурное решение, решение с долгосрочными последствиями
|
||||||
|
или дорогим откатом, либо намеренный отказ от очевидного варианта.
|
||||||
|
|
||||||
|
Не заводи:
|
||||||
|
- для рутины (бамп версии образа, сервис по накатанной схеме) и того,
|
||||||
|
что видно из кода/git;
|
||||||
|
- для идей, планов и того, что ещё не реализовано — это `docs/drafts/`,
|
||||||
|
а не ADR.
|
||||||
|
|
||||||
|
Если сомневаешься — спроси пользователя, не плоди записи молча.
|
||||||
|
|
||||||
|
## Создание новой ADR
|
||||||
|
|
||||||
|
1. **Дата.** Когда изменение реально сделано. Обычно сегодня
|
||||||
|
(`date +%F`). Если оформляем задним числом — уточни дату у
|
||||||
|
пользователя, не подставляй сегодняшнюю вслепую.
|
||||||
|
2. **Идентификатор и имя файла:** `ADR-ГГГГ-ММ-ДД-kebab-slug.md`
|
||||||
|
(slug — латиницей). Если за эту дату уже есть ADR — slug просто
|
||||||
|
должен отличаться; проверь `ls docs/adr/`.
|
||||||
|
3. **Файл.** Возьми за основу `docs/adr/template.md`.
|
||||||
|
4. **Заполни** по шаблону:
|
||||||
|
- Заголовок `# Человеческий заголовок` (без даты/ID в тексте).
|
||||||
|
- Метаданные: только `- Дата: ГГГГ-ММ-ДД`. **Строку статуса не
|
||||||
|
добавляй** — у активной записи статуса нет.
|
||||||
|
- **Контекст** — какая проблема и ограничения вынудили это делать.
|
||||||
|
- **Рассмотренные варианты** — *опциональная* секция. **Спроси
|
||||||
|
пользователя, рассматривал ли он какие-то альтернативы.** Если да —
|
||||||
|
перечисли их с плюсами/минусами (особенно те, что отвергнуты); если
|
||||||
|
нет (решение было единственным очевидным) — удали секцию целиком.
|
||||||
|
- **Решение** — что сделано и, **главное, почему**: какое намерение и
|
||||||
|
причина за этим стоят.
|
||||||
|
- **Последствия** — `+`/`-` и что нужно сделать как следствие.
|
||||||
|
5. **Индекс.** Добавь строку в таблицу «Список записей» в
|
||||||
|
`docs/adr/README.md`, **сверху** (новые сверху). Статус — `—`.
|
||||||
|
|
||||||
|
Самое важное в ADR — сохранить **почему**: намерение и причинность, а не
|
||||||
|
просто «что сделали». Не придумывай причины и альтернативы за
|
||||||
|
пользователя — если их нет в контексте сессии, обязательно спроси: что
|
||||||
|
подтолкнуло к изменению и какие варианты рассматривались.
|
||||||
|
|
||||||
|
## Замена / устаревание решения
|
||||||
|
|
||||||
|
Старые ADR неизменяемы. Если решение пересмотрено:
|
||||||
|
|
||||||
|
1. Заведи новую ADR (шаги выше). В её «Контексте» — строка
|
||||||
|
«Заменяет ADR-ГГГГ-ММ-ДД-slug».
|
||||||
|
2. В старой ADR добавь строку статуса сразу под датой:
|
||||||
|
`- Статус: заменено на ADR-ГГГГ-ММ-ДД-slug` (или `- Статус: устарело`,
|
||||||
|
если замены нет). Тело не трогай.
|
||||||
|
3. Обнови статус старой записи в индексе `README.md`.
|
||||||
|
|
||||||
|
## После записи
|
||||||
|
|
||||||
|
Покажи пользователю путь к файлу и кратко содержание. Не коммить без
|
||||||
|
явной просьбы.
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# Вести историю решений в виде ADR
|
||||||
|
|
||||||
|
- Дата: 0000-00-00
|
||||||
|
|
||||||
|
> Основополагающая запись о самом процессе ADR. Дата-сентинел
|
||||||
|
> `0000-00-00` (фактически создана 2026-05-24) — исключение: так запись
|
||||||
|
> всегда остаётся в самом низу списка и не путается с реальными
|
||||||
|
> изменениями.
|
||||||
|
|
||||||
|
## Контекст
|
||||||
|
|
||||||
|
Сервер развивается итеративно: меняются прокси, схема бэкапов, набор
|
||||||
|
сервисов, провайдер хостинга. Решения принимаются по одному, часто с
|
||||||
|
неочевидными компромиссами под ресурсы сервера и стоимость. Через
|
||||||
|
несколько месяцев мотивация забывается, и возникает риск «переоткрыть»
|
||||||
|
уже отвергнутый вариант или сломать то, что было сделано осознанно.
|
||||||
|
|
||||||
|
Журналы в `docs/drafts/` фиксируют хронологию и черновики, но не
|
||||||
|
обоснование выбора — по ним не видно, какие альтернативы отвергнуты и
|
||||||
|
почему.
|
||||||
|
|
||||||
|
## Рассмотренные варианты
|
||||||
|
|
||||||
|
- **ADR (отдельный файл на решение)** — стандартный формат, каждая
|
||||||
|
запись неизменяема, видно эволюцию через накопление и замену записей.
|
||||||
|
- **Один changelog-файл** — проще вести, но правки затирают историю
|
||||||
|
рассуждений, и формат расплывается со временем.
|
||||||
|
- **Ничего, держать в голове / в git-сообщениях** — нулевые затраты,
|
||||||
|
но обоснование теряется, а git-история не отвечает на вопрос «почему».
|
||||||
|
|
||||||
|
## Решение
|
||||||
|
|
||||||
|
Заводим каталог `docs/adr/` с записями в формате ADR (Nygard + блок
|
||||||
|
«Рассмотренные варианты»). Идентификатор записи — датовый,
|
||||||
|
`ADR-ГГГГ-ММ-ДД-slug`: дата (когда изменение реально сделано) сразу
|
||||||
|
видна в списке и позволяет оформлять записи задним числом. ADR пишем
|
||||||
|
постфактум, поэтому жизненный цикл сведён к двум статусам у потерявших
|
||||||
|
силу записей — `заменено на` и `устарело`; идеи и планы остаются в
|
||||||
|
`docs/drafts/`.
|
||||||
|
|
||||||
|
Формат и процесс описаны в [`README.md`](README.md), шаблон — в
|
||||||
|
[`template.md`](template.md). Для единообразия заполнение
|
||||||
|
автоматизировано скиллом `adr` (`.claude/skills/adr/`).
|
||||||
|
|
||||||
|
## Последствия
|
||||||
|
|
||||||
|
- `+` Сохраняется обоснование решений и отвергнутые альтернативы.
|
||||||
|
- `+` Датовый ID даёт хронологию «из коробки» и не мешает оформлять
|
||||||
|
записи задним числом.
|
||||||
|
- `+` Единый формат: записи делает человек или агент по одному шаблону.
|
||||||
|
- `-` Небольшая дисциплина: сделав значимое изменение, нужно не забыть
|
||||||
|
оформить ADR.
|
||||||
|
- Скилл `adr` берёт на себя имя файла, шаблон и обновление индекса в
|
||||||
|
`README.md`, снижая трение.
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# Architecture Decision Records (ADR)
|
||||||
|
|
||||||
|
Журнал значимых архитектурных и инфраструктурных решений по серверу.
|
||||||
|
Одна запись — одно решение. ADR пишем **постфактум**, когда изменение
|
||||||
|
уже сделано: идеи, планы и обсуждения живут в [`../drafts/`](../drafts),
|
||||||
|
а в ADR попадает только то, что реализовано. Записи **неизменяемы**:
|
||||||
|
передумали → не правим старую, а заводим новую и помечаем старую.
|
||||||
|
|
||||||
|
Чем ADR отличается от журналов в `../drafts/`: drafts — оперативная
|
||||||
|
хроника и черновики («что делаю / собираюсь сделать»), ADR — фиксация
|
||||||
|
выбора и его обоснования («почему сделал так, а не иначе»).
|
||||||
|
|
||||||
|
Главная ценность записи — сохранить **почему**: намерение и причинность.
|
||||||
|
Это важнее аккуратности оформления и полноты остальных секций.
|
||||||
|
|
||||||
|
## Когда заводить ADR
|
||||||
|
|
||||||
|
- Выбор технологии или инструмента (Caddy vs Nginx, restic vs borg).
|
||||||
|
- Структурные решения (схема бэкапов, организация плейбуков, сеть).
|
||||||
|
- Решения с долгосрочными последствиями или дорогим откатом.
|
||||||
|
- **Намеренный отказ** от очевидного подхода — чтобы потом не
|
||||||
|
переоткрывать «а почему мы не сделали X».
|
||||||
|
|
||||||
|
Не заводить для рутины (бамп версии образа, добавление сервиса по
|
||||||
|
накатанной схеме) и того, что и так видно из кода и git.
|
||||||
|
|
||||||
|
## Соглашения
|
||||||
|
|
||||||
|
- **Имя файла = идентификатор:** `ADR-ГГГГ-ММ-ДД-kebab-slug.md`.
|
||||||
|
Идентификатор — имя без `.md` (например `ADR-2026-05-24-adr-process`).
|
||||||
|
Slug — латиницей.
|
||||||
|
- **Дата** — когда изменение реально сделано (можно задним числом, а не
|
||||||
|
дата оформления записи).
|
||||||
|
- Несколько ADR за один день различаются по slug.
|
||||||
|
- **Заголовок в файле:** `# Человеческий заголовок` (без даты и ID — они
|
||||||
|
в имени файла и в строке «Дата»).
|
||||||
|
- Секция **«Рассмотренные варианты» — опциональна**: оставляй её, только
|
||||||
|
если альтернативы реально рассматривались.
|
||||||
|
- Шаблон новой записи — [`template.md`](template.md).
|
||||||
|
- Исключение: основополагающая мета-запись о самом процессе ADR
|
||||||
|
использует дату-сентинел `0000-00-00`, чтобы всегда оставаться в самом
|
||||||
|
низу списка. Реальные записи такую дату не используют.
|
||||||
|
|
||||||
|
## Статусы
|
||||||
|
|
||||||
|
Активная запись статуса **не имеет**. Статус появляется, только когда
|
||||||
|
запись теряет силу, и значений всего два:
|
||||||
|
|
||||||
|
- `заменено на ADR-ГГГГ-ММ-ДД-slug` — решение пересмотрено новой ADR.
|
||||||
|
- `устарело` — решение потеряло смысл и замены нет.
|
||||||
|
|
||||||
|
## Замена и устаревание
|
||||||
|
|
||||||
|
1. Заводим новую ADR; в её «Контексте» — строка
|
||||||
|
«Заменяет ADR-ГГГГ-ММ-ДД-slug».
|
||||||
|
2. В старой ADR добавляем строку `- Статус: заменено на ADR-…` сразу под
|
||||||
|
датой. Тело не трогаем — это часть истории.
|
||||||
|
3. Обновляем статус старой записи в индексе ниже.
|
||||||
|
|
||||||
|
## Список записей
|
||||||
|
|
||||||
|
Новые сверху.
|
||||||
|
|
||||||
|
| Дата | Запись | Статус |
|
||||||
|
| ---------- | ------------------------------------------------------------------------------- | ------ |
|
||||||
|
| 0000-00-00 | [Вести историю решений в виде ADR](ADR-0000-00-00-record-architecture-decisions.md) | — |
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# Краткий заголовок решения
|
||||||
|
|
||||||
|
- Дата: ГГГГ-ММ-ДД
|
||||||
|
<!-- Строку статуса добавляют позже, только если запись потеряла силу:
|
||||||
|
- Статус: заменено на ADR-ГГГГ-ММ-ДД-slug
|
||||||
|
- Статус: устарело
|
||||||
|
У активной записи строки статуса нет. -->
|
||||||
|
|
||||||
|
## Контекст
|
||||||
|
|
||||||
|
Что вынудило сделать изменение: проблема, силы и ограничения (ресурсы
|
||||||
|
сервера, стоимость, время на поддержку, существующая архитектура).
|
||||||
|
Пиши так, чтобы через год было понятно «почему это вообще делалось»
|
||||||
|
без чтения переписки.
|
||||||
|
|
||||||
|
## Рассмотренные варианты
|
||||||
|
|
||||||
|
<!-- Опциональная секция. Оставь, только если варианты реально
|
||||||
|
рассматривались. Если решение было единственным очевидным —
|
||||||
|
удали её, а причину объясни в «Решении». -->
|
||||||
|
|
||||||
|
- **Вариант A** — суть, плюсы и минусы.
|
||||||
|
- **Вариант B** — суть, плюсы и минусы.
|
||||||
|
- **Вариант C** — если отвергнут сразу, коротко почему.
|
||||||
|
|
||||||
|
## Решение
|
||||||
|
|
||||||
|
Что именно сделано и — главное — **почему**: какое намерение и какая
|
||||||
|
причина за этим стоят. Если варианты рассматривались — почему выбран
|
||||||
|
этот, а не остальные.
|
||||||
|
|
||||||
|
## Последствия
|
||||||
|
|
||||||
|
- `+` что стало лучше, какие возможности открылись.
|
||||||
|
- `-` чем платим: новые ограничения, риски, регулярная нагрузка на
|
||||||
|
поддержку.
|
||||||
|
- Что нужно сделать как следствие (если есть).
|
||||||
Reference in New Issue
Block a user