User story и критерии приёмки

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

User story (пользовательская история) — короткое описание требования глазами того, кому оно нужно: кто пользователь, что он хочет сделать и какую ценность из этого получит. Это не спецификация на 40 страниц, а обещание разговора: карточка напоминает команде обсудить детали, а не заменяет обсуждение.

Зачем истории, если можно просто написать «сделать кнопку»

Задача «Добавить кнопку экспорта в отчёты» выглядит понятной ровно до момента, когда разработчик садится её делать. Экспорт куда — в CSV, Excel, PDF? Весь отчёт или только видимые строки? Что если строк миллион? Кому вообще эта кнопка нужна? Ответов в задаче нет, и дальше происходит одно из двух: разработчик угадывает (и в половине случаев угадывает мимо) или идёт спрашивать — но спрашивает уже посреди спринта, когда время потрачено.

Формулировка через историю заставляет автора задачи назвать человека и его выгоду. И тут внезапно выясняется, что кнопка нужна бухгалтеру, чтобы отдать выгрузку в 1С, — значит, нужен именно CSV с конкретными колонками и точкой с запятой в качестве разделителя, а PDF никому не сдался. Один вопрос «зачем» сэкономил неделю.

Вторая причина — приоритизация. Бэклог из пятидесяти «сделать кнопку» невозможно отсортировать: непонятно, что важнее. Бэклог из пятидесяти историй с явной ценностью сортируется за полчаса.

Формула

Канонический шаблон, придуманный в команде Extreme Programming и с тех пор ставший индустриальным стандартом, выглядит так:

Как <роль>,
я хочу <действие>,
чтобы <ценность>.

Три части — три разных вопроса, и каждая работает по-своему:

  • Роль — не «пользователь», а конкретный типаж: «новый пользователь», «администратор магазина», «курьер в приложении». Абстрактный «пользователь» — красный флаг: он значит, что автор не думал о том, кто это.
  • Действие — что человек хочет сделать в системе. Именно человек, а не система: «я хочу отменить заказ», а не «система должна отменять заказ».
  • Ценность — зачем ему это. Самая ценная и самая часто пропускаемая часть. Если ценность не формулируется — возможно, задача не нужна.

Живой пример из интернет-магазина:

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

Обратите внимание: из ценности сразу вытекает граница задачи. «До момента отправки» — значит, после отправки кнопки отмены быть не должно, а нужен уже другой сценарий (возврат). Это выяснилось из одной фразы, без ТЗ.

INVEST: шесть проверок на вменяемость истории

INVEST — мнемоника Билла Уэйка. Это чек-лист, по которому историю прогоняют перед тем, как брать в работу.

БукваЧто значитКак проверить
I — IndependentНезависимаяИсторию можно сделать отдельно, не дожидаясь трёх соседних. Если задачи связаны цепочкой «сначала А, потом Б, потом В» — их порядок в бэклоге жёстко зафиксирован, и планировать нечего.
N — NegotiableОбсуждаемаяИстория описывает потребность, а не готовое решение. «Хочу выпадающий список с автодополнением» — не история, а дизайн, навязанный команде.
V — ValuableЦеннаяЦенность видна пользователю или бизнесу. «Отрефакторить сервис заказов» ценна разработчикам — такое лучше оформлять как техдолг, а не маскировать под историю.
E — EstimableОцениваемаяКоманда может сказать «примерно столько». Если в ответ звучит «понятия не имеем» — не хватает информации или нужен отдельный research-спайк.
S — SmallМаленькаяВлезает в спринт с запасом. Хорошая планка: не больше пары дней работы на историю.
T — TestableПроверяемаяЕсть способ доказать, что сделано. Отсюда напрямую растут критерии приёмки.

INVEST — не бюрократический ритуал, а быстрый фильтр. На груминге по нему проходятся за 20 секунд, и «эта история не Small» — совершенно нормальный вердикт, после которого историю режут на две.

Критерии приёмки: Given / When / Then

Критерии приёмки (acceptance criteria) — список условий, при выполнении которых история считается сделанной с точки зрения заказчика. Это ответ на вопрос «как мы поймём, что получилось».

Самый удобный формат — сценарии в стиле Given/When/Then (он же Gherkin, язык из BDD — Behavior-Driven Development):

  • Given — исходное состояние («дано»);
  • When — действие пользователя («когда»);
  • Then — ожидаемый результат («тогда»).

Для нашей истории с отменой заказа критерии выглядят так:

Сценарий 1: отмена до отправки
  Дано: заказ №1042 в статусе «Оплачен», не передан в доставку
  Когда: покупатель нажимает «Отменить заказ» и подтверждает
  Тогда: статус меняется на «Отменён»,
         деньги ставятся в очередь на возврат,
         покупателю уходит письмо об отмене

Сценарий 2: отмена после отправки невозможна
  Дано: заказ №1042 в статусе «Передан курьеру»
  Когда: покупатель открывает страницу заказа
  Тогда: кнопки «Отменить заказ» нет,
         показана ссылка «Оформить возврат»

Сценарий 3: повторная отмена
  Дано: заказ №1042 уже в статусе «Отменён»
  Когда: покупатель повторно отправляет запрос на отмену
  Тогда: статус не меняется, второе письмо не отправляется

Три сценария — и половина будущих багов уже обсуждена на берегу. Сценарий 3 (повторный клик, гонка запросов) — классическая дыра, которую в формате «просто список требований» забывают, а в формате Given/When/Then он напрашивается сам.

Важная деталь: критерии приёмки пишет не тестировщик в одиночку и не аналитик в вакууме. Их формулируют вместе — владелец продукта приносит намерение, разработчик приносит вопросы про краевые случаи, тестировщик приносит подозрения. Эта встреча на троих в Agile-мире называется Three Amigos.

