Книга: Джоэл и снова о программировании
Назад: Часть пятая. Советы программистам
Дальше: Глава двадцать первая. Шестое письмо о стратегии

Глава двадцатая. Планирование с учетом прежних результатов (EBS)

26 октябpя 2007 года, пятница

Программист не очень любит составлять график работ (schedule). Обычно он пытается как-то этого избежать. «Как только — так сразу!» — говорит он, надеясь таким смелым и остроумным ответом вызвать улыбку на лице босса, чтобы тот, повеселев, забыл про график.
Если вы все же видите какие-то графики, то, в основном, сделанные без всякого энтузиазма. Хранят их в каком-нибудь забытом месте на файловом сервере. Когда, с опозданием на пару лет, команда все-таки выпускает продукт, приходит этот странный малый, у которого в кабинете стоит шкаф с папками, и подводит итог, читая старую распечатку, чем вызывает всеобщее веселье. «Надо же! Мы хотели за две недели переписать все на Ruby!»
Очень смешно! Если, конечно, вы еще не обанкротились...
Нужно тратить время на то, что приносит максимум результатов на каждый вложенный доллар. И вы не сможете определить, во сколько долларов вам обойдется этот результат, если не будете знать, сколько времени займет ваша работа. Выбирая между реализацией «анимационной канцелярской скрепки» и «дополнительных финансовых функций», вы обязаны знать, сколько времени потребуется в каждом случае.
Почему программисты не хотят составлять график разработки? Тому есть две причины. Во-первых, график — это головная боль. Во-вторых, никто не верит, что график может быть реалистичным. Зачем мучиться с планированием, если на практике все будет по-другому?
В течение прошлого года или около того мы в Fog Creek разрабатывали систему, столь простую, что даже самые ворчливые из наших разработчи-
ков согласились ее применять. По нашему мнению, она позволяет создавать на редкость реалистичные планы проектов. Мы назвали ее Evidence-Based Scheduling (планирование с учетом прежних результатов), сокращенно EBS. Вы собираете факты, в основном из данных учета времени в прежних проектах, и учитываете их при составлении графика. В результате вы получаете не одну дату готовности продукта, а кривую вероятности завершения работы в каждый конкретный день. Это выглядит примерно так:
Чем круче кривая, тем больше уверенности в реальности даты поставки (Ship Date).
Вот как это делается.

1. Разбейте на куски

Глядя на график проекта, расписанный по дням или даже неделям, я знаю, что он не будет выполнен. Нужно разбить график на такие мелкие задачи, чтобы они измерялись в часах. Не более 16 часов каждая.
Это заставит вас реально определить, что вы намерены сделать. Написать такую-то подпрограмму. Создать вот это диалоговое окно. Организовать синтаксический разбор такого-то файла. Отдельные задачи разработки проще оценить, потому что вы когда-то уже писали подпрограммы, создавали диалоговые окна и анализировали файлы.
Если вы, не размениваясь по мелочам, небрежно определяете задачи на три недели вперед, — например «написать Ajax-редактор фотографий», -значит вы не продумали, что будете делать. В деталях. Шаг за шагом. А не продумав, что надо делать, вы не можете знать, сколько времени это у вас займет.
Установление 16-часового предела заставит вас спроектировать эту чертову штуку. Если вы отводите три недели на нечто неопределенное под названием «Ajax-редактор фотографий» без детального проекта, с глубоким прискорбием вынужден довести до вашего сведения, что вы обречены. Вы не обдумали шаги, необходимые для решения задачи, и наверняка пропустите многие из них.

2. Ведите учет затраченного времени

