Пользовательские истории на практике: как правильно взаимодействовать программистам, тестировщикам и другим участникам Agile-команды
Рассмотрим плохие и хорошие варианты разделения работы над User Story, которые применимы не только в Scrum. Адаптированный перевод статьи Майка Кона.
Бывало ли так, что тестировщики в вашей команде не понимали, чем им надо заняться в начале спринта, до того как программисты завершают написание кода к пользовательской истории?
А задавались ли программисты вопросом: чем им заняться ближе к концу спринта, в то время когда тестировщики проверяют написанный код? Возможно, у них даже был соблазн начать работу над следующей пользовательской историей, несмотря на то, что она не может быть завершена в этом спринте?
Когда команда научится правильному способу взаимодействия в рамках пользовательских историй, такие вопросы исчезнут. А также команда становится способна гораздо чаще поставлять заинтересованным лицам больше ценности.
Содержание статьи
Неправильный способ взаимодействия в рамках пользовательской истории
Перед тем, как мы перейдём к правильному способу взаимодействия, давайте рассмотрим наиболее часто встречающийся способ взаимодействия в рамках пользовательской истории, — и поймем, почему он неправильный.
Самый распространенный способ взаимодействия программистов и тестировщиков — если это вообще можно назвать взаимодействием — выглядит так: программист берет пользовательскую историю из бэклога продукта, полностью пишет к ней код до того момента, пока код не будет его удовлетворять, и затем передаёт всю пользовательскую историю на проверку тестировщику.
Пока программист это делает, тестировщик не вовлекается в работу и просто ждёт, когда программист закончит работать с пользовательской историей.
Это именно та ситуация, когда тестировщики начинают задаваться вопросом, что им делать в начале спринта.
Проблема с тестированием в следующем спринте после написания кода
Одно из плохих решений, которое могут попробовать команды: разрабатывать в одном спринте, а тестировать в следующем спринте. Это создает массу проблем.
- Во-первых, это растягивает время поставки ценности (фичи). Если фича должна быть поставлена сразу после готовности, это означает, что время поставки (time-to-market) повышается. Даже если готовая фича поставляется лишь в конце спринта, time-to-market все равно повышается. Ведь теперь потребуется вместо одного два спринта, прежде чем команда сможет получить обратную связь от заинтересованных в данной фиче сторон.
- Во-вторых, это также увеличивает время получения программистом обратной связи о качестве его кода. Например, если новая фича работает, но медленно, программист не будет этого знать до следующего спринта. Если новый программист делает больше ошибок (багов) по сравнению с другими программистами, это не будет известно до следующего спринта.
- В-третьих, к тому моменту, когда программисты получат обратную связь, они уже не помнят код. Возможно, это прозвучит как клише, но многие программисты, когда услышат, что в их коде найдена ошибка, даже не вспомнят, что они писали этот код. Чем раньше от момента написания кода была найдена ошибка, тем легче программисту её исправить.
Природа проблемы взаимодействия
Основная проблема взаимодействия команд в рамках пользовательских историй заключается в том, что программисты делают разработку пользовательской истории целиком, и лишь затем передают ее тестировщикам. Это очень большая партия (пакет изменений). Большая партия чего-то сначала завершается одним человеком, а затем передаётся следующему.
Были ли вы когда-нибудь в ресторане, когда перед вами сделал заказ столик с большой компанией? Возможно, попав в такую ситуацию, вы уже понимаете, что ваш заказ будет выполняться дольше обычного. Это связано с тем, что большой объем (партия) был только что передан от официанта на кухню, а ваш заказ следующий.
Как и с ожиданием ужина, большая партия изменений в коде приводит к таким же проблемам при взаимодействии в рамках пользовательской истории. Чтобы работать эффективно, участники команды должны избегать передачи больших партий друг другу.
Как избежать передачи больших партий?
Наилучший способ избежать передачи большой партии — это отдавать код на тестирование частями.
Чтобы такая практика случилась, необходимо, чтобы программист и тестировщик совместно обсуждали, какую именно часть пользовательской истории необходимо разработать сначала. Когда это решено, программист уходит разрабатывать часть, одновременно с этим тестировщик параллельно пишет тест-кейсы, создает тестовые данные и, если возможно, автоматизирует тесты для разрабатываемой части пользовательской истории.
Как только программист завершил разработку той части истории, которую обсудили, он передает ее на тестирование. Тестировщик завершает работу по автоматизации тестовых кейсов и начинает “прогонять” тесты. После того, как ошибки найдены и исправлены, новая функциональность полноценно интегрируется в систему.
И затем процесс повторяется: программист и тестировщик обсуждают над какой частью пользовательской истории работать дальше и т.д., пока все части пользовательской истории не будут завершены.
Это инкрементальный подход к разработке пользовательской истории. Работа выполняется параллельно с частой передачей небольших частей на тестирование в момент завершения программистом разработки этих частей.
Пример: как программист и тестировщик работают вместе
Давайте посмотрим на то, как это может работать. Для наглядности мы возьмем пример разработки входа на сайт. Программист и тестировщик обсуждают с чего начать. Они могут решить, что можно начать с возможности войти через Facebook*, или с требования сильного пароля, или возможности для пользователя запросить напоминание пароля.
Представим, что программист и тестировщик согласились начать с базового сценария: пользователь вводит имя и пароль, и вход будет разрешен только в том случае, если оба параметра верны.
- После достижения согласия программист начинает разрабатывать данную часть, тестировщик в это же время пишет тест-кейсы.
- Когда программист завершит разработку, тестировщик проверит данную часть, используя ранее написанные к данной функциональности тесты. Возникающие ошибки решаются в момент возникновения.
- После того как данная функциональность завершена, программист и тестировщик встречаются снова для обсуждения пользовательской истории. На этот раз они решают добавить запрос на сильный пароль. Возможно, для начала им необходимо уточнить у владельца продукта или эксперта по безопасности параметры сильного пароля. Такое уточнение они делают вместе. Предположим, что они получили определение сильного пароля: 8 символов, содержит как минимум одну цифру, одну большую букву, одну маленькую букву и специальный символ.
- Вооруженный данной информацией программист пишет код, который будет обеспечивать соблюдение данных правил всякий раз, когда установлен пароль. В то время как программист делает это, тестировщик пишет тестовые кейсы, которые проверят соблюдение каждого правила.
- Когда оба завершат, они перейдут к следующей части пользовательской истории, которая, возможно, будет про запрос на напоминание пароля.
Выше был описан случай нескольких диалогов. Однако, весьма возможно, что такое количество диалогов не требуется, и программист с тестировщиком могут договориться об этапах на одной встрече (например, на планировании). Несмотря на это, важно, чтобы программист всегда сигнализировал тестировщику о том, что он завершил разработку и можно начать тестирование.
Можно ли достичь подобного результата с супер-маленькими пользовательскими историями?
Возможно, пока вы читали приведенный выше пример, у вас возник вопрос: “Разве нельзя добиться подобного путем декомпозиции на супер-маленькие пользовательские истории?” Ведь у нас могут быть следующие пользовательские истории:
- Я, как пользователь, могу войти на сайт, только в том случае, если ввел корректные данные.
- Я, как пользователь, должен создать сильный пароль.
- Я, как пользователь, могу запросить напоминание пароля.
В целом, таким способом вы можете достичь такого же результата, как и с частичной передачей кода, однако, у супер-маленьких историй есть свои минусы.
Во-первых, работая с очень маленькими историями, сложно управлять зависимостями. Например, если вход на сайт декомпозировать на 20 пользовательских историй, возникнет необходимость управлять зависимостями между всеми этими историями. Если же, вместо этого у команды будет только одна история, которая полностью включает в себя функциональность по входу на сайт, то зависимостей, которыми надо управлять, не будет, — как минимум в рамках подсистемы входа.
Управление зависимостями между множеством историй может стать проблемой: вполне вероятно, что какая-то история может потеряться или отделиться от других и, как следствие, важная часть функциональности может быть проигнорирована и не разработана.
Во-вторых, приоритизация экстремально маленьких историй в бэклоге продукта — очень затратное дело. Чем больше историй в бэклоге продукта, тем сложнее их упорядочить. В большинстве случаев эти дополнительные усилия — лишь пустая трата времени, так как большинство маленьких историй имеют одинаковый приоритет и близки друг к другу по очередности.
И последнее. Чем больше в спринте историй, над которыми работает команда, тем больше времени тратится на их отслеживание и обновление статуса в любом из трекеров, которая команда использует. Это не является аргументом в пользу больших историй, а лишь одним фактом, над которым имеет смысл задуматься при работе с супер-маленькими историями.
Итак, маленькие пользовательские истории в целом хороши, однако слишком маленькие пользовательские истории несут свои проблемы.
Как понять, что маленькое — это слишком маленькое? Чтобы ответить на этот вопрос, обратите внимание на три проблемы, которые были описаны выше. Если эти проблемы начали влиять на команду, то ваши истории стали слишком маленькими.
Это касается передачи функциональности между любыми специалистами
В данной статье был рассмотрен пример взаимодействия программиста и тестировщика, однако важно отметить, что данное взаимодействие применимо к любой роли в Agile-команде, что непременно приведёт к повышению эффективности работы.
Работают ли вместе всего два специалиста или больше, их работа будет более эффективной за счет параллельной работы над маленькими партиями. Уменьшение размера передаваемой функциональности от одного специалиста к другому крайне важно для эффективного взаимодействия между участниками команды.
Работая таким образом, тестировщики не задают вопрос, что им делать в начале спринта. Они тестируют часть кода, которая передана им от программистов, или готовят тест-кейсы к тому, о чем договорились с программистами. И программисты не остаются в конце спринта с вопросом «А не начать ли разрабатывать функциональность для следующего спринта?» в ожидании завершения работы тестировщиков.
Узнать больше о том, как правильно писать и декомпозировать пользовательские истории, а также строить карту User Story Map, вы можете на моем тренинге.
* Facebook принадлежит Meta, которая признана в России экстремистской и запрещена.
Почему команды так не любят изменения? Как это проявляется и почему на самом деле сопротивление — это хороший знак? В этой статье обсудим, какую роль играет сопротивление и как Agile-коуч может не бороться с ним, а использовать в интересах команды, применяя различные техники.
Что такое интервизия и действительно ли она помогает скрам-мастерам и agile-коучам, как правильно организовать такую встречу и зачем интервизия нужна самой компании. В статье я постараюсь ответить на все эти вопросы и рассказать о своем опыте, а в конце поделюсь кратким чек-листом для участников, которые хотят извлечь из интервизии максимум пользы.
Современные компании сталкиваются с необходимостью постоянных изменений — будь то адаптация к новым рыночным условиям или улучшение внутренних процессов. Как найти способ эффективно внедрять изменения, причем так, чтобы сделать это быстро и с минимальным сопротивлением от команды? Один из инструментов, который может помочь в этом, — HADI-цикл.