Опубликован: 17.06.2015 | Доступ: свободный | Студентов: 2345 / 361 | Длительность: 13:09:00
ISBN: 978-5-9556-0174-8
Лекция 8:

Артефакты agile

< Лекция 7 || Лекция 8: 12 || Лекция 9 >
Аннотация: Для поддержки своих практик agile подходы определили несколько артефактов, некоторые из них конкретные, как "карточки историй", другие виртуальные – чисто концептуальной природы. Начнем с главных виртуальных артефактов: работающий код, тесты, пользовательские истории, баллы за историю, скорость, определение сделанного, бэклог продукта. Потом перейдем к рассмотрению конкретных артефактов: рабочего пространства, карточек истории, задач, панели историй, диаграмме выполненных работ. И в заключение рассмотрим пять артефактов, четыре из которых виртуальные, а один конкретный, фигурирующие постоянно во всех обсуждениях agile – хотя и негативно, как ловушки, которых следует избегать: помехи, технические долги, затраты, зависимости, диаграммы зависимостей.

8.1 Код

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

8.2 Тесты

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

Юнит тест представляет описание некоторого частичного теста и ожидаемых результатов его выполнения. Процесс юнит тестирования претерпел существенные изменения в связи с появлением инструменария тестирования, называемого xUnit, как например JUnit для Java. Как отмечалось в предыдущей главе, неслучайно, что Бек, одна из наиболее уважаемых личностей в XP, является (вместе с такими людьми, как Эрих Гамма) одним из авторов этого инструментария. Юнит тест в стиле xUnit принимает форму класса и включает:

  • программу (метод), выполняющую тест;
  • программы подготовки условий тестирования и восстановления контекста после выполнения теста, например, установка соединения с базой данных и восстановление исходного состояния базы после прохождения теста;
  • утверждения (известные также как оракул), определяющие условия успешного прохождения теста. Рассмотрим, например, операцию, обрабатывающую запрос на аренду автомобиля, и, если запрос окажется приемлемым, устанавливает переменную age – возраст водителя; тест для этой операции может включать утверждение is_accepted implies (age >= 18 & age <=75).

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

Существует и лучший подход. Вместо того чтобы рассматривать код и тесты как отдельные артефакты и связывать утверждения только с тестами, можно рассматривать утверждения как механизм спецификации и записывать их как интегральную часть кода в форме инвариантов класса, предусловий и постусловий методов класса. Таким подходом является проектирование по контракту, используемое в языке Eiffel [Meyer 1997], [Meyer 2009]. При этом подходе появляется возможность автоматически генерировать тесты по коду и утверждениям. Все это, однако, предмет другого обсуждения.

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

Фактически нет причин включать в этот набор только "падающие" тесты. Мы видели, что один из важных вкладов agile (прежде всего XP) – это правило, в соответствии с которым каждому элементу кода соответствует, по меньшей мере, один тест. XP требует, чтобы тест строился и запускался до реализации соответствующего кода, так что тест автоматически становится "падающим" и включается в регрессионный набор тестов. Амблер отмечает, что аджилисты ввели в практику если не TDD, то, по крайней мере, регрессионное тестирование.

Набор регрессионных тестов представляет один из определяющих agile артефактов, точно так же, как непрерывная интеграция – одна из определяющих agile практик, даже для команд, которые не воспринимают более экстремальные идеи, такие как TDD.

Регрессионный набор – ключевая ценность любого хорошо управляемого программного проекта. Частично его привлекательность в том, что он представляет истинно возрастающий продукт. Мы видели, что "возрастание", пропагандируемое в agile подходах, не всегда хорошо работает при применении к разработке. Но набор тестов обладает свойством "возрастания" по своей природе. Он может начинаться с совсем небольшого множества, и, если каждый придерживается дисциплины "ни пяди кода без теста", растет быстро и становится одним из основных ресурсов проекта.

8.3 Пользовательские истории

Пользовательские истории составляют базисный набор требований в agile методах.

Пользовательская история представляет описание мелкозернистой функциональности, как ее видят пользователи. Более общим понятием является "случай использования" или "вариант использования", детально проработанный в хорошо известной книге Якобсона [Jacobson 1992]. Вариант использования может быть большим (крупнозернистым): он описывает сценарий полного взаимодействия, например, процесс заказа элемента на коммерческом сайте. Пользовательская история много меньше.

