Замороженная работа: метрика, которая считает непринятые решения
Мне понадобилось разобраться, что происходит на большом проекте внедрения: почему сроки едут и куда девается ресурс. Разработку вела внешняя команда, живьём я её не вёл и контекста не имел — на руках были только следы: трекер, вики, гит, списания времени.
Начал я с самого очевидного — померить, кто из аналитиков сколько делает. Провозился неприлично долго, получил красивые графики и всё выбросил. Дальше — почему выбросил и что нашлось, когда я перестал смотреть на людей.
Сразу оговорюсь про две вещи. Первая: это не статья про оценку эффективности сотрудников, скорее наоборот — про то, почему у меня не получилось её написать.
Вторая — про сам кейс. Он тяжёлый. Спринт вдвое больше собственного лимита, треть незавершёнки без движения месяцами, задачи с семнадцатью сменами исполнителя. Нормальным этот проект не был, и типичным я его не выдаю. Полезен он ровно этим: в здоровой команде все описанные ниже эффекты тоже есть, но дают процентов пять и потому не видны. Здесь они дают триста и становятся различимы. Это стенд, а не образец, и интересен тут метод, а не кейс.
Часть 1. Персональные метрики: красиво и бесполезно
Первое, что приходит в голову человеку с доступом к трекеру, — посчитать, кто сколько закрыл. Я посчитал шесть таких метрик. Все шесть деформируются от одного и того же — от того, как нарезана работа.
Количество закрытых задач. Тот, кто дробит тему на двадцать подзадач, обгонит того, кто ведёт её одной, при равном объёме работы. Метрика меряет стиль ведения трекера.
Доля закрытых историй. Зависит от того, что в команде принято называть историей. У одного история — двухнедельная работа, у другого — зонтик на полгода с сорока задачами внутри. Первая закрывается, вторая не закроется, пока живёт модуль.
Конверсия спецификаций в код. Меряет гранулярность документов и очередь на разработку, а не аналитика. Десять мелких спецификаций — девять уехали в код. Одна на весь модуль — годами висит «частично реализована».
Число переносов между спринтами на задачу. Крупная задача переезжает по определению: она физически не помещается в спринт. Метрика штрафует за размер.
Медианный возраст открытых задач. То же самое с другого конца. Ведёшь одну тему полгода — медиана полгода. Закрываешь мелочь — медиана три дня.
Число итераций уточнения требований. Ловушка тоньше: мало итераций — это либо «всё было понятно сразу», либо «к тебе не приходят, потому что разработка делает по-своему». По данным одно от другого не отличается никак.
Общее у них одно: всё, что считает задачи, награждает за дробление.
Три захода — три разных ответа про одного человека
Неприятнее всего было, когда по одному человеку у меня вышли три взаимоисключающих вывода.
По медиане переносов между спринтами — лучший показатель в команде: 1. По числу итераций уточнения после старта разработки — тоже лучший: 1,3. По доле содержательных правок, внесённых до старта разработки, — снова лучший: 74%. Три метрики подряд говорят: человек работает аккуратнее всех.
А потом я посмотрел на вес висящей работы. 13 долгостроев, под которыми 113 открытых задач. Среди них сквозные темы: одна открыта 763 дня и имеет ровно одну подзадачу, другая — 762 дня, третья 334 дня стоит в статусе «Новая» и ни разу не была в спринте.
Три захода — три разных ответа про одного и того же человека. Данные при этом везде нормальные. Неправильный был вопрос.
Ошибки атрибуции, на которых я обжёгся
Считал по автору записи, а не по исполнителю. Человек, заведший в трекер треть задач проекта в роли координатора, забрал себе чужую статистику. Красивый график, полностью выдуманный.
Искал ссылки на задачи в теле страниц вики. Получил контраст 62 к 1 между двумя людьми и на секунду поверил. Оказалось, что вставлять ссылки прямо в текст — привычка одного человека из пяти. По корректному источнику вышло 37% против 30%, то есть разницы нет.
Не запросил у трекера поле связи эпика с историями — оно не отдаётся по умолчанию. Эпики выглядели пустыми, и я успел построить на этом вывод. После перевыгрузки под одним оказалось 416 задач.
Сверял работу со справочником функциональных требований, не проверив его периметр. Справочник покрывал два модуля из шестнадцати. Вывод «половина работы вне контракта» оказался враньём. Правильная формулировка — «вне периметра первой очереди», и это совсем другое утверждение.
И главное
Даже если бы я всё посчитал безупречно, персональная оценка — работа тимлида, а не моя. Он знает, кому досталась тухлая тема, кто месяц сидел на поддержке продакшена, а кого дёргали на три проекта сразу, и делает эти поправки в голове автоматически. Снаружи я их не сделаю никогда, и никакая нормировка это не чинит.
Отсюда правило, которым я теперь пользуюсь: если метрика позволяет назначить виноватого — скорее всего, она врёт.
Часть 2. Уровень команды и потока
Я переключился с людей на поток. И вот там открылась бездна.
Сразу отвечу на законное возражение — в таком трекере ничего мерить нельзя, это свалка. Во-первых, метрика, ради которой написана статья, стоит на дате последнего движения: это поле пишет система, а не человек, и плохой гигиеной его не испортить. Не проставили статус, не залинковали эпик, назвали историю зонтиком — дата всё равно есть. Во-вторых, и это важнее: свалка в трекере не помеха измерению, а его результат. Спринт вдвое больше лимита и сотни задач без движения — это не плохие данные о работе, это хорошие данные об управлении. В итоге я мерил не работу, а управление, и для этого трекер честнее любого отчёта: его никто не готовил к показу.
1. Незавершённое производство выросло в семь раз. Со 121 задачи до 866 за два года — при росте пропускной способности примерно вдвое. Очередь из уже начатого при текущем темпе — четыре-восемь месяцев. Если завтра перестать брать новое, команда ещё полгода будет разгребать взятое.
2. Замороженная работа. Главная находка. Из 835 задач в активных статусах 261 не двигалась больше трёх месяцев, 138 — больше полугода, 81 — больше года.
Общая цифра мало что даёт, важен разрез по стадии:
-
421 задача с уже написанным кодом — тестирование, верификация, проверка, исправление замечаний. Из них 129 стоят больше 90 дней, 58 — больше полугода. Это работа, которая уже стоила денег и не превратилась в результат.
-
414 задач взяты в разработку и брошены: 132 стоят больше 90 дней, 80 — больше полугода, 54 — больше года.
Возражение «это просто забытые записи, а работа шла мимо трекера» отчасти справедливо: статус сам по себе ничего не доказывает. Проверять надо по следам — есть ли под задачей коммиты и списания. Там, где следы есть, забытая запись означает не отсутствие работы, а ровно обратное: работа сделана и потеряна.
Дальше контринтуитивное. Замороженные задачи выпадают из спринтов: медиана переносов у них — ноль, тогда как 574 живые задачи дали 2 239 переносов. Замороженное невидимо по построению: оно не в спринте — значит, не в отчёте — значит, о нём не говорят на планировании. Чем дольше задача заморожена, тем меньше её видно. Ценность метрики ровно в этом: она показывает то, что выпало с доски.
3. Стоимость переключения контекста. 12 139 смен исполнителя на 3 965 задач — в среднем каждая задача трижды переходила из рук в руки. 1 722 задачи меняли исполнителя три и более раз, 1 042 — пять и более. На 261 замороженной задаче — 726 смен исполнителя.
Рекорд: задача с 17 сменами исполнителя, простой 272 дня, статус «Исправление замечаний». Семнадцать человек по очереди грузили контекст, и ни одна загрузка не дала результата.
Для сравнения: всего по проекту списано 11 324 часа. Переключений контекста больше, чем зафиксированных часов работы. Сравнение грубое — учёт времени неполный, — но порядок понятен.
4. Запуск против закрытия. Самый простой график и самый убедительный. По полугодиям, создано в месяц / закрыто в месяц: 146/54, 82/75, 186/81, 191/144. Каждый период запускается больше, чем закрывается.
Здесь нужна оговорка, без которой график читается неправильно. Запуск — не заслуга и не вина тех, кто пишет код. Задачи в этот трекер заводят обе стороны, и заметная часть потока — изменения и уточнения со стороны заказчика. Очередь наполняли совместно, и разгребать её тоже пришлось бы совместно.
5. Реакция на эскалацию. Самое интересное. После жёсткой эскалации на уровне руководства: активных людей 16 → 19, создаётся задач 154 → 239 в месяц, закрывается 110 → 191 (рост на 74%), влитых merge request 94 → 118. Команда действительно стала работать больше — это не имитация. И при этом незавершёнка выросла с 707 до 866 задач, а доля закрываемого в спринте упала с 57% до 34%.
Нажим дал всплеск интенсивности и ухудшил результат — потому что запуск вырос быстрее закрытия. И это провал не команды, а рычага: единственный инструмент, который был у управления, сработал ровно наоборот.
6. Наращивание состава уже пробовали. За два года людей стало больше на 47%, производительность на человека почти удвоилась (4,5 → 8,4 закрытых задач в месяц), поток кода вырос впятеро. Очередь всё равно выросла втрое.
7. Размер спринта. С 674 до 1 034 задач за пять итераций — при действующем требовании держать лимит 400–450. Доля закрываемого за спринт за то же время упала с 57% до 34%. Спринт перестал быть обязательством и стал списком пожеланий.
8. Переносы между спринтами — не метрика качества требований, хотя все считают наоборот. Я разобрал 4 730 переносов: 95% приходится на зонтичные «истории», 92% вообще не привязаны к спецификациям. В момент переноса задача была в разработке в 53% случаев, не начата — в 27%, на тестировании — в 19%. В статусе «уточнить требования» — один раз из 4 730. Рекордсмен переезжал 33 раза.
Перенос измеряет планирование, а не аналитику. Если вы этой метрикой прижимаете аналитиков — вы прижимаете не тех.
Часть 3. Две метрики, которые выжили
Из всего, что я насчитал, осталось две штуки.
Замороженная работа
Лучшая управленческая метрика из тех, что у меня получились. Ничего нового в самой идее нет — это aging work in progress, он описан в любой книжке по канбану, и я его не изобретал. Интересно другое: почему при всей известности его никто не смотрит. Ответ ниже, и он же объясняет, почему метрика работает.
Почему именно она:
-
Измеряет решения, а не усилия. Каждая замороженная задача — один невынесенный выбор из трёх: доделать со сроком, явно приостановить, закрыть. Никто не выбрал ничего.
-
Не улучшается дроблением. Раздробишь одну замороженную — получишь десять замороженных.
-
Не наказывает за крупную тему. Живая крупная задача в неё не попадает вообще: критерий — отсутствие движения, а не размер.
-
Имеет цену в деньгах. 421 задача с написанным кодом — это потраченное и не превратившееся в результат. Такую цифру можно нести на разговор о деньгах: она понятна без объяснений про спринты.
-
Объясняет парадокс роста производительности при падении результата.
Стоимость такой задачи складывается из трёх слоёв: прямые затраты на уже сделанное; стоимость возврата — через полгода контекст грузится заново, и часто дешевле переделать, чем вспомнить; сгоревший контекст всех предыдущих передач из рук в руки.
Отсюда формулировка, которая мне кажется точной: замороженная задача — это не остановленная работа. Это работа, которая продолжает потреблять ресурс, не производя ничего.
Длина рабочего дня по временным меткам
Медиана от первого до последнего события человека за день. Отвечает на другой вопрос — не «кто хорошо работает», а «сколько мощности реально куплено». Не зависит от полноты учёта времени, не деформируется нарезкой задач, и её нельзя завысить — только занизить, если работать вне систем.
В сумме по команде вышло 2,7 полной ставки на пять человек, утилизация 54%. Это, кстати, совершенно нормальное число, и именно поэтому метрика полезна: она отвечает на вопрос о закупленной мощности, а не о чьей-то лени. Поимённый разрез у меня есть, и я его здесь не привожу намеренно — он ничего не объясняет и провоцирует ровно тот разговор, против которого написана статья.
Как это считалось
Коротко, чтобы не выглядело магией.
-
История изменений задач выгружается с раскрытием changelog, и обязательно нужны значения переходов, а не только имена изменённых полей. Иначе «статус менялся» есть, а «из чего в что» — нет.
-
Списания времени по всему инстансу берутся одним проходом через эндпоинт обновлённых ворклогов, а не обходом задач.
-
Полная история версий страниц вики доступна только через экспериментальный API, в стабильном её нет. Тела исторических версий запрашиваются отдельно.
-
Поле связи эпика с историями не отдаётся по умолчанию, его нужно знать по идентификатору.
-
Новизна правки — доля новых восьмисловных шинглов относительно предыдущей версии: так содержательная переработка отделяется от переформатирования.
-
Связь спецификации с задачей брать только из ссылок самой задачи, не из текста страницы.
-
Цифры в разных блоках посчитаны по разным периметрам и периодам и поэтому не складываются друг с другом впрямую: «активные статусы» — это не вся незавершёнка, часть задач уходит в отменённые и дубли. Внутри блока всё сходится: 421 + 414 = 835 и 574 + 261 = 835.
Чего с этим не надо делать
Теперь честная часть.
Не надо брать замороженную работу и длину рабочего дня и нести их в свою команду вместо разговора с людьми. Применённая к конкретному человеку без контекста, любая из них повторит все ошибки первой части статьи, только с более убедительным видом. Замороженная задача — почти всегда след управленческого решения, которое не приняли: не хватило ответа от смежников, приоритет уехал, заказчик замолчал, некому принять. Человек, на котором она висит, обычно к этому отношения не имеет.
И я не готов сказать «внедрите это завтра». Половину времени я потратил не на расчёты, а на то, чтобы понять, что именно я посчитал, и четырежды обнаружил, что посчитал не то.
В сухом остатке: я шёл смотреть на людей, а посмотрел на очередь. Вопрос «кто плохо работает» на этих данных ответа не имеет вообще. Вопрос «где работа стоит и почему её никто не видит» — имеет, причём в деньгах.
Хорошая управленческая метрика считает не то, сколько сделано, а сколько решений не принято. Всё остальное — про доску. А смотреть надо на то, что с доски выпало.
Автор: Nemax

