Когда я был начинающим программистом, – а впрочем, и позднее, когда я был начинающим ведущим разработчиком, – я думал, что спрогнозировать сроки, в которые ты что-то сделаешь, абсолютно невозможно. Или же, что хороший прогноз требует очень детальных проектирования и подготовки, примерно таких же по длительности, как и сама задача.
Позднее, конечно, я обнаружил, что по теме прогнозов написано несколько умных книжек, которые в сумме с некоторым опытом делают оценку задач хоть и неблагодарным, но и небезнадёжным занятием. Самым удобным способом, конечно, является оценка по аналогии: когда ты уже делал нечто подобное, ты довольно точно знаешь, каких усилий эта задача потребует. Но как быть в ситуации, когда опыта сравнительно немного или аналогии брать неоткуда, а оценить все же хочется?
В одной из команд, где я работал, мы придумали оригинальный метод для предварительной оценки задач. Метод синтезирует некоторые известные из литературы приёмы, но в приведённой форме, пожалуй, никем не описан. Концепция была следующей: объективность (связь с измеримыми показателями); интегрируемость с Agile; повторяемость; быстрота оценки (меньше 0.5% от объема задачи); доступность для начинающих разработчиков. Я буду рад обсудить нашу идею и не исключаю, что кому-то из Хабрааудитории она придётся по душе.
Четыре фактора сложности: анализ задачи
Итак, берём задачу (плохо поставленную, формально не описанную — всё как в жизни). Выполняем экспресс-анализ: а именно, собираем в голове (или на доске) интуитивное представление о том, какую функциональность нужно реализовать и как технически эта задача может быть выполнена.
Нашей первой целью является конкретизировать возникшее представление настолько, чтобы можно было его численно оценить по ниже приведенным 4 шкалам.
Факторы сложности, они же проекции, условно называются так:
- «Поверхность»
- «Тестирование»
- «Требования»
- «Технический риск»
Эти термины в методе понимаются достаточно оригинально (например, «поверхность» — это вообще нестандартное понятие), но сформулированы так, чтобы иметь связь с объективной реальностью, т.е. с измеримыми величинами:
Поверхность в общем случае — это площадь соприкосновения нашей доработки с внешним миром. Например, для GUI компоненты следует составить некое количественное представление о будущем числе элементов интерфейса. Для библиотеки — о числе методов в публичном API. Для баг-фикса — об объеме затронутого кода. Для стейт-машины — о классах входящих событий. В случае, если у нас в задаче «и то, и другое, и третье», то надо задуматься, что из этого внешнее, а что, по сути, приватное, и именно публичную часть и оценивать.
Тестирование — это наше представление о количестве элементарных автоматических тестов, которые нам придётся написать для исполнения в стиле TDD. Это не обязательно предполагает, что мы будем разрабатывать через тестирование (говорят, настоящие ковбои вообще тестов не пишут), но для оценки сложности задачи нам нужно задуматься, какой объем тестов ей соответствует.
Требования — это наше представление об объёме того, что в классических подходах называется требования (requirements). Мы можем понимать этот фактор как размер спецификации, которую нам пришлось бы написать, если бы мы хотели полностью формально поставить задачу. Естественно, мы практически никогда не тратили время на составление подобных спецификаций — составление требований в наш процесс не входило — но имели представление о том, насколько объёмными подобные документы получаются. Выносим оценку в форме: «Чтобы формально это описать, потребовалось бы страниц 15» и идём дальше.
Технический риск — этот фактор отражает ожидания того, что придётся делать какое-то исследование, пробовать несколько подходов, или выбрасывать часть работы из-за того, что у нас что-то не срастётся. В теории, эту величину можно выразить числом от 0% до 100%, но на практике это наиболее субъективная из 4 величин. Можно действовать так: для оценки риска, придумываем все способы, как можно эту задачу завалить. Если в результате мы чувствуем депрессию и у нас появились серьезные сомнения, что мы в итоге cправимся в разумные сроки — то ставим оценку, близкую к максимальной.
Получившиеся 4 «проекции» образуют своего рода профиль задачи — становится понятным, что составляет её основную сложность. Одновременно при анализе задачи происходит валидация (проверка) её постановки: если вы, к примеру, осознаете, что вам неизвестно, как вы будете тестировать свою доработку, то скорее всего приступать к написанию кода нельзя. Некоторое значение имеет и соотношение проекций — большие показатели сразу по нескольким факторам намекают на то, что у задачи есть «скрытый объём» (что угрожает многократным превышением наших ожиданий), в то время как «плоские» задачи (задачи с одной доминирующей «проекцией») обычно легко просматриваются и делаются в ожидаемый срок. В том же случае, когда задача изначально казалась небольшой, и действительно оказалась небольшой по всем оценкам, время на размышления всё равно было потрачено не зря: как минимум, мы подтвердили, что у нас есть достаточное понимание того, что надо реализовать.
Такой экспресс-анализ проводится быстро, и даёт достаточно ясное представление о сложности и трудоёмкости задачи. Можно было бы и закончить на этом, ограничившись качественным подходом. Однако, мы на самом деле пошли намного дальше и синтезировали из этой концепции экспериментальную метрику.
Ниже будет изложен способ получить из 4 качественных оценок количественную величину, которая, в конечном счёте, помогает составить бэклог итерации или обозначить прогноз времени. За ней не стоит серьёзного научного исследования, но в нашей практике он давал довольно неплохую точность при минимальных затратах сил.
Экспериментальная метрика
Как мы уже поняли, на начальном этапе 4 проекции выражаются примерно так: «в нашем компоненте ожидается штук пятьдесят методов, двести тестов; потребовалось бы 20 страниц описания, которого никогда не будет, и есть примерно 10% шансов все переделывать заново». Теперь, когда мы это всё оценили, нам потребуется эти количества агрегировать. Но просто так сложить тесты и шансы, конечно же, нельзя, поэтому наши оценки предстоит конвертировать в условные единицы сложности.
Сложность, вообще, понимается как мера временных затрат за вычетом написания очевидного бойлерплейта и всех остальных рутинных и предсказуемых операций. Для начальной конвертации, используется следующая нелинейная шкала:
- 0 — означает «все просто» (можно сразу представить во всех деталях, что требуется сделать, и собственно сделать за незначительный срок);
- 1 — это та сложность, которую можно побороть за квант времени (допустим, за 4 или 8 часов)
- 3 — больше единицы в 3-5 раз, что уже считается довольно высоким, несколько проблемным значением
- 5 — максимальная оценка, означает «эпик» (так сложно, что точно стоит разбить, урезать или отказаться)
Формула
Для получения итоговой метрики суммируем все наши оценки в единицах сложности по четырём шкалам.
Однако, если в двух и более шкалах у нас получилось ≥2 — то два наибольших числа мы не складываем, а перемножаем.
Иллюстрация:
Задача 1. 1 0 0 0 -> 1 -> 1 Задача 2. 1 0 2 0 -> 1+2 -> 3 Задача 3. 1 1 2 0 -> 1+1+2 -> 4 Задача 4. 3 3 1 2 -> 3*3+1+2 -> 12 Задача 5. 1 4 1 5 -> 4*5+1+1 -> 22
Использование
Метрика сложности даёт представление об объёме интеллектуальной работы, явном и скрытом, и даже может быть конвертирована, почти механически, в пессимистическую оценку времени. Как это сделать, смотрите ниже, но сначала я рассмотрю несколько более легких сценариев использования. Некоторые из нижеизложенных способов вообще не привязаны к тому, как именно вы получили метрику — они просто показывают, как можно извлечь какую-то пользу из подобной числовой величины.
Выбор технического решения
Когда вы пишете большой и сложный проект, бывает, что у вас есть два-три приемлемых способа добавить некую функциональность, и вам нужно заранее предсказать, какой путь будет проще. Чтобы принять решение, вы можете оценить каждый из вариантов по 4 факторам и сравнить значения (правда, выбирая более простой путь, стоит задуматься, не добавляете ли вы технический долг).
Валидация задач
Метод обладает интересной способностью выявлять скрытую сложность задачи за счёт того, как в нём устроена арифметика и шкалы (тот самый скрытый объём; см. также раздел «опыт использования»). Если вы не ограничиваетесь качественным анализом, а вычисляете метрику, то вы можете сделать постановку задач лучше. Для этого, вводятся два критерия:
- Метрика сложности не должна превышать некоторого предела. Задачи по объему относительно однородны (не слишком маленькие, не слишком большие);
- Нет «трехмерных» и «четырехмерных» задач, т.е. задача получает высокие оценки максимум по 2 проекциям.
В этих критериях вводятся некоторые константы, характеризующие желаемый размер разбиения. Их можно настраивать. Я предпочитаю вариант «не более 10 по метрике, не больше 1 в 2 младших проекциях», но это получается довольно крупно.
Составление бэклога
Методологий разработки ПО существует великое множество, но значительная часть их предполагает определённую итеративность, которая заключается в том, что команда ставит себе цель на период времени и определяет набор задач, которые для достижения этой цели надо сделать. В конце итерации должна получиться готовая к поставке версия продукта.
В начале итерации производится оценка того, что вообще возможно сделать за этот период времени и происходит уточнение задач, в результате чего получается некий перечень, аналогичный бэклогу из User Story и/или других форм описания задач.
Известное преимущество стандартного бэклога в формате User Story перед «планом работ на период» состоит в том, что его не обязательно точно оценивать, в силу своебразной «магии» скрама. Но здесь есть важный нюанс. Если задачи, как это происходит во многих командах, разбиты не в каноническом формате User Story, а более крупно, или более «архитектурно», то упомянутая «магия» легко ломается: качество оценки размера задачи в начале итерации начинает играть критическую роль. Это очень распространённая ситуация, в которой вам может потребоваться и набор исторических данных по прошлым задачам, и вычислимая метрика, которую вы используете в начале итерации как оценку размера для задач, вызывающих сомнения. Поскольку неправильно выбранный состав итерации наносит вред и продукту, и мотивации разработчика, прилагать усилия к адекватной оценке задач бывает более чем оправдано. Я бы рекомендовал это делать.
Boost your Scrum
Scrum-команды, как правило, выставляют оценку задачам в условных единицах (Story Point). Сделать это не всегда просто. Практикуются относительно сложные процедуры, такие как Planning Poker.
Применение метода в стиле Agile заключается в том, что мы считаем предлагаемую метрику в тех случаях, когда у нас есть сомнения относительно размера задачи или возможности её реализации. Поскольку для отдельной задачи все расчёты и оценки по этому методу можно проделать в уме, это проходит достаточно безболезненно и без больших методологических споров. Имеется также возможность «партизанского» применения этого метода — если задачу оцениваете вы один, как разработчик, и 4-х факторный метод у вас работает, то вам необязательно рассказывать на стендапе всю эту механику.
Нужен план?
Заранее прошу прощения у тех читателей, для которых «планирование» — это ругательное слово. Оставшуюся часть читателей хочу обрадовать, что из метрик выводятся и непосредственные временные оценки, если действовать аккуратно. Стратегически планировать так, наверное, не получится. Однако, одним из преимуществ метода является возможность предварительно оценивать довольно крупные блоки задач.
Планирование с метриками строится на предположении, что задачи по своему будущему фактическому объёму будут соотноситься как их метрика объёма. Конечно, сложность и объём — понятия не эквивалентные, ведь порой лишь часть усилий разработчика направлена на собственно решение задачи. Если вам, помимо программирования, приходится заниматься какой-то малоинтеллектуальной деятельностью, вроде написания тонн XML, ручного неэффективного тестирования или трудоёмкой процедуры деплоя; если вы вдобавок ведете переговоры с заказчиком и пишете манускрипты документации, и все такие занятия неравномерно распределены между задачами — я вам могу лишь посочувствовать. Вам придётся самим придумать, как оценить непрограммистскую и малоинтеллектуальную деятельность. Однако если такой работы немного, – а в хороших проектах её немного, – вполне можно себе позволить считать для целей планирования, что Объём == Сложность, и не вносить дополнительные поправки.
Когда мне приходилось составлять среднесрочные планы, я поступал следующим образом:
- Выделяется некоторый перечень задач и вычисляется наша метрика по каждому пункту.
- Задачи, оценки которых сигнализируют о необходимости изменения или разбиения, разбиваются (критерии — см. «Валидация задач»)
- Дальше мы, ориентируясь на свои интуитивные ощущения, сжимаем или растягиваем этот график по времени, более-менее соблюдая вычисленные пропорции объёма и не допуская возникновения нереалистично выглядящих пунктов.
Конечно, это достаточно наивный подход, – так можно составлять план и без всякой оценки задач, – но результат будет хуже. Метрика помогает тем, что в момент планирования мы видим численные оценки (соотношения между задачами), что страхует нас от искажений и не даёт сократить сроки ниже предела разумного. Выходит, что конечном счете, срок все равно выбирается не механически, а отчасти интуитивно, но при серьезной поддержке со стороны метрики.
Альтернативно, если вы планируете для себя одного, можно поступать проще: вычислить исторически некоторый коэффициент «скорости» и механически вычислять прогноз времени, деля на коэффициент метрику очередной задачи. Но так планировать получается хуже, чем когда вы видите цельную картину. К тому же, калибровка подобного коэффициента — занятие не из приятных. Схожий подход со «скоростью» вполне работает в Scrum с его BurnDown диаграммами, но там он выглядит более эффективным и естественным. Можно сказать, что концепция Scrum Velocity представляет собой более тонко устроенный механизм, чем просто пропорция между объёмом и временем.
Опыт использования
Для небольшой задачи, как показывает практика, оценки и арифметика выполняются в пределах минуты в уме. Для больших компонент требуется чуть большее время, но всё равно метод может выглядеть как быстрый, устный расчёт, дающий приемлемый по точности результат — обычно, более точный, чем интуитивно озвученный прогноз в N дней. Бывали случаи, когда я эти цифры подсчитывал и складывал в уме на митинге, пока мои коллеги из других команд занимались настоящей работой — тайком закрашивали клеточки в Buzzword Bingo.
Едва ли можно назвать этот метод очень простым, но зато он отличается полезной способностью выявлять неявную сложность — даже такую, которая скрывается в плохих библиотеках и инструментах, в плохой архитектуре, в нелинейности трудозатрат, в техническом долге. Отчасти, этому способствует нелинейная арифметика, но в целом выявление скрытой сложности происходит скорее за счёт того, что шкалы оценки не вполне ортогональны: рассмотрите несколько вариаций реальной задачи, и вы заметите, что даже изменения, дающие прирост преимущественно по одной шкале, всё равно отчасти проявляются и в остальных. При этом характерно, что в одних случаях такой перенос проявляется сильно, а в других — слабо. И чем меньше выражен перенос, тем интуитивно проще и легче выглядит соответствующая доработка задачи, не так ли? Формула, действительно, использует то наблюдение, что разнообразные «подводные камни» никогда не проявляются преимущественно по отдельной шкале, но их наличие существенно поднимает вверх одновременно две-три проекции. Нелинейность формулы «ловит» этот эффект, создавая существенную прибавку к рассчитываемому значению.
Из-за этих анатомических деталей, 4-х факторная оценка, хоть и требует больше времени, но почти всегда получается лучше, чем простые оценки «по аналогии» или оценки на основе отдельного фактора.
Сам я практикую этот метод эпизодически уже несколько лет. Моя привязанность к нему вызвана несколькими причинами. Во-первых, при аккуратном применении он даёт заметно более точный прогноз, чем другие примитивные методы. Во-вторых, он достаточно гибко адаптируется к тем или иным методологиям разработки: с некоторой натяжкой его возможно применять и в «чистом» Agile окружении, и в гибридных проектах, и в условно «классическом» проектном менеджменте с Microsoft Project поверх команды программистов. Я также замечал в нём некую приятную масштабируемость — иногда возможно применять подобную оценку не только в малых (bug, story...), но и в более крупных временных масштабах (блок функциональности, компонент). Наконец, метод помогает обучению оценивающего: всегда имеется возможность сравнить фактически состоявшиеся показатели (объем кода, сложность тестирования и т.д.) со своими ранними оценками, и сделать предметные выводы.
∗ ∗ ∗
В своей статье я в принципе не ставил целью обсуждать, нужно ли вообще оценивать задачи в проектах, и нужно ли применять какие-то метрики при разработке ПО, а просто хотел предложить полезный инструмент для тех, у кого такая потребность существует. Меня подкупает то, что при достаточно хороших показателях этот метод малоизвестен; и признаться, мне было бы весьма интересно найти первоначальный источник некоторых из его концепций.
Как научиться оценивать задачи, если не умеешь? Отвечая на этот вопрос, я рассказал о своём любимом методе, который достаточно механистичен, чтобы его мог использовать относительный новичок. Вообще же говоря, методов оценки существуют многие десятки, и если вы желаете изучить эту тему глубже, я бы посоветовал прочитать одну из широко известных книг:
- Стив Макконнелл. Сколько стоит программный проект
- Mike Cohn. Agile Estimating and Planning
Буду рад вашей критике и комментариям.
Автор: Rumega