Сложно точно определить индивидуальные затраты времени. Как учесть отвлечения, непредсказуемые баги, совещание для обсуждения хода проекта или совершаемое раз в полгода жертвоприношение Windows, во время которого вам приходится целиком переустанавливать основную машину, на которой ведутся разработки? Да и без всего этого — как вы можете точно узнать, сколько времени займет реализация какой-либо подпрограммы? Да никак.
Так что ведите учет времени. Отслеживайте, сколько времени вы тратите на каждую задачу. Тогда позднее вы сможете сравнить реальное время со своей оценкой. Каждый разработчик должен собрать данные такого типа:
Каждая точка на диаграмме — это завершенная задача в координатах запланированного (Estimated Hours) и фактически потраченного (Actual Hours) времени. Поделив оценку на фактическое время, вы получите скорость: насколько быстро задача была решена в сравнении с планом. Со временем у вас накопятся массивы таких данных по каждому разработчику.
Мифический идеальный оценщик, существующий только в нашем воображении, всегда точно определяет необходимое ему время. Его набор скоростей: {1; 1;1; 1; 1; ...}.
Типичный плохой оценщик раскидает точки по всей координатной сетке, например вот так: {0,1; 0,5; 1,7; 0,2; 1,2; 0,9; 13,0}.
Большинство исполнителей плохо определяют масштаб, но их относительные оценки правильны. Все задачи выполняются дольше, чем рассчитывалось, потому что оценка не учитывает исправление ошибок, совещаний комиссии, кофе-брейки и ненормального босса, который все время отвлекает. У этого стандартного оценщика скорости весьма постоянны, хотя и не дотягивают до 1, например: {0,6; 0,5; 0,6; 0,6; 0,5; 0,6; 0,7; 0,6}.
По мере приобретения опыта точность оценки растет. Так что можете смело выкинуть показатели, скажем, полугодовой давности.
Однако если в вашей команде появился новый разработчик, данных о скорости работы которого у вас нет, следует исходить из худшего варианта: назначьте ему какой-нибудь фиктивный набор скоростей с большим разбросом до тех пор, пока он не выполнит с полдюжины реальных задач.

3. Моделируйте будущее

Вместо того чтобы складывать оценки для получения точной даты поставки (что кажется правильным, но дает слишком неточные результаты), лучше смоделировать возможные исходы с помощью метода Монте-Карло. При этом вы берете 100 сценариев возможного развития событий, каждый из которых имеет вероятность 1%, и строите график вероятности готовности к поставке для любой даты.
Рассчитывая каждый возможный вариант развития событий для конкретного разработчика, нужно разделить оценку для каждой задачи на выбранную случайным образом скорость из данных по этому разработчику, собранных вами на шаге 2. Вот возможный пример:
Проделайте это 100 раз. Вероятность каждой суммы 1%, и теперь вы можете оценить вероятность поставки для каждой заданной даты.
А теперь посмотрите, что получилось.
Для мифического идеального оценщика все скорости равны 1. Деление на 1 ничего не меняет. Поэтому все циклы моделирования дают одну и ту же дату окончания проекта, и ее вероятность 100%. Просто сказка!
У плохого оценщика скорости разбросаны по всему пространству. Может встретиться и 0,1, и 13,0. Результаты всех циклов будут сильно различаться, потому что при делении на случайно выбранные значения скорости получатся весьма различные числа. Кривая распределения вероятности, которую вы получите, будет очень пологой, показывая равную вероятность завершения работ как завтра, так и в отдаленном будущем. Но это тоже ценная информация: она говорит, что предположительной дате поставки доверять нельзя.
Стандартный оценщик располагает набором очень близких скоростей, например: {0,6; 0,5; 0,6; 0,6; 0,5; 0,6; 0,7; 0,6}. При делении на эти значения вы увеличиваете продолжительность выполнения задачи, поэтому в одной итерации вместо 8 часов получится 13, а в другой, скажем, 15. Это компенсирует неизменный оптимизм разработчика. Причем компенсирует точно, исходя из доказанности и проверен-ности исторически зафиксированной меры его оптимизма. И поскольку все эти зарегистрированные скорости весьма близки (их значение колеблется около 0,6), в каждом цикле моделирования вы получите довольно близкие значения, а в итоге — довольно узкий интервал для возможной даты поставки.
На каждом этапе моделирования по методу Монте-Карло вы, конечно, должны переводить данные из рабочих часов в рабочие дни, то есть нужно принять в расчет график работы каждого разработчика, его отпуск, праздники и так далее. И в каждом цикле вы должны посмотреть, кто из разработчиков завершит работу последним, потому что это и будет датой завершения проекта командой в целом. Эти подсчеты довольно трудоемки, но, к счастью, как раз для такой работы существуют компьютеры.

