Переход от каскадной разработки к итеративной

Per Kroll, Director, Rational Unified Process, IBM

Оглавление

Из журнала Rational Edge: Модель совершенной методологии итеративной разработки во многом радикально отличается от совершенной модели каскадной разработки. Но на практике ни одна группа разработчиков не применяет эти подходы строго в соответствии с их моделями. В этой статье объясняется, почему группам может потребоваться плавный переход от каскадного к итеративному подходу; также указаны некоторые полезные шаги в этом направлении.

Большинство групп разработчиков используют в своих проектах каскадный (waterfall - водопад, каскад) процесс. В чистом виде каскадный подход означат выполнение ряда фаз в строго определенном порядке: анализ требований, проектирование, выполнение/интеграция, тестирование. Тестирование откладывается до конца проекта, когда проблемы накапливаются настолько, что на их решение требуется много сил и времени; эти проблемы могут сорвать сроки выполнения проекта и надолго оставить ключевых членов группы без работы.

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

Преимущества итеративного похода

При итеративном подходе, например, в принятом компанией IBM процессе Rational Unified Process (сокращенно RUP), выполняется последовательность шагов, которые называются итерациями. Каждая итерация включает в себя часть (иногда большую) стадий разработки (сбор требований, анализ, проектирование, выполнение и т. д.), показанных на рис. 1. Каждая итерация имеет четко определённый набор целей, а ее завершение обеспечивает частичную рабочую версию конечной системы. Каждая очередная итерация строится на основе предыдущих итераций, далее развивает, уточняет и совершенствует систему до завершения конечного продукта.

На первых итерациях главное внимание уделяется требованиям к системе, а также анализу и проектированию; на завершающих итерациях главное внимание уделяется реализации и тестированию.

Рис. 1. Итеративная разработка по методологии RUP. На каждой итерации выполняются: учет требования, анализ, проектирование, тестирование. Каждая итерация строится на основе предыдущих итераций; ее результатом является исполняемый файл, который на один шаг ближе к конечному продукту.

Итеративный подход имеет преимущества над каскадным подходом по ряду следующих причин.

  • Он позволяет учитывать изменяющиеся требования. Изменение требований, добавление функций по требованиям технологии или заказчика - это всегда было главным источником трудностей при выполнении проектов, из-за чего задерживались сроки завершения, разочаровывались заказчики, приходили в отчаяние разработчики. Чтобы избежать таких проблем, группы разработчиков, применяющие итеративный подход, стремятся в первые же недели создать и продемонстрировать заказчику работающее программное обеспечение, чтобы уточнить требования и лучше вникнуть в суть дела.
  • Интеграция перестает быть авралом в конце проекта. Откладывание интеграции до конца проекта почти всегда приводит к дополнительным затратам времени на переделку, иногда до 40% от всего времени проекта. Чтобы избежать этого, каждая итерация обязательно заканчивается интеграцией компоновочных блоков, что минимизирует в будущем затраты на переделку.
  • Первые итерации выявляют риски. Итеративный подход помогает группе разработчиков уменьшить риски на первых итерациях, на которых выполняется тестирование всех компонентов процесса. Поскольку в каждую итерацию вовлечено много аспектов проекта (инструменты, готовое программное обеспечение, квалификация членов группы разработчиков и т. д.), группа имеет возможность быстро понять, насколько реальны предполагавшиеся риски, и выявить новые риски, о которых ранее не подозревали, причем сделать это еще на ранней стадии, когда проблемы можно устранить относительно легко и дешево.
  • Руководство может вносить в продукт тактические изменения. При итеративной разработке быстро создается действующая архитектура (хотя и с ограниченным набором функций), которая может быть легко преобразована в "облегченную" или "модифицированную" версию продукта с целью опередить конкурентов.
  • Упрощается выявление общих участков кода. Общие участки кода легче выявить не на стадии планирования, а когда они частично спроектированы или уже написаны при очередной итерации. Анализ плана проекта на первых итерациях позволяет архитектору найти потенциальные возможности, которые могут использоваться различными компонентами системы, а затем разработать и дорабатывать общий код этих возможностей во время последующих итераций.
  • За несколько итераций можно найти и устранить дефекты. В результате достигается надежная архитектура и высокое качество приложения. Дефекты можно обнаружить уже на ранних итерациях, а не на фазе массового тестирования в конце проекта. Кроме того, на первых итерациях можно найти узкие места, ограничивающие быстродействие, которые легче исправить на ранней стадии, не нарушая графика проекта и не создавая паники накануне срока поставки.
  • Лучше организована работа участвующих в проекте сотрудников. Многие организации, применяющие каскадный подход, работают по конвейерной схеме: аналитик передает составленные им требования проектировщикам, те в свою очередь передают составленный ими план проекта программистам, те передают компоненты интеграторам, а далее система передается на тестирование. При этих передачах происходят ошибки, но беда не только в этом - сотрудники не чувствуют особой личной ответственности за конечный продукт. А при итеративном процессе сотрудники имеют более разнообразные обязанности, и выполняют много ролей. Руководитель проекта имеет возможность более эффективно загружать работой своих сотрудников и устранять риски при передаче материалов от одной ступени к другой.
  • Члены группы постоянно учатся. При итеративном процессе разработки есть много возможностей исправлять свои ошибки и повышать свою квалификацию от одной итерации к другой. Оценивая очередную итерацию, руководитель проект может найти возможности обучить членов группы полезным навыкам. В каскадных проектах дело обстоит иначе - каждый узкий специалист занят только своим делом - проектированием, написанием кода или тестированием.
  • Процесс разработки можно совершенствовать на протяжении всего проекта. Оценки результатов очередной итерации не только показывают состояние проекта с точки зрения готовности продукта или выполнения графика работ, но также помогают руководителям понять, как улучшить организацию и процесс следующей итерации.

