{ "index": 150, "slug": "editorial-2023-11-practice-postmortem", "title": "Postmortem, который помогает исправить систему", "excerpt": "Как отделить наблюдаемые факты от поздних объяснений, связать решение с доступной информацией и превратить профилактику в проверяемое действие.", "contentHtml": "

После сбоя команда обычно помнит две вещи: какой сигнал сработал и кто последним менял систему. На встрече эти детали быстро превращаются в объяснение: «ошибка произошла из-за этого изменения». Такой вывод может быть неверным. Он смешивает факт, решение и гипотезу о причине.

\n

Цена ошибки высока. Команда тратит время на защиту вокруг случайного признака, а настоящий механизм остаётся без проверки. Следующий дежурный получает документ с обвинением и общим советом «быть внимательнее». Похожий сбой повторяется, но его уже труднее разобрать: нужные логи истекли, контекст решения забыт, а исправление объявили готовым без измерения.

\n

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

\n

Три разных типа записи

\n

Факт отвечает на вопрос «что было зафиксировано и где это видно?». Это узкое утверждение с временем и ссылкой на разрешённый артефакт: лог, trace, метрику, версию конфигурации или запись мониторинга. Фраза «в 10:03 запросы к маршруту получили 502» может быть фактом, если рядом есть запрос к источнику и задано окно времени.

\n

Решение отвечает на вопрос «что команда сделала, имея такую информацию?». В него входят время, действие и список фактов, доступных до действия. Поздний trace или результат расследования нельзя добавлять в этот список задним числом. Он помогает понять выбор, но не доказывает, что выбор был правильным или ошибочным.

\n

Профилактическая проверка отвечает на вопрос «что мы проверим, чтобы уменьшить риск повторения?». В ней нужны гипотеза, минимальный метод, бинарный критерий и обратимый путь. До прогона это намерение проверить, а не доказательство того, что новый alert, лимит или тест уже защитил пользователей.

\n
Не смешивайте записи в одной строке
ТипВопросМинимальные поляНельзя выводить
ФактЧто зафиксировано?время, наблюдение, ссылка на источниквиновника и root cause
РешениеЧто выбрали тогда?время, действие, доступные fact IDоценку задним числом
ПроверкаЧто проверим дальше?гипотеза, метод, критерий, rollbackреальный эффект до измерения
ДействиеКто доведёт работу?владелец роли, срок, ссылка на проверкуобещание устранить все риски
\n

Механизм на маленьком примере

\n

Представим учебный инцидент в HTTP-сервисе. После релиза доля ответов 502 выросла. Дежурный откатил конфигурацию таймаута. Через несколько минут доля ошибок снизилась. Этого недостаточно, чтобы написать «новый таймаут был причиной». За это время могли исчезнуть входной всплеск, зависший upstream или другая ошибка маршрутизации.

\n

Сначала запишите наблюдения:

\n
const facts = [\n  { id: 'f-1', at: '10:03', text: 'gateway reported 502 for /checkout', source: 'metric:gateway_5xx' },\n  { id: 'f-2', at: '10:04', text: 'timeout config was version 17', source: 'config:checkout@17' },\n  { id: 'f-3', at: '10:05', text: 'on-call restored version 16', source: 'change:rollback-482' },\n];\n\nconst decision = {\n  at: '10:05',\n  action: 'restore checkout config to version 16',\n  availableFactIds: ['f-1', 'f-2'],\n};\n\nconst check = {\n  hypothesis: 'the timeout change contributes to the 502 path',\n  method: 'replay the same request class with versions 16 and 17',\n  criterion: 'both outcomes and upstream status are captured',\n  rollback: 'keep version 16 and stop the replay if error rate rises',\n};
\n

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

\n

Нужна и отрицательная ветка. Если в карточке факта появилось поле rootCause, система или ревью должны остановить запись. Если решение ссылается на факт, который возник позже, его нельзя считать контекстом решения. Если проверка говорит «сбой больше не повторится», но не называет вход, окно и измерение, это обещание, а не критерий.

\n

Симптом → причина → проверка → действие

\n
Маршрут разбора
СимптомВероятная причина смешенияПроверкаДействие
В черновике есть имя инженера, но нет источниковоценка человека заменяет анализ условийнайти timestamp и evidence для каждой фразыубрать имя из объяснения, добавить владельца следующего действия
«Релиз вызвал ошибку» написано как фактгипотеза попала в timelineсравнить время релиза, симптома и альтернативные измененияпометить связь как непроверенную и сформулировать эксперимент
Action item звучит как «добавить мониторинг»нет сценария и порога срабатыванияназвать вход, сигнал, окно и ожидаемое значениесделать критерий бинарным и указать обратное действие
После отката написано «проблема решена»снижение симптома приняли за доказательство причинысопоставить ошибку с upstream, версиями и временемописать откат как mitigation, а причину оставить открытой
Документ нельзя проверить через неделюв нём остались воспоминания без артефактовпроверить каждое утверждение по ссылке и сроку хранениясохранить минимальный разрешённый evidence или отметить пробел
\n

Иллюстрация временной границы

\n
\"Учебная
Учебная схема: факты стоят до решения, а профилактическая проверка — после него. Она не представляет настоящий инцидент и не показывает production-метрики.
\n

Временная граница нужна не для бюрократии. Она защищает от hindsight bias: после сбоя команда видит больше, чем видела в момент действия. Поэтому в записи решения храните не весь итоговый материал, а именно набор сведений, который мог повлиять на выбор. Если действие необратимо, отдельно запишите владельца точки возврата и сигнал остановки.

\n

Порядок работы

\n
  1. Опишите симптом. Укажите затронутый путь, окно времени, наблюдаемый сигнал и цену ошибки: недоступность операции, потерю данных, ручное восстановление или задержку.
  2. Зафиксируйте факты. Для каждой строки назовите источник, время и точную формулировку. Не добавляйте в факт причину, виновника или эффект, которого источник не измеряет.
  3. Восстановите контекст решения. Запишите действие, доступные fact ID, обратимость и сигнал, по которому команда решала продолжать или остановиться.
  4. Разделите mitigation и cause. Откат, переключение трафика или отключение функции может убрать симптом. Это ещё не доказательство механизма сбоя.
  5. Сформулируйте одну гипотезу. Укажите конкретный вход, способ проверки и альтернативу. Не начинайте с общего «повысить надёжность».
  6. Задайте критерий. Критерий должен приводить к PASS или FAIL и ссылаться на измеримый артефакт. Добавьте rollback и условие остановки.
  7. Проверьте документ. Уберите фразы, которые шире источника. Отдельно перечислите открытые вопросы и назначьте владельца только для следующей проверяемой работы.
\n

Ограничения

\n

Такая схема не заменяет расследование распределённой системы. Один trace может не показать потерю сообщения. Откат может убрать симптом, но оставить повреждённые данные. Метрика может считать только успешные запросы и скрывать ошибки до входа в сервис. Поэтому границы источников и неполные данные нужно писать прямо.

\n

Blameless не означает «никто ни за что не отвечает». Документ должен содержать владельца действия, срок и критерий завершения. Он также должен фиксировать небезопасное изменение, нарушенный контроль или отсутствие доступа к сигналу, если это подтверждено. Не следует приписывать человеку мотив или использовать его имя как техническую причину.

\n

Учебный код выше не подключается к сети, CI, логам, alert-системе или production runtime. Его нельзя выдавать за результат прогона. В реальной системе доступ к incident data, приватность, retention и право публикации требуют отдельной проверки. Если источник недоступен, честная запись — «не проверено», а не правдоподобная реконструкция.

\n

Проверяемый критерий готовности

\n

Postmortem готов к разбору, когда другой инженер может пройти его без устного пересказа:

\n\n

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

\n

Проверяемые источники

\n" }