Не нужно синдрома навязчивых состояний

Что делать с боссом, который постоянно отвлекает вас нескончаемыми рассказами о рыбалке? Или с совещаниями по продажам, на которые вы должны ходить, хотя делать вам там нечего? С чаепитиями? С необходимостью потратить полдня, помогая новому сотруднику установить нужные программы?
Когда мы с Бреттом разрабатывали технологию планирования в Fog Creek, нас сильно беспокоило, что есть отнимающие много времени вещи, предвидеть которые невозможно. Иногда они вместе съедают больше времени, чем уходит на написание кода. Может быть, для них сделать такие же оценки, ведя учет реального времени?
Можно поступить и так, если хотите. Система EBS сработает и в этом случае.
Но вам необязательно делать это.
Дело в том, что EBS настолько эффективна, что вам достаточно не останавливать отсчет времени, когда возникло отвлечение. Как ни странно, в этом случае EBS работает даже лучше.
Приведу короткий пример. Чтобы максимально его упростить, представим себе программиста Джона, который работает с хорошо предсказуемой скоростью и задача которого — писать однострочные функции чтения и записи значений на одном из этих недоразвитых языков программирования. Вот код, который он пишет изо дня в день:
private int width;
public int getWidth () { return width; }
public void setWidth (int _width} { width = _width; }
Знаю, знаю, это крайне тупой пример. Но нечто подобное наверняка встречалось вам и в реальной жизни.
Тем не менее. На каждую функцию у Джона уходит 2 часа. Таким образом, оценка длительности задач выглядит для него так:
{2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; ... }
Теперь представим, что у этого бедняги есть начальник, который время от времени затевает с ним двухчасовую беседу об особенностях ловли тунца. Конечно, Джон мог бы внести в свой график работы пункт «Тягомотина с тунцом» и зафиксировать потраченное на это время, но с его стороны это было бы неблагоразумно. Вместо этого Джон просто продолжает отсчет времени, и его график начинает выглядеть так:
{2; 2; 2; 2; 4; 2; 2; 2; 2; 4; 2; ... }
А показатели скорости разработки, соответственно, так:
{1; 1; 1; 1; 0,5; 1; 1; 1; 1; 0,5; 1;... }
Теперь посмотрим, что происходит. При оценке методом Монте-Карло вероятность того, что оценка будет поделена на 0,5, равна вероятности того, что босс прервет работу Джона над каждой из задач. То есть EBS даст правильный график!
На самом деле, EBS гораздо точнее отражает всевозможные отвлечения, чем какой-нибудь одержимый учетом времени программист. Вот почему она так эффективна. Я объясняю этот факт следующим образом. Когда разработчика отвлекают от работы, он может поступить по-разному:
1.    Поднять шум и потребовать зарегистрировать отвлечение в учете времени и в оценках, чтобы руководство знало, сколько времени отняли разговоры о рыбалке.
2.    Поднять шум, что эти отвлечения не учитываются как рабочее время, если он не выполнил работу к положенному сроку, потому что ему не дают скорректировать его абсолютно точную оценку на время дурацких разговоров о рыбалке, на которую его даже не пригласили.
В любом случае, EBS предоставляет одинаково точные результаты независимо от того, пассивны или агрессивны ваши разработчики.

4. Активно управляйте своими проектами