Некоторые руководители проектов не хотят применять итеративный подход, потому что считают его формой бесконечной и неуправляемой возни. Но в процессе RUP весь проект полностью управляем. Количество итераций, их длительность и цели - всё это тщательно планируется, задачи и ответственности участников четко определены. Кроме того, регистрируются объективные показатели прогресса. И хотя группа переделывает некоторые вещи от одной итерации к другой, эта работа тщательной контролируется.

Четыре шага перехода

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

  • Сначала создаются функциональные (действующие) прототипы.
  • Фазы подробного проектирования, выполнения и тестирования делятся на итерации.
  • На раннем этапе создается базовая версия действующей архитектуры.
  • Применяется итеративный процесс с управлением на основе рисков.

Рассмотрим эти шаги более подробно.

Шаг 1. Создание функциональных прототипов на раннем этапе

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

Следует начать с трёх самых больших технических рисков и трёх самых крупных функциональных областей, которые нужно прояснить. Технические риски могут быть связаны с новой технологией, возможными технологическими решениями, которые значительно повлияют на всё решение в целом, а также с трудновыполнимыми техническими требованиями. Функциональные риски могут быть связаны с теми областями, в которых заказчики выдвинули нечёткие требования и критически важным функциям, а также с теми требованиями, которые имеют первостепенное значение для всей системы.

Для каждого ключевого технического риска нужно спланировать прототип с целью уменьшить этот риск. Рассмотрим следующие примеры.

Технический риск. В ходе выполнения проекта требуется перенести существующее приложение, чтобы оно могло работать поверх сервера IBM WebSphere Application Server. Пользователи уже жалуются на недостаточное быстродействие приложения, поэтому у вас есть подозрение, что вышеуказанный перенос может ещё более замедлить работу приложения.

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

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

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

Шаг 2. Деление фаз подробного проектирования, выполнения и тестирования на итерации

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

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