Стандартный стиль agile – описание пользовательских историй. В этом стиле пользовательская история задается тройкой: <роль, цель, преимущества>. Например:

"Как сотрудник Я хочу отменять заказы, так чтобы разумные запросы на исключение полисов можно было согласовывать".

Хотя некоторые проекты принимают такой фиксированный стиль, возможны различные варианты описания.

Определяющее свойство пользовательских историй как средства для описания функциональности системы в том, что каждая история описывает единицу функциональности с точки зрения пользователя, более точно с позиций роли пользователя, поскольку есть понятие роли, но нет понятия просто "пользователь". "Сменить реляционную базу данных на не-SQL решение" – это не пользовательская история. Для интеграции такого ахитектурного решения необходимо определить его как задачу для пользовательской истории, которая описывает преимущества, видимые пользователю. Например:

"Как менеджер по маркетингу Я хочу создать новые предложения потребителям без соответствия существующим схемам, так чтобы была возможность более быстро отвечать потребностям рынка".

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

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

История 2 инспирирована ситуацией, рассказанной Поппендик, в которой компания нарушила Lean принцип "целостности", предоставив две различные системы для покупки билета и покупки, оплачиваемой за счет накопленных миль.

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

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

Кстати, все сказанное вполне сочетается с одним из принципов agile подхода Lean – "Видеть Целое". Но Поппендик не показывает, как этот принцип может сочетаться с разработкой, полностью основанной на пользовательских историях. Он не сочетается.

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

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

Одного из моих коллег однажды попросили проконсультировать архитектуру забавного нового компьютера, полную новых концепций, объектно-ориентированную и так далее. После прослушивания с энтузиазмом представленной презентации его первой реакцией было: "Очень впечатляюще, спасибо, но как я должен загружать и хранить данные?" Ему не хватало типичных пользовательских историй. Как тесты предлагаемой системы они незначимы. Как способ построения системы (кто будет конструировать архитектуру компьютера на основе загрузки и хранения?) они недостаточны. Тем не менее, они важны.

Придавая пользовательским историям слишком большое значение, мы умаляем роль задач, критичных для всех применений, для того рода деятельности, которая является предметом критики со стороны agile, – построение модели предметной области. Эта модель (в предположении объектно-ориентированной разработки) представляет множество классов, покрывающих фундаментальные концепции создаваемой системы: полеты и накопленные мили, служащие и квитанции, клиенты и кредитные карты, абзацы и шрифты, телефонные вызовы и текстовые сообщения. Эти и другие концепции проектируются с ассоциированными операциями, отношениями между классами – наследованием, клиент–поставщик. При проектировании предметной области внимание уделяется в первую очередь бизнес-аспектам системы, а не только аспектам, носящим чисто программный характер, – доступу к базам данных и пользовательским интерфейсам. Построенная в результате модель предметной области не задает функциональность, поставляемую пользователю. И все же эта модель представляет прочный скелет, позволяющий успешно развивать систему.

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

  • последовательно: отдавая предпочтение построению модели предметной области в начальной фазе проекта, что позволит создать прочную основу; затем фокус смещается на поставку функциональности, видимой пользователю благодаря пользовательским историям;
  • параллельно: работать одновременно над обоими аспектами, постоянно информируя друг друга.

Основываться исключительно на пользовательских историях как на источнике требований недостаточно для построения прочного базиса системы. Такой узкий взгляд является одним из главных ограничений agile методов.

8.4 Истории. Начисление баллов

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

Мы рассматривали приемы оценивания при обсуждении игры в планирование и покер планирования ( "Практики agile: производственные процессы" и "Практики agile: производственные процессы" ). Точно так же важно проводить измерение того, что сделано в процессе развития проекта.

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

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

В качестве меры все еще широко используется подсчет числа строк заключительного кода. Число строк нетрудно подсчитать, но, кажется, это единственный аргумент в пользу такой меры. Даже если предположить, что это хороший показатель функциональности (спорное утверждение), трудно представить, как можно заранее подсчитать этот показатель для будущей системы. Показатель неудобен и для измерения прогресса разработки. (Спасибо, что вы мне сказали, что уже произвели 85 000 строк, но значит ли это, что работа выполнена на 90 %, 50 % или сделано только 10 % работы.)

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

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

