Постмортем без блейма: шаблон, который работает
Сервис вышел из строя в три ночи. Хорошие команды разбираются, что случилось, и через пару дней пишут постмортем — документ, который объясняет инцидент и закрывает выводы. Плохие команды ищут виноватого, и постмортем превращается в обвинительный акт «вот разработчик X выкатил баг». Через полгода в команде боятся писать постмортемы, потому что попадание под раздачу гарантировано.
Постмортем без обвинений — это формат, который пришёл из Google SRE и распространился в индустрии. Цель — выяснить причины и предотвратить повторение, а не наказать. Звучит просто, но в реальности команды всё равно скатываются в blame, потому что не знают, как структурировать документ, чтобы он не оказался обвинительным даже непреднамеренно. Разберу шаблон постмортема, что в нём важно, и какие фразы превращают «без обвинений» в обратное.
Чем blameless отличается от обычного
Blameless постмортем не означает, что нельзя называть имена, или нельзя говорить «здесь было сделано не так». Это означает, что фокус — на системе, а не на людях.
Сравним:
Было (с обвинением):
Алексей выкатил миграцию без тестирования на staging, что привело к падению базы. Ему следовало быть внимательнее.
Стало (без обвинений):
Миграция была применена без прогона на staging. У команды не было автоматической проверки, требующей staging-теста перед production-релизом. Добавим эту проверку в pipeline.
В первом варианте — конкретный человек и оценка его действий. Во втором — описание процесса, его пробела, и действие для устранения. Имя Алексея может быть в timeline, но не в выводе «кто виноват».
Это не про мягкость к ошибкам. Это про то, что человеческие ошибки — это симптом, а не причина. Если процесс позволяет одному человеку уронить прод нажатием кнопки, дело не в человеке.
Шаблон постмортема
Структура, которая работает:
# Postmortem: <short incident description>
## Summary
One paragraph: what happened, when, impact, how it was resolved.
## Impact
Quantified user/business impact.
- N users affected.
- Service unavailable for X minutes.
- Revenue impact: estimated $Y.
## Timeline
Detailed chronology with timestamps in UTC.
- 14:32 — Deploy of v2.4.1 starts.
- 14:35 — First error in monitoring.
- 14:38 — On-call paged.
- 14:45 — Investigation starts.
- 15:02 — Rollback initiated.
- 15:08 — Service restored.
## Root cause
Technical explanation of what went wrong, in the system.
Not "who did what".
## Detection
How was the incident detected?
- Detected at 14:35 by error rate alert.
- Or: detected at 14:50 after user complaints in support.
What was the gap between failure and detection?
## Response
What was done during the incident.
- Initial triage steps.
- Decision to rollback (and why, why not).
- Communication during the incident.
## Resolution
What action restored service.
## Action items
Concrete tasks with owners and deadlines.
- [Owner] Add staging gate to deploy pipeline. Due: YYYY-MM-DD.
- [Owner] Improve alert sensitivity for db latency. Due: YYYY-MM-DD.
## Lessons learned
What we know now that we didn't before.
What surprised us.
## Supporting data
Links to dashboards, logs, traces, related tickets.
Десять секций, каждая на конкретный вопрос. Постмортем без timeline или action items — это не постмортем, это сообщение в чате.
Что положить в Summary
Summary читают все. Менеджер, открывший постмортем, должен из неё понять масштаб и суть. Один абзац, без деталей.
Шаблон:
15 марта 2026, с 14:35 до 15:08 UTC, сервис нотификаций был недоступен для всех пользователей из-за ошибки в миграции БД. Затронуто примерно 12000 активных сессий. Сервис восстановлен после rollback миграции и пересборки read-replica.
Конкретные числа, даты, длительность. Без эмоций и без «к сожалению, мы столкнулись с непредвиденной ситуацией».
Timeline: что включать
Timeline — это голые факты. Что происходило в системе и что делала команда. Без интерпретаций.
Хорошие записи:
- 14:32 — Deploy of v2.4.1 starts.
- 14:35 — Error rate jumps from 0.1% to 8%.
- 14:38 — PagerDuty alerts on-call.
- 14:42 — On-call begins investigation.
- 15:02 — Rollback initiated.
Плохие записи:
- 14:32 — Кто-то решил выкатить миграцию (это интерпретация).
- 14:38 — Сработал алерт, к сожалению, никто не отреагировал быстро (оценка).
- 14:50 — Поняли, что всё плохо (эмоция).
Имя on-call можно упомянуть в формате «on-call (name)» или просто «on-call» — для timeline это не важно. Важно, какое действие было сделано в какое время.
Root cause: про систему
Самая частая ошибка — root cause описывается как действие человека.
Было:
Root cause: Разработчик добавил миграцию, которая блокирует таблицу users на 5 минут.
Стало:
Root cause: Миграция, добавленная в этой версии, выполняла ALTER TABLE с блокировкой на чтение. Pipeline не проверяет блокирующие миграции, и они проходят на production без специального плана.
Описание системы и пробела в процессах. Действия конкретного человека — в timeline, как факт. В root cause — что в системе позволило этому действию обрушить сервис.
Удобный приём — «5 whys». Спрашиваем «почему» пять раз подряд:
- Почему сервис упал? Потому что миграция блокировала таблицу.
- Почему миграция блокировала? Она использовала ALTER TABLE без CONCURRENTLY.
- Почему её пропустили в прод? В CI нет проверки на блокирующие миграции.
- Почему нет проверки? Команда раньше не сталкивалась с проблемой.
- Почему не сталкивалась? База была меньше, блокировки незаметны.
На пятом «почему» обычно становится понятно, какой системный пробел нужно закрыть.
Action items: конкретные задачи
«Action items: будем внимательнее в будущем» — это не action items.
Хорошие action items:
- Добавить linter в CI, который ловит ALTER TABLE без CONCURRENTLY. Owner: @platform-team. Due: 2026-04-01.
- Создать runbook «миграции на больших таблицах». Owner: @data-platform. Due: 2026-04-15.
- Снизить порог алерта error_rate с 5% до 2% для notification-service. Owner: @sre. Due: 2026-03-25.
У каждого — конкретное действие, владелец, дедлайн. Без owner — задача не сделается. Без deadline — будет висеть полгода.
Action items должны быть реалистичными по объёму. «Переписать всю систему миграций» — это не action item, это эпик. В постмортеме — что можно сделать в обозримый срок.
Lessons learned: то, что было неожиданно
Эта секция часто заполняется как «было плохо, в следующий раз сделаем лучше». Это пустой текст.
Что должно быть:
- Знания, которых не было до инцидента: «Не знали, что ALTER TABLE без CONCURRENTLY блокирует чтение, не только запись».
- Ошибочные предположения: «Считали, что 5 минут блокировки — приемлемо, по факту это 5 минут полной недоступности».
- Обратная сторона: «Mitigation сработал быстрее, чем ожидали — rollback занял 6 минут вместо предполагаемых 15».
Эта секция — о росте знаний команды, не о том, что «надо быть внимательнее».
Тон формулировок
Маленькие лингвистические детали меняют постмортем из blameless в blame:
Заменяй:
- «Алексей не проверил миграцию на staging» → «Миграция не была проверена на staging».
- «Кто-то поменял конфиг» → «Конфиг был изменён в коммите abc123».
- «Команда не отреагировала вовремя» → «Реакция on-call заняла 8 минут после алерта».
- «Дежурный должен был это заметить» → «Алерт сработал на metric X, но не отразился на dashboard, к которому привязан on-call».
Пассивный залог в постмортеме — это нормально, потому что фокус на действии, не на действующем лице. Это та редкая ситуация, когда стилистика «активного залога» уступает blameless-цели.
Кто пишет
Лучше всего — тот, кто был в инциденте. Обычно on-call, который дежурил. Но это не должен быть тот, кто «выкатил неудачный коммит» — он будет либо защищаться, либо чрезмерно самобичеваться.
Идеальная схема: on-call пишет черновик в течение 24-48 часов после инцидента (пока память свежая), команда (включая того, кто причастен к ошибке) проводит ревью и дополняет, инженер-менеджер или SRE финализируют.
Время сильно влияет: постмортем, написанный через две недели, теряет детали и точность. Через пару дней — самое то.
Постмортем-ревью
Документ написан. Дальше — ревью командой. Это не для красоты, а для:
- Поделиться знанием с теми, кто не был в инциденте.
- Уточнить детали timeline — кто-то мог помнить лучше.
- Договориться об action items: они реальные, или это wishlist?
- Проверить, не скатился ли документ в blame.
Ревью обычно идёт в формате 30-минутной встречи или асинхронно через комментарии в документе. Главный вопрос на ревью: «если мы запустим этот процесс снова, могло ли это случиться опять?». Если ответ «да» — action items недостаточны.
Где живут постмортемы
В репозитории документации команды или в отдельной системе. Главное — доступно для всей команды и инженерной организации.
postmortems/
├── 2026-03-15-notifications-down.md
├── 2026-04-02-deploy-pipeline-stuck.md
└── ...
Имя файла — дата и краткое описание. Через год команда листает «что у нас было в марте» и находит. Без даты — невозможно искать.
Confluence-страницы как место для постмортемов работают хуже: устаревают, теряются, не индексируются. Markdown в репозитории живёт долго.
Чек-лист хорошего постмортема
- Summary в один абзац с ключевыми числами.
- Quantified impact: пользователи, время, бизнес.
- Timeline в UTC, голые факты, без интерпретаций.
- Root cause описывает системный пробел, не действие человека.
- Detection и Response — как быстро сработала реакция.
- Action items с owner и deadline.
- Lessons learned — реальные знания, не «будем внимательнее».
- Тон формулировок безличный или о системе, не о людях.
- Документ написан в течение 48 часов после инцидента.
- Прошёл ревью командой.
Постмортем без обвинений — это инструмент команды, а не отчёт менеджменту. Если в команде он становится привычкой, через год накапливается база знаний, в которой видны паттерны: «мы три раза падали из-за миграций, нужен системный фикс». Если постмортемы превращаются в blame, через год их перестают писать совсем — потому что попадание под раздачу не стоит того.