Проблема разбора редко в отсутствии длинного документа. Чаще команда чинит видимый симптом, а затем одним абзацем называет это причиной, решением и профилактикой сразу. Цена такого текста — потерянная граница ответственности. В следующем сбое непонятно, что повторить: проверить вход, отключить тот же путь, сверить контракт или искать другую ветку. Временный обход живёт как окончательный вывод, а тест появляется только как пожелание.
Для автора конца 2020 года здесь полезна не сложная платформа, а простая модель состояния. Наблюдение хранит то, что произошло в учебном сценарии. Гипотеза объясняет одно наблюдение, но остаётся изменяемой. Действие выбирает ограниченный ход. Проверка измеряет эффект действия. Профилактика меняет будущий путь и остаётся planned, пока её не проверили отдельно. Весь пример ниже синтетический и выполняется только в памяти; он не изображает трафик, журнал, людей или production как факт.
Один абзац не должен играть пять ролей
Возьмём фразу: «мы вернули старую настройку, потому что mapper отбросил currency, и добавили тест». В ней можно найти смысл, но нельзя восстановить ход работы. Неясно, было ли отсутствие поля наблюдением или догадкой. Неясно, какая настройка менялась, как её проверили и был ли тест действительно добавлен. После нескольких недель такая фраза превращается в легенду: звучит уверенно, но не даёт безопасного следующего действия. Модель с разными полями делает текст чуть длиннее, зато резко уменьшает число неявных предположений.
В fixture E2 хранит наблюдение об отсутствии currency. H1 говорит только о возможной связи с mapper и ссылается на E2. A1 возвращает в учебной ветке известный вариант. V1 проверяет именно A1, а не вообще «здоровье системы». P1 и P2 остаются planned: это будущие изменения теста и описания контракта. Такой набор не пытается вычислить все корни проблемы. Он создаёт достаточную трассу от наблюдения к следующей проверяемой работе.
| Состояние | Минимальное содержимое | Допустимая связь | Ошибка при смешении |
|---|---|---|---|
| Observation | граница, значение, evidence | может стать основанием H1 | значение выдают за причину |
| Hypothesis | предположение и ссылка на observation | ведёт к одному или нескольким действиям | гипотеза становится обвинением или окончательным фактом |
| Action | ограниченное изменение и условие возврата | следует за hypothesis | обход называют устранением причины |
| Verification | сценарий и ожидаемый результат | проверяет конкретный action | общий успех не связан с изменением |
| Prevention | изменение и собственный check | остаётся planned до отдельной проверки | задача объявляется сделанной в момент идеи |
Этот контракт удобен тем, что его можно проверять механически. Время событий должно возрастать. H1 не может ссылаться на будущую строку. V1 не должен возникать до A1. Decision D1 обязан назвать trigger и expected check. Prevention не должна менять состояние на completed только потому, что её записали в отчёт. Такие правила не доказывают техническую причину автоматически. Они защищают форму разбора, чтобы у людей осталось место для технического исследования, а не для восстановления истории по памяти.
Почему observation и hypothesis разделяют даже в маленьком модуле
Наблюдение переживает неудачную гипотезу; гипотеза — нет. В этом разница их стоимости. Если написать «mapper не передал currency» как observation, а позже выяснится, что поле отсутствовало ещё до mapper, придётся переписать прошлое. Если же observation говорит «после преобразования поле отсутствует», история остаётся верной. Меняется только H1 и следующая проверка. Это важно не только для аварий. Так же работают разборы странного кеша, ошибки миграции, зависимости от переменной окружения и любого условия, которое появляется на границе модулей.
Проверяемая гипотеза обязана сузить пространство. H1 не говорит «что-то сломалось в заказе». Она говорит, что конкретный новый путь mapper мог не перенести обязательное поле. У неё есть E2, с которым можно спорить, и действие A1, которое можно отменить. Если гипотеза не позволяет придумать маленький эксперимент, она слишком общая. Нужно разделить её: одна строка о входе, другая о преобразовании, третья о контракте. Тогда отрицательный результат не разочаровывает, а сокращает список оставшихся причин.
function assertIncidentLinks(timeline, decisions, prevention) {
// hypothesis ссылается на более раннее observation;
// action ссылается на hypothesis;
// verification проверяет конкретный action.
if (hypothesis.basedOn !== 'E2') throw new Error('missing evidence');
if (verification.checksAction !== 'A1') throw new Error('missing check');
if (prevention.state !== 'planned') throw new Error('premature completion');
}
// Настоящий код модуля делает эти проверки для всех записей fixture.
В исходном модуле проверка шире короткого фрагмента: она проходит по всем events, решениям и профилактическим пунктам. Но даже такой псевдокод показывает смысл. Контракт не проверяет «идеальную архитектуру». Он проверяет, что будущее не перепутано с прошлым и что готовность не подменена намерением. Когда кто-то меняет fixture, ошибка о missing evidence или premature completion полезнее красивой диаграммы: она показывает, какая связь исчезла.
Решение — это ставка с ожидаемой проверкой
Техническое действие во время разбора часто временное. Иногда его выбирают потому, что оно обратимо; иногда потому, что есть понятный прошлый вариант; иногда потому, что позволяет сохранить данные для следующего исследования. В любом случае оно должно быть описано как ставка: на какой hypothesis реагируем, какую границу меняем, что ожидаем увидеть и в каком случае откатываемся. Эта запись не тормозит восстановление. Она освобождает от спорного воспоминания через час, когда уже сделано несколько правок.
D1 в учебном случае говорит: не расширять retry и не увеличивать timeout, оставить предыдущий mapper, затем ждать V1. Это не объявление, что retry плохой. Наоборот, оно оставляет дверь для другой ветки, если V1 не подтвердит действие. У retry должен быть свой trigger, свой риск дублирования и свой check. У timeout — своя причина медленного ответа. Когда все меры складывают в один ответ, команда одновременно меняет несколько переменных и теряет возможность понять, какая из них повлияла на результат.
Профилактика не равна строке в конце отчёта
После временного действия возникает соблазн закрыть разбор фразой «добавить тест». Это слишком мало. Нужно назвать изменение, границу и способ убедиться, что изменение существует. P1 добавляет contract fixture, который отклоняет mapper без currency. P2 закрепляет обязательное поле рядом с границей pricing-adapter и требует сверки на ревью с маленьким входным примером. Обе строки остаются planned. Это честнее, чем создаёт видимость завершённой работы.
const prevention = [
{
id: 'P1',
change: 'fixture отклоняет mapper без currency',
check: 'runIncidentFixture() возвращает true',
state: 'planned',
},
];
// Planned не означает «выполнено».
// У действия есть отдельная будущая проверка и место в очереди команды.
Статус planned не обесценивает профилактику. Он показывает разницу между знанием и изменением. В разборе уже есть вывод: проверка отсутствующего поля нужна. Но ещё нет доказательства, что она попала в репозиторий, выполняется в нужном месте и ловит нужную регрессию. Когда такую разницу не фиксируют, follow-up становится эмоциональным обещанием. Когда фиксируют, его можно положить в обычную очередь задач и вернуться с отдельным результатом проверки.
Что остаётся технической работой, а не языком отчёта
Слова observation, hypothesis и prevention не должны заменить анализ кода. После E2 всё равно нужно открыть преобразование, проследить поле во входном объекте, проверить версию контракта и выбрать точку теста. Запись лишь задаёт порядок, в котором эта работа не уничтожит сама себя. Если обнаружится несколько contributing conditions, можно добавить H2 и A2, но у каждой пары должны остаться свои ссылки. Один большой «root cause» часто скрывает разные условия: пропущенное поле, отсутствие проверки и слишком широкий обход.
Этот подход также не требует копировать процессы большой компании. Не нужно придумывать командный центр, десятки ролей или общую платформу, чтобы перестать смешивать факты с выводами. Для малого проекта достаточно отдельного документа или задачи, небольшой fixture и понятного владельца follow-up в привычной очереди. Важнее другое: текст не должен выдавать остановленный симптом за устранённую причину, а идея теста — за проведённую проверку.
Маршрут механического ревью записи
- Разделить черновик на observation, hypothesis, action, verification и prevention. Если одна строка попала в две группы, переписать её на две короткие.
- Проверить порядок: каждая hypothesis ссылается на более раннее observation, а каждое действие — на конкретную hypothesis.
- Проверить decision record: у решения есть trigger, ограниченное действие и expected check, а не только итоговая формулировка.
- Проверить verification: она должна измерять именно действие, а не произвольный положительный сигнал рядом.
- Проверить prevention: у неё есть изменение и будущий check, а статус planned не перепутан с выполнением.
- Отдельно прочитать, какие реальные технические границы ещё не проверены. Не добавлять имитированные журналы, клиентов или поведение среды вместо этого исследования.
- Сохранить fixture рядом с текстом и запускать её после изменения записи, чтобы связи не разошлись незаметно.
Граница модели и историческая рамка
Модель не заменяет диагностику, резервирование, мониторинг или безопасную процедуру изменения. Она не делает из учебной ветки описание production-инцидента и не говорит, что один mapper был причиной любого отказа. В материале не запускались SDK, клиент, HTTP, база, очередь, dashboard или deployment. Синтетический вход нужен только для того, чтобы независимый читатель увидел связь E2 → H1 → A1 → V1 и мог проверить её локально.
Официальные материалы ниже используют более широкий язык incident management и postmortem. Здесь от них взят ограниченный, доступный в 2020 году урок: состояние разбора должно быть живым, причины — отделены от обвинений, а follow-up — проверяемым. Это соответствует растущей инженерной практике автора, но не приписывает ему опыт зрелой платформы надёжности или универсальный процесс для всех команд.
Проверяемые источники
- Google SRE Book: Managing Incidents — официальная глава 2017 года о фиксации живого состояния инцидента, разделении работ и восстановлении; это источник принципов, а не описание данного учебного случая
- Google SRE Book: Postmortem Culture — официальное описание postmortem как записи влияния, действий, причин и follow-up; особенно полезно различение системных причин и персонального обвинения
- Google SRE Book: Effective Troubleshooting — официальный материал о проверяемых гипотезах, наблюдениях и ценности отрицательного результата при поиске причины