Подход 1. Разработка подсистем по одной или по несколько одновременно. Предположим, у вас есть девять подсистем, причем в каждой множество компонентов. Вы можете разделить фазы подробного проектирования, выполнения и тестирования на три итерации, каждая из которых нацелена на три из девяти подсистем. Это хорошо в том случае, если зависимости между подсистемами не слишком велики. Например, ваши девять подсистем должны предоставлять конечным пользователям четко определенный набор возможностей. На первой итерации можно разработать самые важные подсистемы, на второй итерации - менее важные, а на третьей - ещё менее важные. Такой подход имеет большое преимущество: если вы не успеете завершить проект к назначенному сроку, то хотя бы сделаете часть системы с наиболее важными функциями, причём эта часть будет действующей.

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

Подход 2. В первую очередь разрабатываются наиболее критически важные сценарии. При подходе 1 подсистемы разрабатываются последовательно по одной. А при подходе 2 главное внимание уделяется ключевым сценариям или, иначе говоря, ключевым способам использования системы, а затем добавляются остальные сценарии, менее важные. Насколько это отличается от подхода 1? Рассмотрим пример.

Предположим, вы создаёте новое приложение, которое позволит заказчику вести работу с дефектами. Это многоуровневое приложение, которое будет работать поверх сервера WebSphere Application Server, а системой управления базами данных будет DB2. На первой итерации вы разрабатываете ряд сценариев, например, ввод простого дефекта без дополнительной информации. На второй итерации вы усложняете эти сценарии, например, дефект может влиять на последовательность производственных операций. На третьей итерации завершается создание набора функций ввода дефектов и обеспечивается полная поддержка нестандартных пользовательских записей, например, возможность сохранить частичную запись о дефекте, чтобы впоследствии вернуться к ней и продолжить работу с ней.

При таком подходе вы работаете со всеми подсистемами на всех итерациях, но на первой итерации главное внимание уделяется самым важным вещам, а на последних итерациях внимание уделяется менее важным и менее трудным вещам.

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

Шаг 3. Создание базовой версии действующей архитектуры на раннем этапе

Этот шаг можно рассматривать как более формальный и организованный шаг 1: Создание функциональных прототипов на раннем этапе Что такое "действующая архитектура"?

Действующая архитектура - это частичная реализация системы, созданная с целью продемонстрировать, что подобная архитектура способна поддерживать ключевые функции. Но более важно то, что при этом демонстрируется способность архитектуры удовлетворить требованиям по быстродействию, пропускной способности, объёму данных, надёжности, масштабируемости и т. д. Создание действующей архитектуры позволяет на следующих фазах уверенно строить на прочном фундаменте все функциональные возможности системы. Действующая архитектура - это эволюционный прототип, который в ходе своей эволюции будет сохранять проверенные функции и те функции, которые с высокой вероятностью удовлетворят требованиям к системе, когда архитектура будет завершена. Говоря другими словами, эти функции станут частью завершенной системы. В отличие от функционального прототипа, который создаётся на шаге 1, эволюционный прототип полностью охватывает все вопросы архитектуры.

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

Но как придумать архитектуру эволюционного прототипа? Главное - сконцентрироваться на самых важных вариантах использования, примерно от 20% до 30% всех услуг, которые системы должна предоставлять конечным пользователям. Далее приведены некоторые способы для определения самых важных вариантов использования.

  • Функциональность - это ядро приложения, она зависит от ключевых интерфейсов. Архитектуру системы должен определять её ключевой набор функций. Обычно архитектор выявляет наиболее важные варианты использования, анализируя множество факторов: стратегия управления избыточностью, риск конфликта между ресурсами, риск недостаточно высокой производительности, стратегии защиты данных и т. д. Например, в системе, предназначенной для торговой точки, ключевыми вариантами использования будут следующие: а) подсчёт стоимость всех покупок и выдача чека, б) оплата; потому что система проверяет интерфейс к системе проверки кредитных карт - это критически важно с точки зрения быстродействия и способности выдерживать большую нагрузку.
  • Выбор вариантов использования, описывающих обязательные функции. Поставка приложения без ключевых функций бесполезна. Например, система ввода заказов неприемлема, если она не позволяет пользователям вводить заказы. Обычно специалисты в предметной области понимают, какие ключевые функции требуются пользователям (основные варианты поведения, операции с данными при пиковой нагрузке, критически важные управляются транзакции и т. д.), поэтому могут помочь при определении критически важных вариантов использования.
  • Выбор вариантов использования, описывающих функции для той области архитектуры, которая не связана с критически важным сценарием использования. Чтобы учесть основные технические риски, разработчики должны понимать все области системы. Даже если какая-либо область архитектуры на первый взгляд не может создать высокий риск, за ней могут скрываться технические трудности, которые можно выявить только после проектирования, реализации и тестирования некоторых функций в данной области.

