Что за User Story?

Перевод статьи Дэна Норта - "What's in a story?"


Разработка, основанная на поведении (Behaviour-driven development, BDD) - это одна из методологий разработки программного обеспечения по стратегии "снаружи-вовнутрь". Она берёт своё начало извне команды разработки, отталкиваясь от определения бизнес-целей заказчика, а затем углубляется до проработки набора функций(feature), которые позволят достичь заданных бизнес-целей. Каждая функция фиксируется как "пользовательская история", в которой задаются границы этой функции с помощью критериев приёмки. В этой статье описывается подход BDD по формулировке пользовательских историй и идентификации их критериев приёмки.

Введение

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

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

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

Собственно, для этого и предназначены "Пользовательские истории". Они должны быть описанием требований и коммерческой ценности от их реализации, а также набором критериев, по которым мы все будем оценивать конечный результат. Это более строгое определение, чем в других гибких (Agile) методологиях, где это в разных случаях определяется как "договоренность по понятиям" (promise of a conversation) или "описание функции". Пользовательская история в нотации BDD может с лёгкостью описывать нефункциональные требования, при этом объём работ по такому описанию может быть зафиксирован, осмечен и согласован.

Структура пользовательской истории

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

Английский вариант Локализованный вариант Title (one line describing the story)

Narrative:

As a [role]

I want [feature]

So that [benefit]


Acceptance Criteria: (presented as Scenarios)


Scenario 1: Title

Given [context]

And [some more context]...

When [event]

Then [outcome]

And [another outcome]...


Scenario 2: ...

Заголовок(описание истории в одну строку)

Формулировка истории:

Я как [роль]

Хочу [функционал]

Для того чтобы [выгода]


Критерии приёмки: (описываются сценариями)


Сценарий 1: Заголовок

Дано [контекст]

И [ещё немного контекста]...

Когда [событие]

Тогда [результат]

И [ещё один результат]...


Сценарий 2: ...


Рассказывая пользовательскую историю

Пользовательская история должна быть результатом общения нескольких задействованных в процессе людей. Бизнес-аналитик общается с владельцем бизнеса о функционале либо требовании, и помогает ему преобразовать его видение в формат формулировки пользовательской истории (Я как [роль] хочу [функция] для того чтобы [выгода]). Затем тестировщик помогает определить граничные условия пользовательской истории - в форме критериев приёмки,определяя какие сценарии более подходят для этого, а какие менее важные. Технический специалист сможет в первом приближении оценить объём работы для реализации пользовательской истории и предложить различные подходы по реализации. Прекрасные идеи, воплотившиеся в программные системы, возникают не только в голове разработчиков, но в голове заказчиков, которые требует первостепенной их реализации.

Это весьма вероятно будет итеративный процесс. У человека из бизнеса рождается идея, но он обычно не имеет представления о трудозатратах на её реализацию, или как это вообще можно реализовать. С помощью технических специалистов и экспертов по тестированию заказчик получает представление о соотношении стоимость/выгода по каждому сценарию и поэтому может принять решение "стоит ли овчинка выделки". Конечно, на другой стороне весов лежат остальные требования: что лучше - более тщательно проработать критерии приемки (сценарии) по текущей истории, либо перейти уже к следующей?

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

Критерии качества пользовательской истории

Используя пример из статьи "Введение в BDD" давайте посмотрим на требования по реализации извлечения наличных из банкомата.


Английский вариантЛокализованный вариант Story: Account Holder withdraws cash

As an Account Holder

I want to withdraw cash from an ATM

So that I can get money when the bank is closed


Scenario 1: Account has sufficient funds

Given the account balance is \$100

And the card is valid

And the machine contains enough money

When the Account Holder requests \$20

Then the ATM should dispense \$20

And the account balance should be \$80

And the card should be returned

Scenario 2: Account has insufficient funds

Given the account balance is \$10

And the card is valid

And the machine contains enough money

When the Account Holder requests \$20

Then the ATM should not dispense any money

And the ATM should say there are insufficient funds

And the account balance should be \$20

And the card should be returned


Scenario 3: Card has been disabled

Given the card is disabled

When the Account Holder requests \$20

Then the ATM should retain the card

And the ATM should say the card has been retained

Scenario 4: The ATM has insufficient funds

...

История: Владелец карточки снимает наличку

Я как Владелец карточки

Хочу снять наличку в банкомате

Для того чтобы я мог получить деньги, когда банк закрыт


