Процессы итеративные и водопадные

Самая бурная дискуссия о процессах разворачивается вокруг выбора между итеративной и водопадной моделями. Часто эти термины упо­требляются неправильно, в частности потому, что применение итера­тивного процесса вошло в моду, а водопадный процесс считается чем-то вроде брюк в клеточку. В результате процесс разработки многих проектов объявляется итеративным, хотя в действительности он явля­ется процессом водопадного типа.

Существенная разница между двумя этими типами проявляется в том, каким образом проект делится на более мелкие части. Если предпола­гается, что разработка проекта займет год, то мало кто сможет с лег­ким сердцем сказать людям, что им надо уйти на год и вернуться, ко­гда все будет сделано. Необходимо некоторое разделение, чтобы разра­ботчики смогли найти подход к решению проблемы и наладить работу.

При организации работы в стиле водопада проект делится на основа­нии вида работ. Чтобы создать программное обеспечение, необходимо предпринять определенные действия: проанализировать требования, создать проект, выполнить кодирование и тестирование. Наш годич­ный проект может включать двухмесячную фазу анализа, за которой следует четырехмесячная фаза дизайна, а затем трехмесячная фаза кодирования и, наконец, трехмесячная фаза тестирования.

Итеративный стиль делит проект по принципу функциональности про­дукта. Можно взять год и разделить его на трехмесячные итерации. В первой итерации берется четверть требований и выполняется пол­ный цикл разработки программного обеспечения для этой четверти: анализ, дизайн, кодирование и тестирование. К концу первой итера­ции у вас есть система, обладающая четвертью необходимой функцио­нальности. Затем вы приступаете ко второй итерации и через шесть ме­сяцев получаете систему, делающую половину того, что ей положено.

Естественно, приведенное выше описание упрощено, но в этом состоит суть различия. Конечно, на практике к течению процесса добавляются

непредвиденные вредные ручейки.

При разработке способом водопада после каждого этапа обычно в ка­ком-либо виде выполняется формальная сдача, но часто имеет место возвращение назад. В процессе кодирования могут выясниться обстоя­тельства, вынуждающие снова вернуться к этапам анализа и дизайна. Конечно, в начале кодирования не следует думать, что анализ завер­шен. И решения, принятые на стадии анализа и дизайна, неизбежно будут пересматриваться позднее. Однако эти обратные потоки пред­ставляют собой исключения и должны быть по возможности сведены к минимуму.

При итеративном процессе разработки перед началом реальной итера­ции обычно наблюдается некоторая исследовательская активность.


Как минимум на требования будет брошен поверхностный взгляд, до­статочный, по крайней мере, для разделения требований на итерации для последующего выполнения, В процессе такого исследования могут быть приняты некоторые решения по дизайну самого высшего уровня. С другой стороны, несмотря на то что в результате каждой итерации должно появиться интегрированное программное обеспечение, гото­вое к поставке, часто бывает, что оно еще не готово и нужен некоторый стабилизационный период для исправления последних ошибок. Кро­ме того, некоторые виды работ, такие как тренировка пользователей, оставляются на конец.

Конечно, вы вполне можете не передавать систему на реализацию в конце каждой итерации, но она должна находиться в состоянии про­изводственной готовности. Однако часто бывает, что система сдается на регулярной основе; это хорошо, поскольку вы оцениваете работо­способность системы и получаете более качественную обратную реак­цию. В этой ситуации часто говорят о проекте, имеющем несколько версий, каждая из которых делится на несколько итераций.

Итеративную разработку называют по-разному: инкрементной, спи­ральной, эволюционной и постепенной. Разные люди вкладывают в эти термины разный смысл, но эти различия не имеют широкого признания и не так важны, как противостояние итеративного метода и метода водопада.

Возможен и смешанный подход. В книге Мак-Коннелла [31] описыва­ется жизненный цикл поэтапной доставки (staged delivery), в соответ­ствии с которым сначала выполняются анализ и проектирование верх­него уровня в стиле водопада, а затем кодирование и тестирование, разделенные на итерации. В таком проекте может быть четырехмесяч­ный этап анализа и дизайна, а затем четыре двухмесячные итерации построения системы.

Большинство авторов публикаций по процессу создания программно­го обеспечения, особенно принадлежащие к объектно-ориентирован­ному сообществу, последние пять лет испытывают неприязнь к подхо­ду в стиле водопада. Из всего множества причин этого явления самая главная заключается в том, что при использовании метода водопада очень трудно утверждать, что разработка какого-то проекта действи­тельно идет в верном направлении. Слишком легко объявить победу на раннем этапе и скрыть ошибки планирования. Обычно единствен­ный способ, которым вы действительно можете показать, что следуете по такому пути, состоит в том, чтобы получить протестированное, ин­тегрированное программное обеспечение. В случае итеративного про­цесса это повторяется многократно, и в результате, если что-то идет не так, как надо, мы своевременно получаем соответствующий сигнал.