Плохая история и хорошая

Смотрим на реальную карточку, какие приносят в бэклог чаще всего:

ПЛОХО

Заголовок: Личный кабинет
Описание: Нужен личный кабинет как у конкурентов.
          Сделать красиво. Срочно!
Оценка: ???

Что здесь не так: нет роли (кто именно и что там делает?), нет ценности (что человек не может сделать сегодня?), нет границ («личный кабинет» — это месяцы работы, не история), нет ни одного проверяемого условия. Слово «красиво» непроверяемо в принципе, а «срочно» — это не приоритет, это эмоция.

Та же потребность, разложенная нормально:

ХОРОШО

Заголовок: История заказов в личном кабинете

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

Критерии приёмки:
  Дано: покупатель авторизован и у него есть 3 заказа
  Когда: он открывает раздел «Мои заказы»
  Тогда: заказы показаны от новых к старым,
         у каждого — дата, сумма, статус, кнопка «Повторить»

  Дано: у покупателя нет ни одного заказа
  Когда: он открывает раздел «Мои заказы»
  Тогда: показан пустой экран с текстом и ссылкой в каталог

  Дано: заказов больше 20
  Когда: покупатель прокручивает список вниз
  Тогда: подгружается следующая страница по 20 штук

Вне рамок: отмена и возврат заказа (отдельные истории)
Оценка: 5

Разница не в объёме текста — хорошая карточка не длиннее плохой. Разница в том, что по ней можно начать работать сегодня, не назначая совещание. И отдельная строчка «вне рамок» — недооценённый приём: она защищает от расползания задачи прямо посреди спринта.

Как это работает

История живёт по циклу «три C» (формулировка Рона Джеффриса):

  • Card (карточка) — короткий текст истории. Специально короткий: он должен помещаться на стикер, чтобы никто не соблазнился написать туда ТЗ.
  • Conversation (разговор) — обсуждение деталей с владельцем продукта. Основная работа происходит здесь, а не в тексте.
  • Confirmation (подтверждение) — критерии приёмки, зафиксированные по итогам разговора. Это то, что превращает договорённость в проверяемый факт.

Если история слишком большая, её называют эпиком (epic) и режут. Режут не по слоям («сделать бэкенд» + «сделать фронтенд» — так нельзя, ни один кусок сам по себе не даёт ценности), а по сценариям: сначала показ списка заказов, потом фильтры, потом повтор заказа. Каждый кусок можно выкатить и получить обратную связь.

И ещё: истории покрывают не всё. Требования вроде «страница открывается меньше чем за 2 секунды на 3G» или «интерфейс доступен с клавиатуры» — это нефункциональные требования. Их не размазывают по историям, а выносят в Definition of Done, о чём будет отдельный урок.

Частые ошибки

  • Роль всегда «пользователь». Если во всех историях подряд стоит «Как пользователь…», формула превратилась в ритуал. Роль должна различать людей с разными потребностями: гость и постоянный покупатель хотят разного.
  • Ценность-заглушка. «…чтобы пользоваться функцией отмены заказа» — это не ценность, это пересказ действия другими словами. Признак: если убрать третью часть, смысл не изменится, — значит, её и не было.
  • История как техзадание. В карточку вписывают названия таблиц, эндпоинтов и имена CSS-классов. Тогда исчезает N из INVEST: команде нечего обсуждать, ей выдали решение. Как делать — решает команда, что и зачем — владелец продукта.
  • Критерии приёмки вместо тест-кейсов. Обратная крайность: 30 сценариев Given/When/Then на одну историю, включая проверку каждого поля формы. Критерии — это ключевые условия приёмки, а не полный тест-план. Пять-семь сценариев — потолок; больше — сигнал, что историю пора резать.
  • Критерии дописывают после разработки. Тогда они превращаются в описание того, что успели сделать, и теряют весь смысл. Критерии — это договор до, а не протокол после.
  • Непроверяемые формулировки. «Удобно», «быстро», «интуитивно понятно» проверить нельзя. «Быстро» превращается в «ответ приходит быстрее 300 мс на 95-м перцентиле» — и вот это уже критерий.

Итоги

  • User story описывает потребность человека, а не решение: Как <роль>, я хочу <действие>, чтобы <ценность>. Третья часть — самая важная и самая часто выбрасываемая.
  • История — это приглашение к разговору (три C: Card, Conversation, Confirmation), а не документ, заменяющий разговор.
  • INVEST — быстрый фильтр: независимая, обсуждаемая, ценная, оцениваемая, маленькая, проверяемая.
  • Критерии приёмки в формате Given/When/Then делают историю проверяемой и вытаскивают краевые случаи до того, как они станут багами.
  • Слишком большая история — это эпик; резать его надо по сценариям ценности, а не по слоям архитектуры.
  • Нефункциональные требования (скорость, доступность, безопасность) живут не в историях, а в Definition of Done.
Проверьте себя
1. Какая из формулировок ближе всего к корректной user story?
AКак пользователь, я хочу, чтобы система сохраняла данные в таблицу orders через POST /api/orders
BКак курьер, я хочу отметить заказ доставленным прямо на месте, чтобы не возвращаться в приложение вечером и не путать адреса
CРеализовать модальное окно подтверждения с двумя кнопками, срочно
DКак пользователь, я хочу пользоваться функцией отмены, чтобы отменять
2. Что означает буква S в аббревиатуре INVEST?
ASpecific — требование сформулировано максимально детально, вплоть до имён полей
BStable — требование больше не будет меняться после попадания в бэклог
CSmall — история достаточно мала, чтобы спокойно поместиться в спринт
DScheduled — у истории проставлен срок сдачи