Перевод статьи «Engineering guide to writing correct User Stories».

Люди, работающие по методологии Agile, одержимы написанием user stories. И это, конечно, очень мощный инструмент. Но по своему опыту могу сказать, что множество людей пишут их неправильно.
Взгляните на этот пример:

Как пользователь
Я хочу получать webhooks о проблемах на Gitlab
Чтобы я мог помещать все текущие задачи в список
На вид совершенно нормальная user story, правда? Но на самом деле эта маленькая история имеет несколько проблем. И если вы не можете найти в ней как минимум 8 ошибок, вам действительно стоит прочесть эту статью.
Статья делится на три основные части:
- Улучшение user story в рамках текущего формата.
- Переписывание user stories с применением BDD, чтобы сделать их проверяемыми.
- Связывание user stories с тестами, исходным кодом и документацией.
И хотя разные части могут быть интересными разным категориям читателей, важно, чтобы каждый разобрался в этом подходе в целом.
Обнаружение и исправление проблем
Все мы знаем, что все наши требования должны быть корректными, недвусмысленными, полными, последовательными, упорядоченными по степени важности, проверяемыми, модифицируемыми и прослеживаемыми, даже если на первый взгляд они вообще не кажутся требованиями.
User stories имеют тенденцию упускать некоторые из этих характеристик. Нам нужно это исправить.
Последовательность в терминах
Желания «Получать webhooks о проблемах» и «помещать все текущие задачи в список» как-то связаны между собой? «Проблемы» и «задачи» это одно и то же или все-таки нет? Ведь это могут быть как совершенно разные вещи, так и просто неудачный побор слов. Как нам это определить?
Вот для чего нужны глоссарии! Каждый проект должен начинаться с определения специфических терминов, которые в будущем позволят выражаться совершенно однозначно. Но как нам, для начала, создать сам глоссарий? Мы опрашиваем экспертов в сфере, к которой относится проект. Обнаруживая новый термин, мы проверяем, все ли эксперты понимают его правильно и единообразно. Также следует обращать внимание на то, что один и тот же термин может по-разному пониматься в разных ситуациях и контекстах.
Допустим, в нашем случае после консультаций с экспертами мы обнаружили, что «задачи» и «проблемы» это одно и то же. Теперь нам нужно удалить неправильный термин.

Как пользователь
Я хочу получать webhooks о проблемах на Gitlab
+++Чтобы я мог помещать все текущие проблемы в список
---Чтобы я мог помещать все текущие задачи в список
Прекрасно. Использование одинаковых слов для одинаковых сущностей делает наши требования более понятными и последовательными.
Желания пользователей и ваши желания это не одно и то же
Когда мы изменили последнюю строку, я обратил внимание, что цель пользователя – «помещать все текущие проблемы в список». Зачем бедный пользователь хочет составлять списки проблем? В чем смысл этих действий? Никакой пользователь ничего подобного не хочет. Это просто некорректное требование.
И это индикатор очень важной проблемы в написании требований. Мы склонны смешивать наши цели и цели пользователя. И хотя наша цель – удовлетворить пользователя, нам все же стоит сосредоточиться в первую очередь на его желаниях. Нам стоит придавать больше значения его целям, чем собственным. И мы должны четко выражать это в наших требованиях.
Как понять, чего хочет пользователь? Нужно проконсультироваться на этот счет с реальными пользователями или их представителями. Или, если мы не можем ни у кого спросить, придется строить предположения самостоятельно.

Как пользователь
Я хочу получать webhooks о проблемах на Gitlab
+++Чтобы я мог просматривать и отслеживать прогресс по
этим проблемам ---Чтобы я мог помещать все текущие проблемы в список
После получения обратной связи мы выяснили, что нашим пользователям нужно знать о прогрессе проекта. Не составлять списки проблем. Вот почему нам нужно получать и хранить информацию о проблемах от стороннего сервиса.
Убираем технические детали
Вам когда-нибудь доводилось встречать человека, который хотел бы именно «получать webhooks о проблемах»? Это никому не нужно. В данном случае мы тоже смешиваем разные вещи.
Есть четкое разделение между целями пользователя и техническими способами их достижения. И «получать webhooks о проблемах» это определенно детали реализации. Завтра webhooks могут измениться на WebSockets, всплывающие уведомления и т. п. А цели пользователя при этом останутся прежними.