Хотя бы только по этой причине я настоятельно рекомендую избегать метода водопада в чистом виде. По крайней мере, необходимо приме-


нять поэтапную доставку, если невозможно использовать итератив­ный метод в полном объеме.

Объектно-ориентированное сообщество долгое время было приверже­но итеративному способу разработки, и, не боясь ошибиться, можно сказать, что значительная часть разработчиков, участвующих в созда­нии UML, предпочитают в том или ином виде итеративную разработ­ку. Однако, по моим ощущениям, в практике программной индустрии метод водопада все еще занимает ведущее положение. Одну из причин этого явления я называю псевдоитеративной разработкой: исполните­ли объявляют, что ведут итеративное проектирование, а на самом деле действуют в стиле водопада. Основные симптомы этого следующие:

• «Мы выполняем одну итерацию анализа, а затем две итерации про­ектирова-

ния... »

• «Код данной итерации содержит много ошибок, но мы исправим их в конце...*

Особенно важно, чтобы каждая итерация завершалась созданием про­тестированного, интегрированного программного продукта, который бы имел качество, как можно более близкое к качеству серийной про­дукции. Тестирование и интеграцию оценить труднее всего, поэтому в конце разработки проекта лучше эти этапы не проводить. Процесс тестирования следует организовать так, чтобы любая итерация, не объявленная в плане как сдаточная, могла бы быть переведена в такой статус без серьезных дополнительных усилий разработчиков.

Общим приемом при итеративной разработке является упаковка по времени (time boxing). Таким образом, итерация будет занимать фик­сированный промежуток времени. Если обнаружилось, что вы не в со­стоянии выполнить все, что планировали сделать за время итерации, то необходимо выбросить некоторую функциональность из данной ите­рации, но не следует изменять дату исполнения. В большинстве проек­тов, основанных на итеративном процессе, протяженность итераций одинакова, и это позволяет вести разработку в постоянном ритме.

Мне нравится упаковка по времени, поскольку люди обычно испыты­вают трудности при сокращении функциональности. Регулярно прак­тикуясь в сокращении функциональности, они учатся делать осмыс­ленный выбор между изменением времени разработки и изменением функциональности. Сокращение функциональности в ходе итерации позволяет также людям научиться расставлять приоритеты между требованиями к проекту.

Одним из наиболее общих аспектов итеративной разработки является вопрос переделки. Итеративная разработка недвусмысленно предпо­лагает, что вы будете перерабатывать и удалять существующий код на последней итерации проекта. Во многих областях человеческой дея­тельности, например в промышленном производстве, переделка счи­тается ущербом. Но создание программного обеспечения не похоже на


промышленное производство - часто бывает выгоднее переработать

существующий код, чем латать код неудачно спроектированной про­граммы. Некоторые технические приемы способны оказать сущест­венную помощь, чтобы процесс переделки был более эффективным.

• Автоматизированные регрессивные тесты (automated regression tests) позволяют быстро найти любые ошибки, внесенные в процессе изменений. Семейство оболочек тестирования xUnit представляет наиболее подходящий инструмент для создания автоматизирован­ных тестов для модульной проверки (unit tests). Начиная с исход­ного Unit http://junit.org, здесь есть порты для почти всех возмож­ых языков http://www.xprogramming.com/software.htm). Хоро­шим правилом является создание модульных тестов примерно та­кого же размера, что и тестируемая программа.

