Story points и почему не часы

Разбираемся, почему команды перестали оценивать задачи в часах и перешли к безразмерным «попугаям».

Story point (стори-поинт) — безразмерная единица оценки, которая показывает сложность задачи относительно других задач той же команды, а не время на её выполнение.

Первая реакция человека, который слышит про story points, обычно одинаковая: «Зачем эта эзотерика? Скажите просто — сколько часов». Реакция честная. Но за ней стоит допущение, которое разваливается на первой же неделе работы: что человек умеет предсказывать, сколько времени займёт то, чего он ещё не делал.

Почему часы врут

Разработчик говорит: «Три дня». Проходит неделя, задача не готова. Он не врал и не ленился. Просто он оценивал ту версию задачи, которую держал в голове — идеальную, без сюрпризов. А в реальной вылезло: библиотека не поддерживает нужный формат, тесты падают на CI по другой причине, дизайнер отдал макет только на второй день, а на код-ревью попросили переписать половину.

У оценки в часах есть три встроенные ловушки.

  • Мы оцениваем счастливый путь. Голова считает время на работу, а не на препятствия. Психологи называют это ошибкой планирования: люди устойчиво недооценивают срок, даже когда прекрасно помнят, что в прошлый раз ошиблись.
  • Часы у всех разные. Одну и ту же форму сеньор сделает за 4 часа, джуниор — за 12. Значит, оценка перестаёт быть свойством задачи и становится свойством исполнителя. Задача переехала к другому — оценка недействительна.
  • Часы читаются как обещание. «6 часов» в глазах менеджера превращается в «к обеду завтра». Оценка мгновенно становится дедлайном, а промах — поводом для разговора. После пары таких разговоров команда начинает закладывать втрое, и оценки перестают значить хоть что-то.

Story points ломают все три ловушки: они не про время, они не привязаны к конкретному человеку, и их невозможно поставить в календарь напрямую.

Что вообще значит «сложность»

Story point — это не «сколько работы». Это смесь трёх вещей:

СоставляющаяВопрос, на который она отвечает
ОбъёмСколько всего нужно сделать? Один экран или двенадцать?
НеопределённостьМы вообще понимаем, как это делать? Делали похожее?
РискЧто может пойти не так? Внешний API, легаси-модуль, миграция данных?

Отсюда неочевидное следствие: маленькая по объёму задача может стоить дорого. «Поменять сортировку в отчёте» звучит на полчаса — но если отчёт собирается в древнем хранимом SQL-процедурном коде, который никто не трогал три года, это честная восьмёрка. И наоборот: сверстать двадцать однотипных карточек — много рутины, ноль неизвестности, поэтому недорого, хотя и долго.

Относительная оценка: сравнивать, а не измерять

Люди чудовищно плохо оценивают абсолютные величины и на удивление хорошо — относительные. Спросите, сколько метров до соседнего дома, — ошибётесь вдвое. Спросите, до какого дома дальше, до соседнего или до того, что через дорогу, — ответите мгновенно и правильно.

Story points эксплуатируют именно это. Команда не измеряет задачу — она сравнивает её с эталоном.

Эталонная задача (reference story) — маленькая, всем понятная, уже сделанная история, которой команда договорилась присвоить, скажем, 2 поинта. Дальше всё меряется от неё: «эта примерно как эталон — 2», «эта явно вдвое муторнее — 5», «а тут мы вообще не знаем, что внутри — 13».

Так выглядит живая шкала одной команды. Её обычно записывают и вешают на видное место:

Шкала команды «Платёжки» (эталон = 2)

1  — поправить текст ошибки, добавить поле в существующую форму
2  — ЭТАЛОН: новый эндпоинт CRUD по готовой модели + тесты
3  — экран из готовых компонентов, данные уже есть в API
5  — новая сущность: модель + миграция + API + экран
8  — интеграция с внешним сервисом, который мы уже подключали
13 — интеграция с сервисом, документацию которого мы ещё не читали
20 — «переехать на новый платёжный шлюз» → это не история, это эпик, дробить

