DarkRiDDeR13 мин

Долг — не список неприятностей: как провести maintenance review

НадёжностьПроцессы

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

Maintenance review нужен не для красивой ретроспективы. Он нужен, когда один симптом возвращается, а изменение каждый раз обсуждают с нуля. Тогда долг — это не неприятность и не обвинение автора прежнего решения. Это повторяемый риск с владельцем, явной границей доказательств и одним следующим экспериментом. Если этих частей нет, пункт backlog нельзя честно сравнить с другим пунктом.

Дальше использую несколько рабочих терминов. Maintenance review — короткая проверка списка задач сопровождения; backlog item — одна такая задача; evidence boundary — запись о том, что подтверждено и что остаётся неизвестным; owner role — роль, принимающая следующий вопрос; experiment — ограниченная проверка, а не запуск изменения. Английские названия оставлены только для устойчивых терминов и кода.

Симптом сначала, название долга потом

Начинать с названия вроде «улучшить поддержку» опасно: в нём нет наблюдаемого факта. Гораздо полезнее написать: «на каждом review приходится заново объяснять, где заканчивается диагностический шаг». Это уже симптом. Он не доказывает частоту в реальной системе и не сообщает стоимость в деньгах, зато даёт предмет проверки: есть ли в runbook одна граница, по которой другой инженер может остановиться.

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

Минимальная карточка maintenance item
ПолеЧто в нём должно бытьЧего в нём нет
Повторяемый symptomодна наблюдаемая ситуация: ручное объяснение, повторный вопрос, повторный stopярлыка «сложно поддерживать» без примера
Riskкакая граница может быть пройдена ошибочно и чем это опаснопрогноза инцидента или обещания потерь
Cost classвидимые усилия: interrupt, задержка review, повторная проверкавыдуманной экономии или счёта конкретной команды
Ownerроль, которая принимает следующий вопрос или эскалациюимени человека без его согласия и полномочий
Evidence boundaryчто подтверждено и чего не читалислова «все пользователи», если scope не проверен
One next experimentодин артефакт и критерий его reviewскрытого плана большого рефакторинга

Маршрут review: symptom → причина → проверка → действие

  1. Зафиксируйте один симптом. Он должен помещаться в предложение и иметь границу: route, runbook step, contract или review question.
  2. Назовите риск. Не «система хрупкая», а «изменение может пересечь compatibility boundary без принимающего owner».
  3. Опишите цену классом. Достаточно «повторный interrupt» или «ещё один review pass». Деньги, часы и проценты пишут только при воспроизводимой методике и разрешённом источнике.
  4. Поставьте owner role. Владелец не обязан сразу исправить всё; он обязан принять следующий узкий вопрос или явно передать его.
  5. Отделите evidence от unknown. Список известного не становится полным только потому, что он красиво оформлен.
  6. Сформулируйте один experiment. Его результатом должен быть новый проверяемый артефакт, а не deploy, удаление или «разобраться».
Цикл maintenance review: наблюдаемый symptom переходит в ограниченную карточку, затем в один experiment, recheck и решение continue, stop или revise. Внешний контур помечен как human review; схема не выполняет change.
Цикл полезен тем, что останавливает рост scope. Повторяемость делает item видимым, но право на реальное изменение остаётся за отдельным human review.

Карточка должна быть контрактом review, а не мини-отчётом

У карточки есть граница ответственности. Автор карточки фиксирует факт, который действительно видел или получил из разрешённого доказательства. Owner role отвечает за дальнейший вопрос. Reviewer проверяет, что experiment не выдаёт учебную модель за production verdict. Никто из них не получает право назвать feature, consumer или incident существующим только потому, что такой пример хорошо объясняет метод.

Это особенно важно в годовом обзоре. Память легко склеивает несколько похожих эпизодов в «весь год было тяжело». Для планирования полезнее три отдельные строки с разными границами: повторяемый runbook gap, risk без owner и cleanup без recheck. Они могут иметь похожий приоритет, но требуют разных действий. Общий список теряет это различие.

Три учебных backlog item и разные следующие шаги
Synthetic itemНаблюдаемый symptomГраница рискаОдин experiment
repeated-runbook-gapобъяснение одного diagnostic step повторяетсяreview не может назвать stop conditionнаписать одну boundary и проверить её на fixed path
ownerless-compatibility-riskриск записан, а принимающая роль пустаcontract change может остаться без решения по residual riskуказать role и один acceptance question
recheck-before-removalcleanup proposal опирается на старые labelsremoval обсуждают до recheck compatibility boundaryдобавить recheck gate и restore question

Компактный воспроизводимый пример

Ниже не находится настоящий долг и не делает запрос к системе. Он берёт один versioned fixed card из памяти, рассчитывает только учебную priority boundary и создаёт review draft. Это полезно как проверка формы: extra key, sparse array или cyclic object должны остановить draft раньше, чем кто-то прочитает красивый summary как разрешение на действие.

import {
  createFixedSyntheticMaintenanceInput,
  inspectSyntheticMaintenance,
  planSyntheticMaintenanceReview,
} from './upgrade-2024-12.mjs';