Организовав такую систему, вы можете активно управлять своими проектами, добиваясь их своевременного завершения. Например, отсортировав функции по приоритетности, легко выяснить, как отказ от реализации маловажных функций может помочь своевременной поставке продукта.
Можно также узнать распределение вероятных дат окончания работ для каждого программиста:
Некоторые разработчики (как Милтон на приведенной иллюстрации) могут создавать проблемы, поскольку дата окончания работ у них оказывается весьма неопределенной: им нужно учиться точнее планировать свою работу. Другие разработчики (как Джейн) очень точно определяют дату завершения своей работы, но она выходит за рамки предельного срока, поэтому придется снять с них часть задач. Другие разработчики (вот! это я!) не участвуют в критическом пути, и их можно оставить в покое.

Расползание границ проекта

Если в начале работы вы спланировали все до последней детали, то EBS работает прекрасно. Но иногда добавляются изначально не запланированные функции. Это происходит, если у вас возникают новые идеи, или агенты по продажам начинают рекламировать то, чего нет в продукте, или кому-то из совета директоров пришла гениальная идея добавить электрокардиограф в ваше GPS-приложение для электромобиля, перевозящего игроков по площадке для гольфа. В результате возникают задержки, которые вы не могли предвидеть при создании первоначального графика.
В идеале, можно запланировать резервное время для разных случаев. Действительно, почему бы не ввести в график резерв для следующих нужд:
1. Новые функции.
2. Ответ на действия конкурентов.
3. Интеграция (настройка совместной работы кода разных разработчиков после его объединения).
4. Отладка.
5. Юзабилити-тестирование (и внесение по его итогам доработок в продукт).
6. Бета-тестирование.
Теперь, если понадобится добавить новые функции, можно выделить время для них из соответствующего резерва.
Как быть, если нужно добавить новые функции, а резервы исчерпаны? Дата окончания работ, рассчитываемая с помощью EBS, начнет запаздывать в сравнении с предельным сроком. Чтобы обнаружить это, нужно пересчитывать распределение вероятной даты окончания проекта в конце каждого рабочего дня:
По оси X откладывается дата проведения расчета, а по оси Y — дата готовности продукта к поставке. Три кривые — это графики: верхний — дата поставки с вероятностью 95%, средний — с вероятностью 50%, нижний -с вероятностью 5%. Чем ближе кривые друг к другу, тем меньше разброс вероятной даты поставки.
Если дата завершения работ отодвигается все дальше и дальше (кривая идет вверх), то у вас проблемы. Если каждый день задержка увеличивается больше чем на сутки, значит, вы наращиваете объем задач быстрее, чем решаете их, и так вы вообще никогда не завершите проект. Можно также узнать, сужается ли доверительный интервал для даты поставки (графики сближаются), что должно происходить, если ваш проект наверняка выходит на окончание к определенному сроку.

Дополнительные замечания

