В корпоративной wiki лежит описание системы на двести страниц, в последний раз тронутое три года назад. В чате новичок спрашивает: зачем сервис аутентификации ходит в LDAP, если половина пользователей давно в собственной базе? Ответ знает один человек, и он уволился в прошлом квартале. Половина чата предлагает переписать модуль по-своему, через день другой ветеран вспоминает: этот обходной путь когда-то спасал медленный поиск по огромной папке, и переписывание сломает синхронизацию. Спор тянется неделю, заканчивается ничем и повторяется каждые полгода. Именно эту сцену лечат ADR-документы, короткие записи архитектурных решений, живущие рядом с кодом, а не в парадном справочнике.

Головная боль без записей и два слепых пути в никуда

Майкл Нигард, автор формата, сформулировал мысль ещё в 2011 году: труднее всего в жизни проекта удержать мотивацию уже принятых решений. Код показывает, как система устроена, и молчит о том, почему она устроена именно так. Человек, столкнувшийся с чужим решением, стоит перед выбором из двух слепых путей. Принять не разбираясь: если контекст давно изменился, решение пора пересматривать, а команда, годами принимающая решения на веру, постепенно страшится менять вообще что-либо и тонет в собственном весе. Отменить не разбираясь: если выбор держал невидимое требование, скажем запас по нагрузке, которую ещё ни разу не мерили, поломка всплывёт позже там, где её никто не ищет. Оба пути приводят в одно место, разница только в сроках. Запись решения убирает саму вилку: человек читает не только вывод, но и расклад сил вокруг него, и действует с открытыми глазами.

Формат ADR-документа и размер в одну страницу

Формат от Нигарда нарочито беден, в этом его сила. Заголовок короткой именной группой вроде "ADR 9: LDAP для интеграции арендаторов". Статус: предложено или принято, позже устарело или заменено, со ссылкой на запись-наследника. Контекст: расклад сил, технических и человеческих, изложенный языком без оценок, сухая фиксация фактов. Решение полными предложениями в активном залоге, от первого лица множественного числа: мы переносим, мы принимаем. Последствия, и вот тут дисциплина важнее всего: все последствия, положительные, отрицательные и нейтральные, потому что каждое из них ждёт команду впереди. Весь документ умещается в одну-две страницы.

Живут записи в репозитории проекта, в каталоге вида doc/arch/adr-NNN.md, в лёгкой разметке Markdown. Нумерация сквозная и монотонная, номера не переиспользуются никогда. Если решение отменено, старая запись остаётся рядом с пометкой о замене: важно знать не только текущий выбор, но и то, что когда-то выбирали иначе. Запись проходит то же ревью, что и код, и пересматривается тем же порядком. Нигард советовал писать каждую запись как разговор с будущим разработчиком: полными предложениями, абзацами, без обрывков. Перечни в его схеме допустимы только как оформление, а не как способ сказать половину мысли.

Границы формата стоит проговорить сразу. Запись решения не описание системы, не учебник и не протокол встречи: обсуждение живёт на встрече, а в запись попадает его итог. Одна запись держит одно решение, и попытка оформить "решения по проекту целиком" даёт нечитаемый ком, из которого нельзя ничего процитировать. Контекст требует осторожности в другом смысле: силы там технические, организационные и даже личные, например опыт команды, но людей записывать не нужно, достаточно расклада. Не место в записи и секретам: ключи и пароли живут в хранилище секретов, а запись пусть называет инструмент, а не значение. Наконец, журнал держит меру: если выбор тривиален и обратим, скажем переименование поля, цена записи выше цены забвения, и она не нужна. На другом полюсе выбор нарезки системы на сервисы, схема хранения заказов, стандарт обработки ошибок: эти решения не отменяются за вечер, и короткая страница окупается многократно.

Запись в движении и образец реального документа

Отдельная запись описывает одно решение и его расклад, а последствия прошлой записи становятся контекстом следующей. Так журнал читается как история проекта, где каждый шаг опирается на предыдущий. Вот как выглядит запись вживую:

# 14. Очередь исходящих писем на Redis вместо таблицы в Postgres

Дата: 2024-03-11
Статус: принята

## Контекст

Рассылка уведомлений выросла, таблица писем в Postgres мешает
обслуживанию базы, лёгкие отчёты по заказам тормозят. Опыт работы
с Redis в команде есть, инфраструктура уже содержит Redis для кэша.

## Решение

Мы переносим очередь исходящих писем в Redis и оставляем в Postgres
только архив доставленных писем.

## Последствия

Скорость отправки больше не зависит от основной базы; появился
второй источник правды по состоянию отправки; команде нужен контроль
лага репликации между сервисами.

Полчаса работы, и через три года любой новый человек поймёт выбор без раскопок в истории чата. Рутина упрощается инструментами: утилита adr-tools создаёт следующий по номеру файл из шаблона одной командой:

adr new "Очередь исходящих писем на Redis"

Автору остаётся заполнить секции. Три года спустя команда перерастает Redis, и новая запись под номером 21 объявляет решение 14 заменённым, сохраняя его в истории. Журнал читается как летопись: видно, что выбор был разумным тогда и почему он уступил место новому. Есть и более сжатая схема из практики архитектурных записей, Y-формулировка: в таком-то контексте, столкнувшись с такой-то силой, мы приняли такое-то решение, чтобы получить такой-то эффект, пожертвовав таким-то. Одна фраза, и вся анатомия выбора на ладони.

Польза, которая проявляется на втором и третьем году

Первая выгода приходит с онбордингом. Новичок читает журнал решений за вечер и входит в проект без стола вопросов, а наставник тратит время на дело, а не на пересказ забытых споров. Вторая выгода зреет медленнее и стоит дороже: смелость. Когда контекст меняется, пользователи подросли, поставщик инструмента объявил о конце поддержки, из записи видно, что именно пересматривать и что это потянет за собой. Симметрично запись спасает от необдуманной отмены: рядом с решением лежит список его последствий, и половина "очевидных" улучшений умирает после первого же взгляда на этот список. Третья выгода чисто экономная: повторные споры исчезают. Обсуждение на планёрке заканчивается ссылкой на номер записи, и группа экономит час, который иначе ушёл бы на пересказ аргументов трехлетней давности. Команды меняются, люди уходят, записи переживают всех: в этом смысле журнал решений принадлежит проекту, а не его сотрудникам. Есть и четвёртая выгода, незаметная в спокойные годы. Разбор инцидента, внешняя проверка, передача проекта другой команде: все эти события требуют ответа на вопрос, что здесь осознанная плата, а что недосмотр. Журнал отвечает мгновенно и по пунктам, а без него команда реконструирует мотивы по следам, тратя недели на то, что записано в двух абзацах. Отсюда и совет для владельцев продукта: перед крупными договорённостями с подрядчиками журнал стоит перечитать, чтобы обещать только то, что архитектура реально позволяет.

Живой сценарий из практики выглядит так. Команда получает задачу вынести авторизацию в отдельный сервис, проект растянут на квартал, и на втором месяце в журнале обнаруживается запись двухлетней давности: вынос уже обсуждался и отвергался из-за токенов с истекающим сроком, которых тогда не было в инфраструктуре. Теперь токены появились, и запись превращается из тормоза в карту маршрута: препятствия прошлого захода известны, способ их обойти тоже. Без записи команда открыла бы те же препятствия заново, ценой пары недель проектирования.

Ошибки внедрения, от которых журнал решений умирает