Сценарий 1: На карточке хватает денег

Дано на карточке лежит 100 долларов

И карточка активна

И в банкомате достаточно денег

Когда когда Владелец карточки запрашивает съём 20 долларов

Тогда банкомат должен выдать 20 долларов

И баланс на карточке должен стать 80 долларов

И карточка должна быть возвращена


Сценарий 2: На карточке НЕ хватает денег

Дано на карточке лежит 10 долларов

И карточка активна

И в банкомате достаточно денег

Когда Владелец карточки запрашивает съём 20 долларов

Тогда банкомат должен НЕ выдать денег

И банкомат должен сообщить о нехватке средств на карте

И баланс должен остаться 10 долларов

И карточка должна быть возвращена

Сценарий 3: Карточка аннулирована

Дано карточка аннулирована

Когда когда Владелец карточки запрашивает съём 20 долларов

Тогда банкомат должен заблокировать карточку

И банкомат должен сообщить об удержании карты

Сценарий 4: В банкомате не хватает налички

...


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

Заголовок должен описывать действие

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

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

Формулировка истории должна включать в себя роль, функцию и выгоду

Шаблон "Я как [роль] хочу [функция] для того чтобы [выгода]" имеет ряд преимуществ. Указывая роль в формулировке ты знаешь с кем тебе общаться о функции. Указывая выгоду - ты всегда объяснишь сотруднику, прорабатывающему историю, зачем им это надо.

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

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

Заголовок сценария должен фокусироваться на отличиях в ситуациях

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

Сценарий должен быть описан в терминах: Дано, События, Результаты

Это единственный наиболее мощный поведенческий сдвиг, который я когда-либо видел в командах, практикующих BDD. Просто заставляя людей от бизнеса, аналитиков, тестеров и разработчиков адаптировать свою речь в терминах "дано/когда/тогда", мы видим, как проблема двусмысленности отступает.

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

Наблюдается интересный побочный эффект - меняется качество общения. Ты быстро обнаруживаешь, когда не учёл текущий контекст ("а, конечно - не хватает средств!"), или забыл проверить результат ("ну, вообще-то карточка должна возвращаться владельцу..."). Я наблюдал этот эффект на одном проекте, где ведущий разработчик поделился со мной, что аналитики и разработчики не могут сойтись во мнениях, но он не видел способа, как им помочь договориться. За несколько дней он смог перевести их общение в термины "дано/когда/тогда" - и увидел поразительное повышение качества их взаимодействия.

В "Дано" должен быть описан полностью весь контекст, но не более того

Любые излишние "Дано" рассеивают внимание. Это усложняет понимание человеку, который первый раз читает историю - как с технической так и с бизнесовой стороны. Так же любые упущенные "Дано" - становятся допущениями. Если при одинаковых "Дано" ты можешь получить разный результат - значит ты что-то упустил на уровне "Дано".

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

Раздел "событие" должен описывать функцию (feature)

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

Пользовательская история должна вписаться в одну итерацию

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

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

Видимо лучше будет разбить эту историю на несколько более мелких:

Владелец карты извлекает наличку (допущения: банкомат в порядке и карта активная)
Владелец карты извлекает наличку с аннулированной картой (допущения: банкомат в порядке)
Владелец карты извлекает наличку из глючного банкомата (допущения: карта активная)

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

Ну и чем это отличается от UseCase-диаграмм?

Ну есть Use Case - и что дальше? Я большой фан того, как Алистер Коберн (Alistair Cockburn) описывает Use Case (в противоположность той сверх-инженерной версии, которую я увидел в RUP-как-водопад проектах). При условии, что у меня нет большого опыта участия в проектах, основанных на Use Case, я предоставляю другим возможность заняться сравнением.

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

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

Заключение

Разработка, основанная на поведении, (BDD) применяет пользовательские истории как базовые модули функциональности, а следовательно - поставки. Критерии приёмки - неотъемлемая часть пользовательской истории, в результате они задают ограничение поведения и дают нам расширенное представление о результате (что получит заказчик, когда мы скажем "Готово!"). Они также используются как основа для осмечивания работы, когда приходит время для планирования.

Наиболее важно: пользовательские истории - это результат общения между представителями бизнеса, бизнес-аналитиками, тестировщиками и разработчиками. BDD в одинаковой мере определяет, как различные участники проекта должны взаимодействовать друг с другом, так и какие должны быть результаты процесса разработки.


Chief technology officer "Один Сервис.ВЦ" - Денис Олейник