Вот еще несколько вещей, которые я выяснил за годы составления графиков работ:
1. Только программист, занятый конкретной задачей, может оценить сроки ее выполнения. Любая система, где график работ составляют менеджеры, спуская его программистам, обречена на провал. Только программист, который будет реализовывать функцию, может определить, какие действия ему при этом потребуются.
2. Найденные ошибки нужно исправлять сразу, а время на исправление учитывать как потраченное на задачу. Нельзя заранее планировать исправление ошибок, потому что вы не знаете, когда и ка-
кие ошибки обнаружатся. Время на исправление ошибок в новом коде — часть времени решения исходной задачи, которая была неправильно реализована. В этом случае с помощью EBS вы можете оценить время разработки полностью отлаженного, а не просто работающего, кода.
3. Не позволяйте менеджерам требовать от разработчиков сокращенных оценок. Многие неопытные менеджеры думают, что могут «мотивировать» программистов работать быстрее, дав им сжатые (нереально короткие) сроки. Я считаю такой способ мотивации просто глупостью. Отставая от графика, я чувствую себя убитым, подавленным и немотивированным. Работая с опережением, я чувствую себя бодрым и продуктивным. График — не место для психологических экспериментов.
Почему же менеджеры делают такие попытки?
В начале проекта технические менеджеры встречаются с представителями бизнеса и составляют список функций, реализация которых, как им кажется, потребует месяца три, хотя на самом деле уйдут все двенадцать. Когда вы думаете о том, что нужно бы написать код, но не обдумываете все этапы, всегда оказывается, что предполагаемое время n на практике превращается в 4n. Составляя настоящий график, вы суммируете все задачи и обнаруживаете, что проект займет гораздо больше времени, чем предполагалось. Представителей бизнеса это не радует.
Плохой менеджер пытается найти выход в том, чтобы заставить людей работать быстрее. Но это не жизненно. Можно набрать больше людей, но им нужно время, чтобы войти в курс дела, а до того они в течение нескольких месяцев будут работать вполовину максимальных возможностей (и при этом снижать эффективность тех, кто будет их учить).
Возможно, вам удастся временно выжать из своих людей на 10% больше сырого кода, но при этом за год они «выгорят» на 100%. Невелико достижение — все равно что рубить сук, на котором сидишь. И, конечно, когда люди перерабатывают, удваивается время на исправление ошибок, и проект лишь запаздывает еще больше. Отличная карма.
Но что вам точно не удастся, так это сделать 4n из n, и если вы думаете, что это не так, пришлите мне, пожалуйста, код акций вашей компании — я сыграю на понижение.
4. График — это коробка с деревянными брусками. Если у вас есть несколько таких брусков, и они не помещаются в коробку, выхода два: взять коробку побольше или выкинуть несколько брусков. Если вы хотите завершить проект за 6 месяцев, но по графику получается 12, придется либо перенести срок завершения, либо отказаться от реализации каких-то функций. Сжать бруски нельзя, а если вам кажется, что можно, то вы просто обманываете себя и лишаетесь реальной возможности заглянуть в будущее.
Раз уж я заговорил об этом, отмечу, что реалистичное планирование хорошо еще и тем, что вынуждает вас избавляться от лишних функций. Почему это хорошо?
Предположим, вы задумали две функции. Одна из них действительно полезна и даст вашему продукту большие преимущества. Другая очень проста, и программистам не терпится начать писать ее код, хотя никакой пользы в ней нет.
Если не составить график работ, программисты сначала возьмутся за то, что делать легче/интереснее. При этом они выбьются из графика, и вам придется переносить срок поставки, чтобы реализовать полезную/важную функцию.
Если же составить график, то даже до начала работы вы поймете, что нужно что-то сократить, и сократите вы легкое/интересное, чтобы сделать полезное/важное. Заставив себя отказаться от маловажных функций, вы создадите более мощный, качественный продукт, с лучшим набором функций и за меньшее время.
Когда в далеком прошлом я работал над Excel 5, сначала у нас был громадный перечень подлежащих реализации функций, с которым мы намного превысили бы отведенные сроки. «Господи, — думали мы, — но они же все совершенно необходимы! Разве можно обойтись без помощника для редактирования макросов?»
Как выяснилось, выбора у нас не было, и для соблюдения сроков мы, как нам казалось, обглодали проект до костей. Все очень переживали из-за этого. Чтобы поднять настроение, мы объясняли себе, что не отказываемся от этих функций навсегда, а просто переносим их на следующую, шестую версию Excel.
Когда работа над пятой версией уже близилась к завершению, я и мой коллега Эрик Михельман (Eric Michelman) начали разработку спецификаций для шестой версии. Мы стали проверять список того, что было исключено из пятой версии в расчете включить это в шестую. И знаете, что? Это был совершенно идиотский список. Ни одну из тех функций не стоило реализовывать ни тогда, ни раньше. Мы очень правильно поступили, отобрав только те функции, которые позволяли нам уложиться в сроки. В ином случае Excel 5 писался бы вдвое дольше, а половина его функций была бы никому не нужна, но их поддержку — в целях обратной совместимости — пришлось бы осуществлять до скончания времен.

Заключение

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

P.S.

Система Evidence-Based Scheduling встроена в FogBugz 6.

 

Назад: Часть пятая. Советы программистам
Дальше: Глава двадцать первая. Шестое письмо о стратегии