Первому и последнему критериям из приведённого выше списка архитектор должен уделить больше внимания; руководитель проекта должен сосредоточиться в основном на первых двух критериях.

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

Шаг 4. Применение итеративного процесса с управлением на основе рисков

Если вы выполнили описанные выше шаги 2 и 3, то очень близко подошли к модели "идеальной" итеративной разработки. Следующий шаг - объединить шаги 2 и 3, добавив управление разработкой на основе рисков и итеративную разработку. То есть описанный в RUP ряд итераций.

RUP предлагает структурный подход к итеративной разработке, деля её на четыре фазы: обследование, проработка, построение системы, сдача её в эксплуатацию. Каждая фаза содержит итерации (иногда только одну итерацию), целью которых является создание технических результатов, необходимых для достижения целей данной фазы. Группа разработчиков выполняет столько итераций, сколько требуется для достижения целей фазы, но не более. Если после запланированного количества итераций не удаётся достичь поставленных целей, то необходима ещё одна итерация на этой же фазе, а значит и задержка срока завершения проекта. Чтобы избежать этого, уделяйте особое внимание тому, что требуется сделать на каждой фазе, каковы её цели. Например, на фазе обследования непродуктивно уделять слишком большое внимание требованиям. Ниже приведено краткое описание типичных целей фаз.

  • Обследование. Нужно хорошо понять, какой должна быть система, вникнув во все требования к системе, и определить объём работ. Уменьшить большинство рисков, составить технико-экономическое заключение о создании системы, получить одобрение со стороны представителей заказчика и их решение - начинать проект или нет.
  • Проработка. Обдумайте самые трудные технические риски: проектирование, реализация, тестирование, создание базовой версии действующей архитектуры, в том числе подсистем, их интерфейсов, ключевых компонентов, архитектурных механизмов (например, как организовать обмен данными между процессами, их сохранение). Проработайте главные технические риски, например, риски конфликта между ресурсами, риски недостаточно высокой производительности, риски недостаточной защиты данных. Для этого создайте и проверьте в деле реальный код.
  • Построение системы. На пути от действующей архитектуры к первой рабочей версии системы выполните основную часть работ по построению системы. Разверните несколько внутренних и альфа-версий, чтобы убедиться в том, что систему можно использовать, и она удовлетворяет потребностям пользователей. Завершите эту фазу развёртыванием полностью работающей бета-версии системы, включая установку, сопутствующую документацию и учебные материалы; помните, однако, что функциональность, производительность и общее качество системы наверняка придётся настраивать.
  • Сдача в эксплуатацию. Убедитесь, что программное обеспечение удовлетворяет потребности его пользователей. Среди прочего, для этого нужно протестировать продукт перед его выпуском и внести в него изменения в соответствии с отзывами пользователей. На этом этапе проекта отзывы пользователей должны быть сосредоточены на тонкой настройке продукта, на вопросах конфигурации, установки и удобстве использования; основные вопросы по структуре должны быть решены на предыдущих этапах проекта1.

Множество способов сделать эти шаги

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

Примечания

1 Подробное описание того, как разработка по методологии RUP осуществляется на практике, содержится в главах 5-8 книги The Rational Unified Process Made Easy (Пошаговое руководство по Rational Unified Process), авторы Per Kroll и Philippe Kruchten (Addison-Wesley, 2003).

Дополнительная информация


Страница сайта http://www.interface.ru
Оригинал находится по адресу http://www.interface.ru/home.asp?artId=1155