Процессы итеративные и водопадные
Самая бурная дискуссия о процессах разворачивается вокруг выбора между итеративной и водопадной моделями. Часто эти термины употребляются неправильно, в частности потому, что применение итеративного процесса вошло в моду, а водопадный процесс считается чем-то вроде брюк в клеточку. В результате процесс разработки многих проектов объявляется итеративным, хотя в действительности он является процессом водопадного типа.
Существенная разница между двумя этими типами проявляется в том, каким образом проект делится на более мелкие части. Если предполагается, что разработка проекта займет год, то мало кто сможет с легким сердцем сказать людям, что им надо уйти на год и вернуться, когда все будет сделано. Необходимо некоторое разделение, чтобы разработчики смогли найти подход к решению проблемы и наладить работу.
При организации работы в стиле водопада проект делится на основании вида работ. Чтобы создать программное обеспечение, необходимо предпринять определенные действия: проанализировать требования, создать проект, выполнить кодирование и тестирование. Наш годичный проект может включать двухмесячную фазу анализа, за которой следует четырехмесячная фаза дизайна, а затем трехмесячная фаза кодирования и, наконец, трехмесячная фаза тестирования.
Итеративный стиль делит проект по принципу функциональности продукта. Можно взять год и разделить его на трехмесячные итерации. В первой итерации берется четверть требований и выполняется полный цикл разработки программного обеспечения для этой четверти: анализ, дизайн, кодирование и тестирование. К концу первой итерации у вас есть система, обладающая четвертью необходимой функциональности. Затем вы приступаете ко второй итерации и через шесть месяцев получаете систему, делающую половину того, что ей положено.
Естественно, приведенное выше описание упрощено, но в этом состоит суть различия. Конечно, на практике к течению процесса добавляются
непредвиденные вредные ручейки.
При разработке способом водопада после каждого этапа обычно в каком-либо виде выполняется формальная сдача, но часто имеет место возвращение назад. В процессе кодирования могут выясниться обстоятельства, вынуждающие снова вернуться к этапам анализа и дизайна. Конечно, в начале кодирования не следует думать, что анализ завершен. И решения, принятые на стадии анализа и дизайна, неизбежно будут пересматриваться позднее. Однако эти обратные потоки представляют собой исключения и должны быть по возможности сведены к минимуму.
При итеративном процессе разработки перед началом реальной итерации обычно наблюдается некоторая исследовательская активность.
Как минимум на требования будет брошен поверхностный взгляд, достаточный, по крайней мере, для разделения требований на итерации для последующего выполнения, В процессе такого исследования могут быть приняты некоторые решения по дизайну самого высшего уровня. С другой стороны, несмотря на то что в результате каждой итерации должно появиться интегрированное программное обеспечение, готовое к поставке, часто бывает, что оно еще не готово и нужен некоторый стабилизационный период для исправления последних ошибок. Кроме того, некоторые виды работ, такие как тренировка пользователей, оставляются на конец.
Конечно, вы вполне можете не передавать систему на реализацию в конце каждой итерации, но она должна находиться в состоянии производственной готовности. Однако часто бывает, что система сдается на регулярной основе; это хорошо, поскольку вы оцениваете работоспособность системы и получаете более качественную обратную реакцию. В этой ситуации часто говорят о проекте, имеющем несколько версий, каждая из которых делится на несколько итераций.
Итеративную разработку называют по-разному: инкрементной, спиральной, эволюционной и постепенной. Разные люди вкладывают в эти термины разный смысл, но эти различия не имеют широкого признания и не так важны, как противостояние итеративного метода и метода водопада.
Возможен и смешанный подход. В книге Мак-Коннелла [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, Если вы не можете получить точные, корректные и стабильные тре
бования, то используйте метод адаптивного планирования.
Предсказуемость и адаптивность предоставляют выбор жизненного цикла. Адаптивное планирование совершенно определенно подразумевает итеративный процесс. Прогнозирующий план может быть выполнен любым из двух способов, хотя за его выполнением легче наблюдать в случае применения метода водопада, или метода поэтапной поставки.