Как пользователь
+++Я хочу иметь обновляемую информацию о проблемах на Gitlab
---Я хочу получать webhooks о проблемах на Gitlab
Чтобы я мог просматривать и отслеживать прогресс по этим
проблемам
Видите? Теперь осталась только важная информация, без деталей реализации.
Уточнение ролей
Из контекста довольно понятно, что речь идет о каком-то инструменте, связанном с разработкой. Мы используем Gitlab и issue management. Так что не сложно догадаться, что у нас есть разные категории пользователей: джуниоры, мидлы и сеньоры. Возможно, менеджеры проектов, а также другие люди.
Итак, мы подошли у определению ролей. Во всех проектах есть разные типы пользователей. Даже если вы думаете, что каких-то определенных типов нет. Эти роли могут основываться на том, как и почему человек использует данный продукт. И эти роли в проекте нужно определить так же, как мы определяли термины.
О каких пользователях идет речь в данной конкретной user story? Будут ли джуниоры точно так же отслеживать прогресс, как менеджеры проектов и архитекторы? Очевидно, что нет.

+++Как архитектор
---Как пользователь
Я хочу иметь обновляемую информацию о проблемах на Gitlab
Чтобы я мог просматривать и отслеживать прогресс
по этим проблемам
После обдумывания вариантов мы можем разделить user stories по ролям пользователей. А это позволяет нам более тонко контролировать поставляемый функционалом и то, кому мы этот функционал поставляем.
Расширяем user stories
Шаблон «Как <роль/человек>, я хочу <цель/нужды>, чтобы <почему>» очень хорош, поскольку он краткий и одновременно мощный. Он дает нам отличную возможность для коммуникации. Однако, у этого формата есть и несколько недостатков, о которых тоже стоит знать.
Делаем user stories проверяемыми
Проблема с приведенной выше user story в том, что она по-прежнему не проверяемая. Как нам проверить, что эта история (на данный момент или все еще) является рабочей для наших пользователей? Мы не можем этого сделать.
У нас нет четкой связи между этой user story и нашими тестами. Было бы прекрасно, если бы можно было писать user stories в качестве тестов…
Погодите, но ведь это возможно! Для этого у нас есть BDD («разработка через поведение») и язык gherkin. Именно для этого BDD и создавалась изначально. Это означает, что для того чтобы чтобы сделать нашу user story проверяемой, мы можем переписать ее в формате gherkin.

История: Отслеживание прогресса проблем
Как архитектор
Я хочу иметь обновляемую информацию относительно проблем
на Gitlab
Чтобы я мог просматривать и отслеживать прогресс по этим
проблемам
Сценарий: получен новый валидный webhook о проблеме
Дано: webhook о проблеме валидный
Когда он получен
Тогда создана новая проблема
Вот теперь user story является проверяемой. Мы можем использовать ее в качестве теста и отслеживать ее статус. Более того, теперь у нас есть связь между нашими требованиями высшего порядка и деталями реализации, а это позволяет нам понять, как конкретно мы будем выполнять требования. Обратите внимание: мы не подменяли требования бизнеса деталями реализации, мы их дополнили этими деталями.
Обнаружение неполноты
Когда мы привыкли писать наши user stories на gherkin, мы начали писать сценарии для наших user stories. И мы обнаружили, что для каждой user story может быть несколько сценариев.
Двайте рассмотрим первый написанный нами сценарий: «получен новый валидный webhook о проблеме». Погодите, но что происходит, когда мы получаем невалидный webhook? Должны мы сохранять эту проблему или нет? Может, кроме сохранения проблемы нужно сделать что-то дополнительно?
Давайте в качестве источника информации о том, что может пойти не так и что делать в этих случаях, возьмем документацию Gitlab.
Оказывается, есть два варианта невалидности, которые нужно обрабатывать по-разному. В первом варианте Gitlab случайно отсылает нам какой-то мусор. Во втором наши токены аутентификации не подходят.

Теперь мы можем добавить еще два сценария, чтобы сделать нашу user story полной.