Обратите внимание на последнюю строку. Шкала работает ещё и как детектор: если задача не влезает, значит, она сформулирована слишком крупно.

Почему Фибоначчи, а не 1, 2, 3, 4, 5

В покере используют ряд с растущими промежутками — 1, 2, 3, 5, 8, 13, 20, 40, 100. Причина простая и очень человеческая: чем больше задача, тем грубее мы её различаем.

Разницу между 1 и 2 команда чувствует: вдвое. Разницу между 2 и 3 — ещё различает. А теперь попробуйте всерьёз поспорить, задача на 21 или на 22. Спор будет ровно ни о чём: точности такой оценки просто не существует, погрешность там плюс-минус десятка.

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

Как это работает на практике

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

Выглядит результат примерно так:

Спринт 14 — оценённый бэклог

[3]  Фильтр по статусу в списке заказов
[5]  Экспорт заказов в CSV
[2]  Починить пагинацию на последней странице
[8]  Отправка чека на email после оплаты
[13] Возвраты через платёжный шлюз      ← дробим на 3 истории
[1]  Заменить иконку в шапке

Итого без «возвратов»: 19 поинтов

Ни в одной строке нет часов. И это не мешает планировать: команда знает, что за прошлые спринты она вывозила 20–25 поинтов, значит, такой набор реалистичен, а «возвраты» в текущий спринт брать нельзя, пока их не разобрали на части.

Частые ошибки

  • Тайный курс обмена. Команда решает: «1 поинт = 1 день». Поздравляю, вы изобрели часы с лишним шагом. Все ловушки времени вернулись, только теперь их прикрывает модное слово.
  • Оценивает не тот, кто делает. Тимлид или менеджер расставляет поинты «за команду». Оценка тут же перестаёт быть оценкой и становится нормативом, который спускают сверху.
  • Поинты как обязательство. «Вы сказали 5, а сделали за 13, будем разбираться». После первого такого разговора команда начинает ставить 13 везде. Оценка — прогноз, а не подпись под договором.
  • Сравнение с другой командой. Восьмёрка команды А и восьмёрка команды Б — разные величины, как рубль и юань. Шкала имеет смысл только внутри одной команды.
  • Оценивают всё подряд, включая эпики. Ставить оценку задаче «сделать личный кабинет» бессмысленно. Сначала дробим до размера истории, потом оцениваем.
  • Пересчёт оценок задним числом. Задача оказалась вдвое тяжелее — и команда «исправляет» оценку с 5 на 13. Не надо: тогда velocity перестанет отражать реальность, а история промахов исчезнет вместе с возможностью учиться на ней.

Итоги

  • Story point — безразмерная единица сложности: объём плюс неопределённость плюс риск.
  • Часы врут: мы оцениваем счастливый путь, часы зависят от исполнителя, а руководство читает их как дедлайн.
  • Оценка относительная: задачу сравнивают с эталонной историей, а не измеряют в вакууме.
  • Ряд с растущими промежутками (1, 2, 3, 5, 8, 13, 20) запрещает ложную точность и подталкивает дробить крупное.
  • Оценивают только исполнители. Поинты одной команды несопоставимы с поинтами другой.
  • Оценка — прогноз, а не обещание. Как только за неё начинают наказывать, она умирает.
Проверьте себя
1. Задача «поменять сортировку в отчёте» требует правки в 15 строках кода, но лежит в древнем модуле, который никто не понимает и не покрыт тестами. Какая оценка ближе к правильной?
A1 поинт — объём работы крошечный
B8 поинтов — высокая неопределённость и риск важнее объёма
C0 поинтов — правка тривиальная
DОценить в часах, так как это техническая задача
2. Команда договорилась, что 1 story point всегда равен одному рабочему дню. К чему это приводит?
AК более точным оценкам, потому что появилась привязка к реальности
BНи к чему: это просто удобное правило пересчёта
CОценка снова становится оценкой времени со всеми её проблемами — зависимость от исполнителя и превращение в дедлайн
DК росту velocity команды