Разбивайте большие истории на основе операций, которые выполняются в пределах истории.
Общий подход к этому заключается в разбивке истории по границам обычных CRUD-операций — создание, чтение, редактирование и удаление. Чтобы понять, как это работает, предположим, что вы создаете систему SwimStats, а команда готова к реализации такой истории: «Как тренер я могу управлять пловцами в моей команде». Команда разработчиков обсуждает историю с тренерами/пользователями и выясняет, что тренер под этим понимает возможность добавлять новых пловцов, редактировать существующие данные по пловцам и удалять записи о пловцах, которые ушли из команды. Подобная первоначальная история легко разбивается на три более мелкие истории:
• Как тренер я могу добавлять новых пловцов в мою команду.
• Как тренер я могу редактировать информацию о пловцах, входящих в мою команду.
• Как тренер я могу удалять записи о пловцах, которые больше не входят в мою команду.
Эти истории практически совпадают с операциями создания, редактирования и удаления. Разбивка большой истории на эти три более мелкие истории представляет очень распространенную модель и дает нам следующее правило:
Разбивайте большие истории на отдельные CRUD-операции.
Удаление сквозной функциональности
В типичном приложении всегда есть множество ортогональных, или сквозных, функций. Безопасность, обработка ошибок и регистрация, например, пересекаются со всеми другими функциями приложения. Слишком большую историю, которая не укладывается в одну итерацию, нередко можно сократить путем ее изоляции от одной или нескольких сквозных функций.
Так, многие приложения содержат окна, которые ведут себя по-разному в зависимости от привилегий текущего пользователя. Если это слишком сложно реализовать за одну итерацию, разработайте окно за первую итерацию и добавьте поддержку привилегий конкретных пользователей в последующей итерации.
В одном из моих проектов клиенту нужно было разбить историю, которая предполагала поиск данных и отображение результатов. Поиск каждый раз проводился по всей базе данных, однако отображаться должны были только те результаты, к которым пользователь имел право доступа. Команда решила игнорировать это ограничение, связанное с безопасностью, и позволить пользователям видеть весь набор результатов после первой итерации.
В качестве другого примера предположим, что команда планирует работу над историей, в которой говорится: «Как пользователь я должен зарегистрироваться с использованием своих имени и пароля, чтобы войти в систему». Команда обсуждает эту историю и предлагает перечень ограничений на пароли: они должны иметь не менее восьми символов, содержать как минимум одну цифру, не должны содержать три и более повтора одного символа, должны шифроваться при передаче и т. д.
Ни одно из этих требований не является слишком трудоемким, однако в сумме они могут сделать историю слишком большой, чтобы она уложилась в одну итерацию. Проблему можно устранить путем удаления мер безопасности из истории, предусматривающей регистрацию, и создания незащищенной и защищенной версий истории. Вторая история может содержать перечень запланированных мер безопасности, таких как длина пароля, ограничения на использование символов и пр. Возможно, вы не решитесь на выпуск релиза только с первой, незащищенной версией истории, однако разбивка первоначальной, большой истории таким образом создает определенную стоимость.
Это подводит нас к следующему правилу:
Попробуйте удалить сквозные функции (такие как безопасность, регистрация и обработка ошибок) и создать две версии истории: одну с поддержкой сквозных функций, а другую без поддержки.
Несоблюдение требований к быстродействию
При разработке программного обеспечения мы нередко забываем (или игнорируем) совет Кернигана и Плоджера: «Сделайте это работоспособным, а затем повышайте быстродействие» (Kernighan and Plauger, 1974). Несколько лет назад я работал над проектом по воспроизведению графиков цен фондового рынка. Веб-пользователи должны были запрашивать график по биржевому символу (тикеру) акции. Наша программа должна была затем загружать исторические цены этой акции (за разные периоды от текущего дня до последних пяти лет) и строить линейный график движения акции. В число условий удовлетворенности, связанных с этой функцией, входили точность линии, восполнение пропусков данных и быстродействие. Для достижения целевого быстродействия мы должны были кэшировать наиболее часто запрашиваемые графики и перезаписывать каждый из них раз в минуту. Поскольку кэширование составляло значительную часть трудозатрат на разработку этой новой функции, мы выделили его в новую пользовательскую историю и включили в план следующей итерации. В общем смысле этот подход можно применять к любому нефункциональному требованию, в результате мы получаем следующее правило:
Читать дальше
Конец ознакомительного отрывка
Купить книгу