История: Отслеживание прогресса проблем
Как архитектор
Я хочу иметь обновляемую информацию относительно проблем
на Gitlab
Чтобы я мог просматривать и отслеживать прогресс
по этим проблемам
Сценарий: получен новый валидный webhook о проблеме
Дано: webhook о проблеме валидный
И webhook о проблеме аутентифицирован
Когда он получен
Тогда создана новая проблема
Сценарий: получен новый невалидный webhook о проблеме
Дано: webhook о проблеме невалидный
Когда он получен
Тогда проблема не создается
Сценарий: получен новый валидный неаутентифицированный webhook о проблеме
Дано: webhook о проблеме валидный
И webhook о проблеме не-аутентифицирован
Когда он получен
Тогда проблема не создается
И сохраняется дата webhook-а для дальнейшего
расследования
Мне нравится, что теперь эта простая user story ощущается как нечто сложное. Потому что таким образом на наше обозрение выставляется ее внутренняя сложность. И мы можем подогнать наш процесс разработки к этой растущей сложности.
Упорядочиваем user stories по степени важности
Сейчас непонятно, насколько важно для архитекторов «просматривать и отслеживать прогресс по проблемам». Это более важно, чем другие наши user stories? Поскольку это кажется довольно сложным, может, вместо этого нам следует заняться чем-то более простым и вместе с тем более важным?
Расстановка приоритетов важна для каждого продукта, и игнорировать ее нельзя. Даже если user stories это единственный наш способ записи требований. Существуют разные методы для расстановки приоритетов в требованиях, но мы рекомендуем придерживаться метода MoSCoW. В основе этого простого метода лежат четыре главных категории: must, should, could и won’t. Подразумевается, что у нас в проектной документации будет отдельная таблица приоритетов всех пользовательских историй.
И снова нам нужно спросить у пользователей, насколько важным для них является каждое свойство.
После обсуждения этой темы с разными архитекторами, которые работают с нашим продуктом, мы обнаружили, что требование в нашей user story это абсолютный must:
Функционал | Приоритет |
Аутентифицированные пользователи должны иметь возможность отсылать приватные сообщения. | Must |
Архитекторы должны отслеживать прогресс проблем. | Must |
Должны быть уведомления о входящих приватных сообщениях. | Should |
Можно было бы поддерживать сообщения нескольких провайдеров. | Could |
Зашифрованные приватные сообщения не поддерживаются. | Won’t |
Итак, теперь мы можем изменить название нашей user story, чтобы обозначить приоритет:

История: Архитекторы должны отслеживать прогресс проблем
Можно даже поставить гиперссылку на таблицу с приоритетами требований в файле с user story.
Таким образом мы можем быть уверены, что этот функционал будет одним из первых в очереди на разработку, поскольку он имеет наивысший приоритет.
Связывание всего воедино
Если не уделять этому делу достаточно внимания, вы вскоре утонете в перепутанных user stories, тестах, исходном коде и документации. По мере роста вашего проекта станет просто невозможно сказать, какие части приложения за какие use-cases бизнеса отвечают. Чтобы разобраться с этой проблемой, нам нужно связать все вместе: требования, код, тесты и документацию. Наша цель – получить примерно следующее:

Для иллюстрации этого принципа я использую Python.
Я могу определить use-cases как набор уникальных высокоуровневых действий, которые может осуществлять ваше приложение (это очень похоже на точку зрения Clean Architecture).
Обычно я определяю пакет под названием usecases и собираю в нем все use-cases, чтобы было легко их просматривать одновременно. Каждый файл содержит простой класс (или функцию), выглядит это так:

Я использую sphinx и директиву literalinclude, чтобы включить тот же файл, который мы используем для тестов, для документации основной логики. Я также использую глоссарий, чтобы показать, что issue это не просто случайное слово, а конкретный термин, используемый в этом проекте.
Таким образом наши тесты, код и документы будут максимально связаны. И нам не придется слишком о них беспокоиться. Можно даже автоматизировать этот процесс и проверить, все ли классы внутри usecases/ имеют директиву .. literalinclude в своей документации.
Этот класс также можно использовать для тестирования нашей user story. Таким образом мы свяжем требования, тесты и собственно логику, реализующую эту user story.
Готово!
Заключение
Это руководство поможет вам писать лучшие user stories, фокусироваться на нуждах пользователей, поддерживать чистоту кода и максимально использовать один и тот же код для различных (но сходных) целей.
Не всё переведено в абзаце про обнаружении неполноты а именно пропущена первая строка and
Спасибо за замечание! Исправили.