Cost per sprint: как вносить деньги в обсуждение ретро
Спринт 47, команда из 8 человек. Стандартный нарратив ретро звучал бы так: «velocity упал на 20%, было много багов, в следующем спринте поприоритезируем лучше». Тот же вайб, что и в спринте 46. И в спринте 45. Теперь добавьте на то же ретро один показатель: общая стоимость спринта — $32 800, из них $11 600 (35%) ушли на тикеты с багами, против $14 200 (43%) на фичи. Скользящее среднее по багам у этой команды — 18%. Одна строка — «мы потратили на баги вдвое больше обычного» — переключила команду с «сделаем лучше» на «первые три дня спринта 48 — только bug-prevention, без исключений».
Этот пост показывает, как встроить один финансовый показатель в 30-минутное ретро так, чтобы оно производило решения, а не ощущения.
{/* truncate */}
Почему ретро перестают менять поведение после 4-го спринта
Atlassian в Agile Practitioner Report 2024 измерили, как часто команды возвращаются к action item'ам прошлого ретро: 62% не возвращаются никогда. Esther Derby и Diana Larsen написали Agile Retrospectives: Making Good Teams Great в 2006 году именно про этот провал — что ритуал переживает дисциплину. Спустя двадцать лет опрос scrum.org 2023 года среди 4 200 практиков поставил «ретро ощущаются перформативными» на первое место в жалобах senior-инженеров.
Механика скучная: люди обсуждают ощущения. Ощущения смещаются к самому громкому голосу в комнате. Самый громкий голос — к самой свежей боли. Поэтому каждое ретро заново разбирает прошлый инцидент, и команда никогда не видит паттерн поверх последних шести спринтов.
Отчёты DORA State of DevOps с 2019 года повторяют ту же структурную мысль — высокопроизводительные команды измеряют систему, а не момент. Ретро, которое начинается с «как все себя чувствовали?», устроено противоположным образом.
Контринтуитивная часть: ОДИН показатель делает всю работу
Большинство статей про «data-driven retro» говорят принести 8 метрик: velocity, cycle time, lead time, MTTR, change failure rate, deployment frequency, planned-vs-delivered, unplanned ratio. Это дашборд, а не ретро. Глаза у команды стекленеют к четвёртой минуте.
Принесите вместо этого одно число: общую стоимость спринта, разбитую на 3-4 типа задач. Фичи, баги, техдолг, незапланированные встречи/созвоны. Всё.
Почему работает: стоимость превращает качественный спор в количественное сравнение. «У нас было много багов» — спорно. «Мы потратили на баги $11 600 против $6 200 в прошлом спринте» — нет. Команда перестаёт обсуждать, было ли так, и начинает обсуждать, что с этим делать.
Что значит «общая стоимость спринта»
Возьмите loaded hourly rate команды (формула — в Loaded Hourly Rate). Умножьте на отслеженные часы спринта на каждого инженера. Просуммируйте по команде. Затем разделите по типам задач Jira через тайм-трекинг тикетов.
Для команды из 8 человек при ставке ~$60/час × 80 часов/спринт × 8 инженеров сырая capacity — около $38 400. После вычета встреч, отпусков и PTO остаётся $30K-$34K — это и есть стоимость спринта.
PanDev Metrics считает это автоматически. Эндпоинт POST /departments/{id}/finance/costs принимает granularity = DAILY|MONTHLY|QUARTERLY и возвращает временной ряд по стоимости с готовыми полями percentageChange (изменение спринт-к-спринту) и trend (UP/DOWN). Каждая строка содержит join по issue_key, поэтому разбивка по фичам/багам/техдолгу получается бесплатно. Виджет с барчартом (costs-widget.tsx) рисует stacked-вид по месяцам, который мы покажем ниже. Без этого тот же расчёт можно собрать SQL-ем — паттерн join'а есть в Cost per Feature: SQL Formula.
Шесть спринтов одной команды из 8 инженеров. Спринт 47 — пик доли багов, который запустил action item. Спринт 48 — результат.
Реальный пример: спринт 47 → спринт 48
Команда настоящая (анонимизировано). 8 backend-инженеров, финтех, фиксированные двухнедельные спринты. Их последние 6 спринтов:
| Спринт | Стоимость | Фичи | Баги | Техдолг | Доля багов | Δ к пред. |
|---|---|---|---|---|---|---|
| 43 | $29 000 | $18 000 (62%) | $7 000 (24%) | $4 000 (14%) | 24% | — |
| 44 | $28 500 | $16 500 (58%) | $8 500 (30%) | $3 500 (12%) | 30% | −2% |
| 45 | $29 000 | $15 000 (52%) | $9 800 (34%) | $4 200 (14%) | 34% | +2% |
| 46 | $29 600 | $14 800 (50%) | $10 500 (35%) | $4 300 (15%) | 35% | +2% |
| 47 | $32 800 | $14 200 (43%) | $11 600 (35%) | $4 800 (15%) | 35% | +11% |
| 48 | $29 800 | $17 800 (60%) | $6 200 (21%) | $5 800 (19%) | 21% | +1% |
Из таблицы видно три вещи, которые не выловил ни один качественный ретро:
- Доля багов росла спринт-к-спринту с 24% до 35% за четыре спринта. Медленный дрейф, ни в одном отдельном ретро не выглядит тревожно.
- Спринт 47 не был драматически хуже 46 по доле — но абсолютные траты на баги выросли с $10 500 до $11 600 и общая стоимость выросла на $3 200 (овертайм, две дополнительные пары рук). Эта комбинация видна только в деньгах.
- Интервенция в спринте 48 — «первые 3 дня только bug-prevention» — снизила долю багов до 21%. Около $5 400 перенаправлено обратно в фичи. Команда почувствовала эффект на следующем стендапе — он не был triage-созвоном.
Это измеримое изменение. Не ощущение.
Шаблон ретро: спросить, посмотреть, решить
Принесите четыре столбца в документ ретро за 15 минут до начала. Не обсуждайте — просто вставьте.
| Что спросить | Какое число использовать | Какое действие включает |
|---|---|---|
| Куда ушли деньги? | Стоимость по типам задач (% спринта) | Перепланирование приоритетов |
| Изменилась ли доля багов? | Доля багов vs скользящее среднее за 6 спринтов | Block bug-prevention при дрейфе > 5 п.п. |
| Куда ушло незапланированное время? | Стоимость тикетов, попавших после планирования | Жёстче планирование ИЛИ шире буфер |
| Платим ли техдолг? | Доля техдолга за последние 4 спринта | Если падает к нулю — назначить debt-спринт |
Жёстко 30 минут. Первые 5 — тихие, все читают таблицу. Следующие 15 — обсуждение одной строки, той, где наибольшая дельта. Последние 10 — один именованный action item с измеримой проверкой. В спринте 48 проверкой было: «доля багов меньше 25% к пятнице». Это число можно проверить в понедельник.
Частые ошибки, которые ломают финансовое ретро
| Ошибка | Чем плохо | Фикс |
|---|---|---|
| Встречи смешаны с «техдолгом» | Раздувает стоимость долга, прячет планирование | Добавьте 4-й бакет: незапланированные встречи |
| Показывать стоимость по инженеру | Разговор уходит в личную перформанс-оценку | Агрегируйте только на уровне команды |
| Использовать стоимость как target («снизим cost спринта») | Команда начнёт меньше трекать, число врёт | Стоимость — диагностика, не цель — проговорите вслух |
| Тянуть числа во время ретро | Съедает встречу, ломает поток | Фасилитатор вставляет за 15 минут до — никаких live-запросов |
| Отслеживать 8 типов задач | Никто не держит в голове | Максимум 3-4 бакета, всегда |
Где это ломается
Cost per sprint полезнее всего командам, которые уже работают по фиксированным спринтам. Команды на continuous flow (Kanban) больше получают от cost per cycle или cost per deploy — у них нет границы спринта, и числу не за что зацепиться. Для них есть Cost per Task: Issue-Tracking Approach — работает на уровне тикета.
Финансовая разбивка требует честной типизации задач. Если «баги» тихо переименовываются в «фичи», чтобы статистика выглядела лучше, данные врут — и инстинкт команды будет громче числа, что обнуляет смысл. Введите правило: тип ставится при создании тикета репортёром, не правится потом. Реклассификация в середине спринта требует комментария.
Ещё одно ограничение: на очень маленьких командах (меньше 5 инженеров) отсутствие одного человека двигает разбивку настолько, что любой отдельный спринт — шум. Смотрите на скользящие средние за 4 спринта, не на однократные дельты. Число всё ещё полезно, просто используется иначе.
Как понять, что ретро работает
- Доля выполненных action items: уехал ли action item прошлого ретро в код? Цель — 80%+ за квартал.
- Дисперсия доли багов: уменьшение стандартного отклонения по спринтам означает, что команда управляет миксом, а не реагирует на него.
- Время до решения внутри ретро: если обсуждение-до-action регулярно занимает 25 из 30 минут, данные не работают — ужмите таблицу.
Это и сдвигается, когда ретро перестают быть перформативными. Velocity не обязательно меняется. Cycle time не обязательно меняется. Меняется разбивка трат.
Что можно сделать сегодня
Вытащите часы по типам задач за прошлый спринт из Jira или вашего трекера. Умножьте на loaded rate команды. Добавьте четыре столбца (стоимость, % спринта, дельта спринт-к-спринту, скользящее среднее) в документ следующего пятничного ретро за 15 минут до начала. Не комментируйте. Затем смотрите, на какую строку показывают пальцем чаще всего.
Эта строка ведёт встречу. Команда сама скажет, что с ней делать.
