From e45e1db002d31afe3647f84e4b6835d1038396be Mon Sep 17 00:00:00 2001 From: Anton Vakhrushev Date: Sun, 24 May 2026 14:35:35 +0300 Subject: [PATCH] Add architecture decision record templates --- .claude/skills/adr/SKILL.md | 81 +++++++++++++++++++ ...000-00-00-record-architecture-decisions.md | 54 +++++++++++++ docs/adr/README.md | 66 +++++++++++++++ docs/adr/template.md | 37 +++++++++ 4 files changed, 238 insertions(+) create mode 100644 .claude/skills/adr/SKILL.md create mode 100644 docs/adr/ADR-0000-00-00-record-architecture-decisions.md create mode 100644 docs/adr/README.md create mode 100644 docs/adr/template.md diff --git a/.claude/skills/adr/SKILL.md b/.claude/skills/adr/SKILL.md new file mode 100644 index 0000000..54db165 --- /dev/null +++ b/.claude/skills/adr/SKILL.md @@ -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`. + +## После записи + +Покажи пользователю путь к файлу и кратко содержание. Не коммить без +явной просьбы. diff --git a/docs/adr/ADR-0000-00-00-record-architecture-decisions.md b/docs/adr/ADR-0000-00-00-record-architecture-decisions.md new file mode 100644 index 0000000..05db70f --- /dev/null +++ b/docs/adr/ADR-0000-00-00-record-architecture-decisions.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`, снижая трение. diff --git a/docs/adr/README.md b/docs/adr/README.md new file mode 100644 index 0000000..fac4835 --- /dev/null +++ b/docs/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) | — | diff --git a/docs/adr/template.md b/docs/adr/template.md new file mode 100644 index 0000000..b7c86e4 --- /dev/null +++ b/docs/adr/template.md @@ -0,0 +1,37 @@ +# Краткий заголовок решения + +- Дата: ГГГГ-ММ-ДД + + +## Контекст + +Что вынудило сделать изменение: проблема, силы и ограничения (ресурсы +сервера, стоимость, время на поддержку, существующая архитектура). +Пиши так, чтобы через год было понятно «почему это вообще делалось» +без чтения переписки. + +## Рассмотренные варианты + + + +- **Вариант A** — суть, плюсы и минусы. +- **Вариант B** — суть, плюсы и минусы. +- **Вариант C** — если отвергнут сразу, коротко почему. + +## Решение + +Что именно сделано и — главное — **почему**: какое намерение и какая +причина за этим стоят. Если варианты рассматривались — почему выбран +этот, а не остальные. + +## Последствия + +- `+` что стало лучше, какие возможности открылись. +- `-` чем платим: новые ограничения, риски, регулярная нагрузка на + поддержку. +- Что нужно сделать как следствие (если есть).