Единицей может служить день работы, но могут быть и другие критерии. Например, за единицу можно принять простейшую историю, тогда все остальные будут оцениваться относительно этой базисной истории. По словам Кона [Cohn 2006]:

Красота в том, что оценивание историй в баллах полностью отделяет оценивание трудоемкости разработки от оценивания ее длительности. Конечно, трудоемкость и расписание коррелированы между собой, но их разделение позволяет оценить каждый показатель независимо. Фактически вы более не оцениваете длительность проекта: она автоматически выводится из числа итераций, затрачиваемых на реализацию принятых историй.

Кон говорит об априорном оценивании проекта, но сказанное применимо и к апостериорным измерениям.

Баллы истории имеют следующие важные свойства.

  • Как следует из сделанного выше замечания, баллы являются относительным индикатором и не задают временные оценки. Вы можете взять оценки историй, сделанные априорно, и измерения в ходе разработки, все умножить на 5, и это никак не повлияет на общую оценку трудоемкости проекта. Внутри проекта оценки, конечно, должны быть согласованы, чтобы была возможность определения и предсказания скорости разработки, что будет обсуждаться в следующем разделе.
  • При измерении уже достигнутых результатов баллы должны считаться только для реализованных историй, истории, не полностью реализованные, учитываться не должны. Это правило соответствует agile пониманию "затрат" – категории, включающей любой код, который фактически не поставлен пользователю.

Более общий взгляд: любой непоставляемый артефакт не учитывается при оценке прогресса проекта. Примеры могут включать документацию, планы, требования – все, что с точки зрения agile представляет "затраты", хотя такие артефакты могут учитываться, если они явно входят в определение "сделано", что будет обсуждаться далее. Заметьте, тесты, которые по определению не являются "затратами", не учитываются в баллах истории.

Баллы истории являются относительно недавним добавлением в коллекцию agile артефактов. Экстремальное программирование вначале использовало абсолютное измерение времени – идеальное время программирования, то есть число дней, требуемых для реализации истории при условии полного рабочего дня и отсутствия помех. Помимо этого, вводился "коэффициент устойчивости", позволяющий оценить реальное время путем умножения идеального времени на коэффициент, который типично принимался от 2 до 4 (Бек). Критики говорили, что введение коэффициента устойчивости на практике означает некоторую фальсификацию оценок, но на самом деле это очевидное стремление расширить рамки оценок. В 2002 году XP перешел к "чистым программистским неделям". Это тренд, указывающий на стремление уйти от точных временных единиц к цифрам, не носящим абсолютный характер. Чтобы подчеркнуть это свойство, иногда применяется термин "резиновый мишка" как синоним "баллы истории".

Внутри проекта баллы истории имеют смысл, поскольку позволяют сравнивать прогресс от одной итерации к следующей в согласованных единицах. И снова Кон [Cohn 2006]:

Здесь нет формул, устанавливающих размер истории. Оценка истории в баллах отражает трудоемкость разработки функционала, сложность разработки, риск, присущий истории.

Покер планирования (как и более ранний вариант – игра в планирование) – один из принятых в agile приемов для получения таких оценок. Вы помните, что в покере используется набор значений, взятый из некоторой последовательности чисел, например из последовательности чисел Фибоначчи: 0, 1, 2, 3, 5, 8… При такой практике 1 означает историю минимальной стоимости, и все другие значения соизмеряются с ней. Вы можете полагать, что эта минимальная история требует двух часов или половины дня работы, хотя, как поясняет Кон, точный выбор для этого соответствия для оценки процесса не критичен.

8.5 Скорость

Сразу же, как пользовательским историям даны индивидуальные оценки и итерация началась, те же самые меры могут служить для оценки прогресса разработки. Здесь становится полезным понятие "скорость".

Это понятие, критически важное и, на удивление, часто игнорируемое в период до agile, дает четкую, измеримую, непрерывную оценку скорости развития проекта.

