Files
progcode/editorial/agent-rewrites/119.json
T
huncode 2d914b543f
Build and deploy / deploy (push) Failing after 15s
Publish rewritten technical article archive
2026-08-02 22:19:34 +03:00

8 lines
19 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"index": 119,
"slug": "editorial-2024-09-mechanism-adr-decisions",
"title": "ADR без иллюзии выбора: как записать решение, его цену и путь назад",
"excerpt": "Архитектурное решение теряет смысл, если в записи виден только победивший вариант. Разбираем, как сравнить альтернативы по одной схеме, проверить отрицательный путь и оставить условие для пересмотра.",
"contentHtml": "<p>В review появляется знакомый симптом: команда обсуждает не условие задачи, а вкус. Один вариант называют простым, другой — надёжным, третий — слишком дорогим. В ADR уже записан победитель, но альтернативы сведены к двум словам. Через месяц авторы помнят контекст, а остальные видят только решение. Через год никто не знает, какую проблему оно закрывало и что делать, если исходное условие изменилось.</p>\n<p>Цена ошибки растёт вместе с границей решения. Неудачный выбор может закрепить общий протокол, миграцию, формат данных или операционную обязанность. Тогда быстрый первый merge скрывает дорогой rollback. Ошибка не в том, что команда выбрала неидеальный вариант. Ошибка в том, что запись не показывает принятый компромисс и не даёт проверить, когда его пора пересмотреть.</p>\n<p><strong>Тезис:</strong> хороший ADR не доказывает, что выбранный вариант лучший вообще. Он связывает наблюдаемую проблему с конкретным ограничением, одинаково описывает альтернативы, называет цену выбора и задаёт сигнал для возврата к решению. Числа могут помочь в учебной модели, но не заменяют факты и не превращают мнение в production-метрику.</p>\n<h2>Механизм: от симптома к решению</h2>\n<p>ADR полезен как короткая цепочка причин. Сначала автор отделяет факт от объяснения. Факт можно наблюдать: caller должен получить статус, пока фоновая операция продолжается; данные нельзя отдавать старше заданной границы; изменение должно откатываться без записи нового формата. Гипотеза объясняет, почему текущий путь не подходит. Решение отвечает на ограничение, а не на абстрактную цель вроде «улучшить архитектуру».</p>\n<p>У каждой альтернативы должна быть одна и та же карточка. Запишите, какой constraint она закрывает, где находится её граница, кто владеет дополнительной работой, как выглядит возврат и какое evidence уже есть. Отсутствующее evidence тоже является результатом сравнения. Оно ограничивает уверенность, но не доказывает безопасность или опасность варианта.</p>\n<p>Статус помогает не смешивать обсуждение и историю. <em>Proposed</em> означает, что запись готова к проверке. <em>Accepted</em> фиксирует принятое решение. <em>Superseded</em> означает, что новый ADR заменил старый и объяснил причину. Статус не запускает миграцию, не назначает approval и не проверяет rollback автоматически. Эти действия должны иметь отдельного владельца и отдельный сигнал.</p>\n<pre><code>symptom = caller не получает понятный status\nconstraint = acknowledgement не должен зависеть от business completion\nalternatives = direct response | bounded async state | shared workflow\ndecision = bounded async state у границы сервиса\nprice = expiry, owner состояния, cleanup и отдельная проверка retry\nreassess = меняется контракт caller или срок хранения состояния</code></pre>\n<p>Этот фрагмент — учебный пример формы. Он не описывает реальный сервис, трафик, SLO или production-результат. Его задача — показать, как решение связывает симптом, условие, цену и отрицательный путь. В настоящем ADR вместо учебных утверждений нужны ссылки на контракт, issue, тест, threat model или другой разрешённый источник evidence.</p>\n<h2>Как сравнить альтернативы честно</h2>\n<p>Сначала выровняйте уровень вариантов. Нельзя сравнивать «локальный cache» с «переделать платформу»: это разные масштабы и владельцы. Сформулируйте варианты на уровне решения, а затем укажите реализацию как следствие. Для asynchronous boundary это могут быть прямой ответ после завершения работы, bounded state с выдачей статуса и общий workflow с отдельным хранением состояния.</p>\n<p>Constraint fit отвечает на вопрос «закрывает ли вариант обязательное условие». Reversibility описывает не наличие кнопки undo, а область возврата, порядок действий и владельца. Evidence fit показывает, какие факты поддерживают выбор и какой вопрос остался открытым. Operating cost называет долг: expiry, retry, cleanup, миграцию, поддержку контракта или ручной review. Reassessment показывает, что должно измениться, чтобы открыть новый ADR.</p>\n<table><thead><tr><th>Критерий</th><th>Вопрос к каждому варианту</th><th>Проверяемый артефакт</th><th>Чего нельзя утверждать</th></tr></thead><tbody><tr><td>Constraint fit</td><td>Какое объявленное условие выполняется?</td><td>Контракт, problem statement или acceptance question</td><td>Что вариант оптимален для всех целей</td></tr><tr><td>Reversibility</td><td>Какой scope возврата, кто его выполняет и что останавливает change?</td><td>План rollback и граница затронутого состояния</td><td>Что rollback уже проверен в production</td></tr><tr><td>Evidence fit</td><td>Какой факт поддерживает выбор и чего пока не хватает?</td><td>Ссылка на источник, controlled test или явное unknown</td><td>Что отсутствие данных равно безопасному результату</td></tr><tr><td>Operating cost</td><td>Кто поддерживает status, expiry, retry, cleanup или migration?</td><td>Owner и consequence в ADR</td><td>Что стоимость измерена в часах или деньгах</td></tr><tr><td>Reassessment</td><td>Какой сигнал отменяет исходное предположение?</td><td>Review condition, metric question или contract link</td><td>Что дата сама запустит пересмотр</td></tr></tbody></table>\n<p>Таблица не требует единой оценки. Она делает пропуски видимыми. Если у одного варианта есть контракт, а у другого только слово «сложно», сравнение ещё не началось. Если команда всё же применяет score, заранее закрепите шкалу, веса и смысл баллов. Рядом напишите, какие данные модель не учитывает. Итоговый балл может быть tie-breaker для обсуждения, но не доказательством корректности.</p>\n<figure><img src=\"/assets/editorial/2024/adr-decisions-2024-alternatives-matrix.svg\" alt=\"Синтетическая матрица сравнения альтернатив ADR по ограничениям, обратимости, evidence и операционной цене\"><figcaption>Иллюстрация показывает синтетическую матрицу. Значения помогают увидеть форму сравнения и не являются метриками реальной команды или production-системы.</figcaption></figure>\n<h2>Пример записи с отрицательным путём</h2>\n<p>Предположим, synchronous caller ждёт результат долгой операции. Прямой ответ сохраняет простую модель, но не выдерживает границу времени. Shared workflow даёт общий status, но добавляет cross-service owner и отдельный контракт. Bounded state у границы сервиса отделяет acknowledgement от business completion. Это может закрыть исходное условие, если срок хранения, повтор запроса и очистка состояния определены явно.</p>\n<pre><code>## Decision\nВыбираем bounded state у границы сервиса.\n\n## Consequences\nПоложительные: caller получает отдельный status.\nЦена: owner хранит expiry и cleanup; retry должен быть идемпотентным.\n\n## Не делаем\nНе вводим shared workflow и не считаем локальное состояние\nуниверсальным механизмом координации.\n\n## Reassessment\nОткрываем новый ADR, если caller требует общего status между\nсервисами или срок хранения превышает допустимую границу.</code></pre>\n<p>Отрицательный путь защищает запись от незаметного расширения. Без него локальное решение постепенно начинает обслуживать новые callers, а временное поле превращается в общий протокол. Если новое требование действительно появилось, это не повод молча дописывать старый ADR. Нужен successor с новым контекстом, альтернативами и ценой. Старый record остаётся историей прежнего компромисса.</p>\n<h2>Симптом → причина → проверка → действие</h2>\n<table><thead><tr><th>Симптом</th><th>Причина</th><th>Проверка</th><th>Действие</th></tr></thead><tbody><tr><td>Выбранный вариант подробно описан, остальные названы «сложными»</td><td>Автор сравнил не варианты, а привлекательность собственного решения</td><td>Заполнить одну карточку criteria для каждой альтернативы</td><td>Переписать ADR и назвать explicit downside победителя</td></tr><tr><td>После merge спорят, что на самом деле означал ADR</td><td>В записи смешаны факт, гипотеза и implementation detail</td><td>Пометить источник каждого важного утверждения</td><td>Вынести неизвестное в evidence gap и добавить owner проверки</td></tr><tr><td>Rollback существует только как фраза</td><td>Не определены scope, порядок и stop condition</td><td>Провести dry run на учебной копии или описать точную границу</td><td>Связать ADR с отдельным rollback-планом и не объявлять его проверенным без evidence</td></tr><tr><td>Локальный механизм используют новые callers</td><td>Отрицательный путь и граница применимости не записаны</td><td>Проверить список потребителей и контракт состояния</td><td>Остановить расширение, создать successor ADR при новом требовании</td></tr><tr><td>Дата review прошла, но никто не вернулся к решению</td><td>Дата ошибочно принята за автоматический процесс</td><td>Найти владельца сигнала и фактическое событие пересмотра</td><td>Назначить действие отдельно или заменить дату проверяемым trigger</td></tr></tbody></table>\n<h2>Порядок работы</h2>\n<ol><li><strong>Сузьте вопрос.</strong> Опишите одну границу: какой caller, какое состояние и какое обязательное условие создают проблему.</li><li><strong>Зафиксируйте наблюдаемый симптом и цену.</strong> Отделите факт от гипотезы. Назовите, что станет дороже или опаснее при неверном выборе.</li><li><strong>Соберите три разумные альтернативы.</strong> Приведите их к одному уровню и не добавляйте вариант, который не может закрыть constraint.</li><li><strong>Заполните одинаковые поля.</strong> Укажите constraint fit, reversibility, evidence gap, operating cost, owner и отрицательный путь.</li><li><strong>Сформулируйте decision как компромисс.</strong> Запишите, что реализуем и чего намеренно не делаем.</li><li><strong>Назначьте проверяемый сигнал.</strong> Это может быть изменение контракта, новый потребитель, исчерпание срока хранения или конкретный вопрос к метрике.</li><li><strong>Проверьте запись до implementation.</strong> Reviewer должен суметь назвать выбранный вариант, его цену и условие пересмотра, не открывая код.</li><li><strong>Свяжите запись с реализацией отдельно.</strong> ADR не заменяет тест, threat model, migration plan, benchmark, runbook или incident review.</li></ol>\n<h2>Ограничения и критерий готовности</h2>\n<p>ADR не делает решение истинным и не заменяет исследование. Он не измеряет latency, надёжность, стоимость или безопасность, если рядом нет соответствующего evidence. Он не гарантирует, что команда найдёт все альтернативы. Формат может различаться: важнее сохранить контекст, выбор, статус, последствия, границы и путь пересмотра. Для legal, security, privacy и data boundary нужны отдельные проверки с отдельными владельцами.</p>\n<p>Не добавляйте в учебный пример вымышленные traffic, error rate, savings или outcome. Если число нужно для объяснения score, пометьте его как синтетическое и не переносите вывод за пределы модели. Если production-данных нет, честная формулировка — «данных пока недостаточно», а не «вариант доказанно безопасен».</p>\n<p>Запись готова, когда независимый читатель может ответить на пять вопросов: какой симптом наблюдали; какое constraint обязателен; почему сравнивали именно эти варианты; какую цену принимает выбранный путь; какой сигнал заставит открыть новое решение. Проверка проста: уберите из текста заголовок <em>Decision</em> и попросите коллегу восстановить его из context, alternatives и consequences. Если он не может назвать отрицательный путь или owner, ADR ещё не готов.</p>\n<h2>Проверяемые источники</h2>\n<ul><li><a href=\"https://adr.github.io/\" target=\"_blank\" rel=\"noopener noreferrer\">Architectural Decision Records</a> — официальный сайт сообщества ADR с материалами о формате и практике.</li><li><a href=\"https://github.com/adr/madr\" target=\"_blank\" rel=\"noopener noreferrer\">MADR: Markdown Architectural Decision Records</a> — репозиторий шаблонов и документации Markdown-формата.</li><li><a href=\"https://www.gov.uk/government/publications/architectural-decision-record-framework\" target=\"_blank\" rel=\"noopener noreferrer\">Architectural Decision Record Framework</a> — официальный framework Government Digital Service и Department for Science, Innovation and Technology.</li></ul>"
}