• Рефакторинг (refactoring) - это способ изменения существующегопрограммного продукта [20]. Механизм рефакторинга основан на применении серии небольших, сохраняющих поведение трансфор­маций основного кода. Многие из этих трансформаций могут быть автоматизированы (http://www.refactoring.com).

• Последовательная интеграция (continuous integration) сохраняет синхронизацию действий разработчиков, объединенных в коман­ду, что позволяет избежать болезненных циклов интеграции [18].В ее основе лежит полностью автоматизированный процесс построе­ния, который может быть автоматически прекращен, как только любой член команды начнет записывать код в базу. Предполагает­ся, что разработчики записывают код ежедневно, поэтому автома­тические сборки выполняются несколько раз в день. Процесс по­строения включает запуск большого блока автоматических регрес­сионных тестов, что позволяет быстро обнаружить и без труда ис­править любую несогласованность.

Все эти технические приемы пропагандировались недавно в книге «Extreme Programming» [2], хотя они применялись и раньше и могли (и должны были) применяться, независимо от того, использовался ли ХР (extreme Programming) или какой-либо другой гибкий процесс.

Прогнозирующее и адаптивное планирование

Одна из причин, по которым метод водопада еще жив, заключается в желании обеспечить предсказуемость при создании программного обеспечения. Ничто так не раздражает, как отсутствие точной оценки стоимости создания программного продукта и сроков его разработки.

Прогнозирующий подход направлен на выполнение работы на началь­ном этапе проекта, для того чтобы лучше понять, что нужно делать в дальнейшем. Таким образом, наступает момент, когда оставшуюся часть проекта можно оценить с достаточной степенью точности. В про­цессе прогнозирующего планирования(predictive planning) проект


разделяется на две стадии. На первой стадии составляются планы, и тут предсказывать трудно, но вторая стадия более предсказуема, по­скольку планы уже готовы.

При этом не надо все делить на белое и черное. В процессе выполнения проекта вы постепенно добиваетесь большей предсказуемости. И даже если у вас есть план, все может пойти не так, как вы спрогнозировали. Вы просто ожидаете, что при наличии четкого плана отклонения будут менее значительными.

Однако все еще идут острые дискуссии о том, много ли проектов могут быть предсказуемыми. Сущность данного вопроса состоит в анализе требований. Одна из самых существенных причин сложности про­граммных проектов заключается в трудности понимания требований к программным системам. Большинство программных проектов под­вергаются существенному пересмотру требований (requirements churn): изменению требований на поздней стадии выполнения проек­та. Такой пересмотр вдребезги разбивает основу прогнозов. Последст­вия пересмотра можно предотвратить, заморозив требования на ран­ней стадии проекта и не позволяя изменениям появляться, но это при­водит к риску поставить клиенту систему, которая больше не удовле­творяет требованиям пользователей.

Эта проблема приводит к двум различным вариантам действий. Один путь - это направить больше усилий собственно на проработку требо­ваний. Другой путь состоит в получении более определенного множе­ства требований, чтобы сократить возможные изменения.

Приверженцы другой школы утверждают, что пересмотр требований неизбежен, что во многих проектах трудно стабилизировать требова­ния в такой степени, чтобы имелась возможность использовать прогно­зирующее планирование. Это может быть либо следствием того, что ис­ключительно трудно представить, что может делать программный про­дукт, либо следствием того, что условия рынка диктуют непредсказуе­мые изменения. Эта школа поддерживает адаптивное планирование (adaptive planning) в соответствии с утверждением, что прогнозируемость - это иллюзия. Вместо того чтобы дурачить себя иллюзорной предсказуемостью, мы должны повернуться лицом к реальности по­стоянных изменений и использовать такой подход в планировании, при котором изменение в проекте считается величиной постоянной. Это изменение контролируется таким образом, чтобы в результате вы­полнения проекта поставлялось как можно лучшее программное обес­печение; но хотя проект и контролируем, предсказать его нельзя.

Различие между прогнозирующими и адаптивными проектами прояв­ляется разными путями, когда люди говорят о состоянии проекта. Ког­да утверждается, что выполнение проекта идет хорошо, поскольку ра­бота ведется в соответствии с планом, то имеется в виду метод прогно­зирования. При адаптивной разработке нельзя сказать «в соответствии с планом», поскольку план все время меняется. Это не означает, что


адаптивные проекты не планируются; обычно планирование занимает значительное время, но план трактуется как основная линия проведе­ния последовательных изменений, а не как предсказание будущего.

На основе прогнозирующего плана можно разработать контракт с фик­сированной функциональностью по фиксированной цене. В таком контракте точно указывается, что должно быть создано, сколько это стоит и когда продукт будет поставлен. В адаптивном плане такое фик­сирование невозможно. Вы можете обозначить бюджет и сроки постав­ки, но вы не можете точно зафиксировать функциональность постав­ляемого продукта. Адаптивный контракт предполагает, что пользова­тели будут сотрудничать с командой разработчиков, чтобы регулярно пересматривать требуемую функциональность и прерывать проект, ес­ли прогресс слишком незначителен. Как таковой процесс адаптивного планирования может определять проект с переменными границами функциональности по фиксированной цене.

Естественно, адаптивный подход менее желателен, поскольку все предпочитают большую предсказуемость программных проектов. Од­нако предсказуемость зависит от точности, корректности и стабильно­сти множества требований. Если вы не в состоянии стабилизировать свои требования, то прогнозирующий план базируется на песке, а из­менения настолько значительны, что проект сбивается с курса. Отсю­да вытекают два важных совета.

1. Не составляйте прогнозирующий план до тех пор, пока не получите
точные и корректные требования и не будете уверены, что они не
подвергнутся существенным изменениям.

2, Если вы не можете получить точные, корректные и стабильные тре­
бования, то используйте метод адаптивного планирования.

Предсказуемость и адаптивность предоставляют выбор жизненного цикла. Адаптивное планирование совершенно определенно подразуме­вает итеративный процесс. Прогнозирующий план может быть выпол­нен любым из двух способов, хотя за его выполнением легче наблюдать в случае применения метода водопада, или метода поэтапной поставки.