const input = createFixedSyntheticMaintenanceInput('repeated-runbook-gap');
const report = inspectSyntheticMaintenance(input);
const draft = planSyntheticMaintenanceReview(report);

console.log(report.risk.priorityBoundary); // review-now
console.log(draft.actions.length);          // 3
console.log(draft.effect);        // no-system-change

Этот example намеренно слабее реального процесса. В нём нет files, Git, CI, network, telemetry, incident archive, clock или production state. Значит, результат review-now не говорит «срочно менять систему». Он говорит только, что заданный набор fixed literals проходит выбранную учебную формулу и может быть оформлен в review card.

Evidence boundary защищает от ложной полноты

Граница доказательств — не юридическая приписка в конце. Она влияет на действие. Если card содержит только documentation gap, нельзя из неё вывести число затронутых клиентов. Если известен один contract, нельзя объявить, что других нет. Если owner role назван, это не означает, что человек уже принял риск. Эти различия мешают review превратиться в формат «мы почти уверены».

Практичный способ — разделить evidence на known, leading, lagging и unknown. Known отвечает, какой артефакт уже есть. Leading signal показывает, что риск растёт до повторения: например, proposal не может назвать check. Lagging signal фиксирует то, что уже вернулось: такой же вопрос снова попал на review. Unknown остаётся отдельным полем; его не переводят в ноль ради удобства таблицы.

Один experiment лучше программы исправлений

Следующий experiment должен менять знание, а не просто создавать активность. Для runbook gap это одна диагностическая граница и короткая репетиция. Для ownership gap — одна роль и вопрос, который она может принять или отклонить. Для cleanup — recheck gate, не сам removal. У каждого варианта есть stop condition: как только draft расширяется до redesign, удаления или обещания данных, которых нет, его останавливают.

Такой stop не означает провал. Он показывает, что первоначальный item был уже, чем предполагаемое решение. Сохраняем текущую карточку, возвращаемся к последней документированной границе и открываем отдельный review для большего scope. Google описывает postmortem как документирование причин и follow-up, а не как автоматическое выполнение любого action item; это полезная рамка и для maintenance review.

Что не стоит класть в годовой список

Не стоит склеивать в один item повторный вопрос, миграцию и будущую архитектуру. Не стоит писать «сэкономим N» без метода, диапазона и разрешённых данных. Не стоит заменять owner именем, если непонятно его полномочие. И не стоит называть числовой score вероятностью. NIST SP 800-30 описывает оценку риска как помощь в выборе курса действий; учебный score может лишь сделать обсуждение последовательным, но не снимает неопределённость.

Если item не проходит этот фильтр, его не обязательно удалять. Можно оставить его как hypothesis с явным unknown и назначить меньшее исследование. Но тогда он не конкурирует с хорошо описанной maintenance work на тех же условиях. Честный backlog допускает незнание, а не прячет его за приоритетом.

Ограничения и следующий проверяемый шаг

Все labels, roles, costs, timelines, evidence, scores и outcomes в этой статье — fixed synthetic teaching values внутри одного JS module. Они не описывают реальную команду, систему, incident, customer, деньги или историю года. Источники объясняют подход к preventive maintenance, risk assessment, postmortem и toil, но не доказывают корректность конкретной карточки читателя.

Следующий шаг: возьмите один пункт своего backlog и перепишите только шесть полей из первой таблицы. Затем попросите reviewer назвать one next experiment и stop condition, не открывая новый scope. Ожидаемый результат: item либо становится коротким проверяемым review card, либо честно возвращается в hypothesis с неизвестной границей.

Историческая граница декабря 2024

Использованы официальные главы первого издания Google SRE Book (2016) и финальные публикации NIST SP 800-30 Rev. 1 от сентября 2012 года и SP 800-40 Rev. 4 от апреля 2022 года. На декабрь 2024 эти материалы уже существовали. Они не дают универсального backlog template и не заменяют локальный change process. Учебная модель намеренно не читает внешний state.

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

  • Google SRE Book, Chapter 15: Postmortem Culture: Learning from Failure, first edition 2016 — Первичный официальный текст Google. Он описывает postmortem как запись влияния, причин, действий и follow-up, а также требует заранее определять триггеры. Он не предписывает конкретный backlog score, состав команды или частоту годового review.
  • Google SRE Book, Chapter 5: Eliminating Toil, first edition 2016 — Первичный официальный текст Google. Он отличает повторяемую ручную операционную работу от устойчивой инженерной ценности и показывает, почему источник toil полезно устранять, а не только фиксировать. Он не даёт универсальной оценки цены одного maintenance item.
  • NIST SP 800-30 Rev. 1: Guide for Conducting Risk Assessments, final September 2012 — Официальная финальная публикация NIST. Она задаёт риск-оценку как вход для выбора курса действий и требует учитывать контекст и неопределённость. Она не утверждает, что произведение нескольких баллов является достоверной вероятностью.
  • NIST SP 800-40 Rev. 4: Guide to Enterprise Patch Management Planning, final April 2022 — Официальная финальная публикация NIST. Она описывает preventive maintenance как идентификацию, приоритизацию, внедрение и проверку обновлений. Она не заменяет локальные ownership rules, change approval или проверку конкретной системы.