У формата есть типовые причины смерти, и почти все они человеческие, а не технические. Первая: записи задним числом ради отчётности. Документ, составленный через год по памяти, фиксирует вывод без расклада сил и не отвечает ни на один настоящий вопрос, зато создаёт видимость порядка. Вторая: парадные записи без последствий. Когда в графе последствий одно радостное предложение, запись бесполезна: самое ценное в решении его цена, и читателю через год нужна именно она. Третья: правка старых записей вместо замены. Стоит однажды отредактировать принятое решение по новому вкусу, и журнал перестаёт быть историей: никто уже не скажет, что именно и когда менялось. Четвёртая: размножение записей по каждой мелочи. Журнал из трёхсот пунктов о переименованиях полей так же нечитаем, как wiki на двести страниц, и доверие к нему падает по той же причине. Пятая: записи без статуса, где предложенное годами числится принятым, и никто не отличает план от договорённости. Шестая: журнал в отдельном хранилище, оторванный от кода: записи расходятся с проектом, и через год о них не вспоминает даже автор. Все шесть причин лечатся одной привычкой: писать коротко, в момент решения, рядом с кодом, и честно заполнять последние две секции, ради которых формат и придуман.

Громоздкая wiki и ловушка описания всего и сразу

Аргумент против больших документов старше формата ADR: объёмистые документы никогда не поддерживаются в актуальном состоянии, их некому читать, а на несчастливых проектах спецификация выходила тяжелее, чем весь исходный код. Страница wiki стареет тихо: выглядит живой, а код давно ушёл вперёд, и доверие к справочнику падает с каждой такой находкой. Запись решения не конкурирует с wiki в объёме, это журнал, а не справочник. В запись попадает только архитектурно значимое: структура системы, нефункциональные свойства, зависимости, интерфейсы, приёмы сборки. Описания методов живут в спецификации, шаги развёртывания в сценариях, пароли в хранилище секретов, а запись держит только выбор и его расклад. Справочник и журнал не соперники, а соседи. Wiki остаётся домом для описаний интерфейсов, инструкций по развёртыванию и памяток для дежурных, а журнал ложится рядом и отвечает на единственный вопрос, который справочник никогда не освещает всерьёз: почему система выглядит так, а не иначе. Попытка описать всё и сразу съедает недели и устаревает к следующему релизу; запись в одну страница пишется за полчаса в момент решения, когда расклад ещё свеж в головах.

Внедрение журнала решений в существующем проекте

Начинать разумнее не с ревизии прошлого, а со следующего решения, которое проект примет на этой неделе. Порядок выверен практикой:

  1. Положить шаблон в репозиторий и договориться о каталоге для записей;
  2. Первую запись написать по ближайшему реальному выбору, не восстанавливая по памяти историю прошлых лет;
  3. Прогонять записи через ревью тем же порядком, что и изменения кода;
  4. Связывать отменённые записи ссылками с заменяющими и никогда не удалять старые;
  5. Держать индекс журнала на одной странице и ссылаться на номера в тикетах и обсуждениях;
  6. Раз в квартал просматривать журнал в поисках решений, чей контекст устарел.

Типовые возражения на внедрении известны заранее. "У нас нет на это времени" разбирается арифметикой: запись в одну страница пишется за полчаса, а один повторный спор о трёхлетнем решении стоит команде несколько часов, и такие споры случаются каждый квартал. "Мы и так всё помним" проверяется тестом с тремя людьми, и он почти всегда показывает расхождение уже на втором ответе. "Это бюрократия" опровергается размером: шесть секций и страница текста, меньше, чем средний комментарий в тикете.

Через полгода такой работы журнал сам собой превращается в карту проекта: видно, какие решения держат систему, какие доживают последние месяцы и где прячется самый болезненный технический долг.

Тест ценности простой. Возьмите любое живое решение и спросите у трёх человек команды, почему система устроена именно так. Если три ответа расходятся или ответы ищутся в переписках, записей нет, и каждый уход сотрудника выносит часть архитектуры в никуда. Если же ответ одинаково звучит у всех и подкреплён номером записи, у проекта есть то, что не купишь наймом: коллективная память, которая стареет медленнее людей. Формат не важнее привычки, и лучше убогий текстовый файл, который действительно пишут, чем красивый шаблон, который заполнили дважды и забыли.