Среди программистов ходит много шуток о проектах, готовых через несколько недель после их начала на 90 % и остающихся в этом состоянии в течение длительного времени. Но вопрос "как далеко вы продвинулись" вполне уместен для менеджеров и других сопричастников проекта.

Скорость является синонимом быстроты, то есть как быстро выполняется работа. Для движущихся объектов скорость V задается отношением S/t, где S – пройденный путь, а t – время его прохождения. Эта интерпретация применима и к скорости разработки проекта. Числитель измеряется в баллах историй, знаменатель явно не появляется, поскольку он принимается равным единице – одной итерации (спринт в Scrum). Так что под скоростью в agile мире понимается число баллов тех историй, которые выполнены во время итерации.

Так, определенная скорость дает меру выполненных работ. Эта концепция подтверждает справедливость выбора относительных оценок, а не абсолютных. В начале работ над проектом довольно трудно сказать, сколько времени уйдет на реализацию задачи – два часа или целый день. Оценивание в баллах позволяет избежать задания точных временных оценок и сосредоточиться на оценке относительной сложности задач, сравнивая их друг с другом. Если применять эту методику согласованно в течение всего проекта, то относительные предсказания (баллы истории) будут все более приближаться к абсолютным значениям (длительности выполнения истории).

Конкретно предположим, что у нас есть две оценки:

  • первый спринт покрывает истории на 30 баллов;
  • один балл соответствует одному дню работы команды.

По нашим ожиданиям, второе из этих предположений может быть дальше от истины, чем первое. Теперь предположим, что в течение 30-дневного спринта удалось выполнить историй на 20 баллов. Предположим, что подобная ситуация имела место и в течение последующих нескольких спринтов (вспомните "коэффициент устойчивости" в ранних версиях XP), так что нужно полагать, что знаменатель, определяющий время при подсчете скорости, равен не 1, а 1,5. Если с течением времени этот образец остается стабильным и команда работает все лучше, как и должно быть, то оценки становятся все более точными. Это та "красота", которую имел в виду Кон в приведенной выше цитате.

Оценка трудоемкости разработки. Конус неопределенности

Рис. 8.1. Оценка трудоемкости разработки. Конус неопределенности

Такие приемы, которые используют непрерывно уточняющиеся измерения для улучшения первоначальных грубых оценок, являются примером более общей концепции программной инженерии, первоначально введенной Боемом [Boehm 1981] и получившей название "конус неопределенности". Конус определяет границы (в конечном счете – измеряемое значение) некоторого свойства проекта. В ходе работы над проектом мы имеем все больше информации о свойстве проекта, и границы сужаются.

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

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

8.6 Определение "Сделано"

Акцент agile на поставку актуальной функциональности, избегая затрат, отражается в строгом определении прогресса как числа баллов поставленных историй, но это требует строгих и согласованных критериев, устанавливающих, что задача действительно сделана. В Scrum дается определение понятия "сделано", объясняющее, что мы имеем в виду, когда говорим – это "сделано".

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

Сазерленд [Sutherland 2013] приводит следующие определения "сделано":

  • готовый к публикации (простейший вариант);
  • прошедший этапы юнит-тестирования и интеграционного тестирования; готовый к приемо-сдаточному тестированию; развернутый на сервере;
  • прошедший приемное тестирование, имеются письменные пояснения к релизу, готовый к публикации, не увеличивающий "технический долг".

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

< Лекция 7 || Лекция 8: 12 || Лекция 9 >
Алексей Задойный
Алексей Задойный

В главе "5: Роли agile" http://www.intuit.ru/studies/courses/3505/747/lecture/26297?page=2 есть упоминание:

Скримшир [Scrimshire сайт]

но нет адреса сайта. Укажите пожалуйста адрес в тексте лекции.

Или речь о человеке James Scrimshire?

Павел Плахотник
Павел Плахотник

http://www.intuit.ru/studies/courses/3505/747/lecture/26293

Сделайте пожалуйста вопросы более корректными. Это сложно конечно. Но надо четко понимать что именно имеется в виду.

По предварительному анализу, водопаду, документам требований вообще не понятно что имеется в виду. Возможно надо будет изменить авторский текст, но всё же ясность и конкретность важна. А её нет.