Разработчик говорит: «Готово». Вы открываете задачу — там поле «Критерии приёмки» пустое. Или того хуже: одна строчка «Всё должно работать». Начинается бесконечный цикл: вы проверяете, находите расхождение, разработчик переделывает, вы снова проверяете. Знакомая ситуация?
Проблема не в разработчике. Проблема в том, что критерии приёмки написали так, будто их поймут телепатически. А Definition of Done спутали с Acceptance Criteria — и получился гибрид, который не работает ни для команды, ни для заказчика.
Давайте разложим, что и как писать, чтобы слово «готово» значило одно и то же для всех.
Что такое Acceptance Criteria и зачем они нужны
Acceptance Criteria (AC) — набор проверяемых условий, которые определяют, работает ли история так, как ожидает пользователь. Это не техническая спецификация и не тест-план. Это контракт между постановщиком задачи и разработчиком: «Если эти пункты выполнены — история готова с точки зрения функциональности».
AC привязаны к конкретной пользовательской истории. Одна история — один набор критериев. Если вы проектируете User Story, то AC — это логичное продолжение шаблона «Я как… хочу… чтобы…»: вы превращаете «чтобы» в измеримые пункты. Если тема User Story для вас новая — загляните в разбор шаблонов User Story и Use Case, там описан фундамент.
Без AC происходит классика: разработчик реализовал историю как понял, а вы имели в виду совсем другое. И оба правы — просто не договорились о критериях завершённости. AC снимают эту неоднозначность до того, как написан хоть одна строка кода.
Хорошие vs плохие критерии приёмки
Сравним на примере истории: «Я как покупатель хочу фильтровать товары по цене, чтобы быстро находить товары в своём бюджете».
| Плохо (размыто) | Хорошо (проверяемо) |
|---|---|
| Фильтр по цене работает | Пользователь вводит «от 500, до 3000» и видит только товары, цена которых попадает в этот диапазон |
| Пограничные значения обрабатываются | При вводе «от -100» поле подсвечивается красным, фильтр не применяется |
| Всё быстро грузится | Результат фильтрации отображается не дольше 2 секунд при каталоге до 10 000 товаров |
| Фильтр сбрасывается | Кнопка «Сбросить» очищает оба поля, страница возвращается к полному каталогу |
Разница очевидна. В левом столбце — лозунги. В правом — условия, которые можно протестировать за пять минут и сказать «да» или «нет» без споров. У критерия есть наблюдаемый результат, а не интерпретация.
Формат Given-When-Then
Самый рабочий шаблон для AC — Given-When-Then. Три части задают структуру, которая не даёт скатиться в абстракцию:
- Given — контекст: что уже есть в системе к моменту действия.
- When — действие: что делает пользователь.
- Then — ожидаемый результат: что видит пользователь после действия.
Пример для той же истории с фильтрацией:
Given: в каталоге есть товары с ценами от 100 до 10 000 руб.When: покупатель в поле «Цена до» вводит «500»Then: в каталоге остаются только товары с ценой ≤ 500 руб.Одна проверяемая ситуация = один Given-When-Then. Если у истории три логически разных сценария — пишем три блока. Не пытайтесь упихать всё в один — получится каша.
Ещё пример, из другой предметной области — банковский перевод:
Given: на счету отправителя 5 000 руб., счёт получателя существуетWhen: отправитель вводит сумму перевода 7 000 руб. и нажимает «Перевести»Then: появляется сообщение «Недостаточно средств», перевод не выполняетсяОбратите внимание: здесь Given задаёт состояние системы, When — конкретное действие, Then — видимый для пользователя результат. Никакой магии. Просто сценарий использования, разбитый на шаги.
Одна история обычно набирает 3–7 таких критериев. Меньше трёх — вы что-то упустили. Больше семи — возможно, история слишком большая и её пора делить.
Что такое Definition of Done
Definition of Done (DoD) — глобальный чек-лист команды, применимый ко всем историям, независимо от их содержания. Это не про «работает ли конкретная фича». Это про «сделали ли мы всё, что команда договорилась делать перед тем, как назвать историю завершённой».
Если AC отвечают на вопрос «Правильно ли работает фича?», то DoD — на вопрос «Можно ли выкатывать в прод?». AC уникальны для каждой истории. DoD — един для всей команды.
Типичный DoD бэкенд-команды:
- Код проходит code review
- Написаны и проходят unit-тесты
- Написаны интеграционные тесты для нового эндпоинта
- Логирование добавлено (все внешние вызовы логируются)
- API-документация обновлена
- Миграции БД протестированы на копии прода
- Задача закрыта в Jira с комментарием о сделанных изменениях
Каждый пункт DoD — это операция, которую разработчик делает для каждой задачи, без исключений. Никакой «это маленькая правка, давайте зальём без тестов». Договорились — соблюдаем.
Где проходит граница: AC vs DoD
Спойлер: в реальных проектах новички постоянно путают AC и DoD. Давайте разведём на конкретном примере. История: «Я как администратор хочу деактивировать пользователя, чтобы заблокировать ему доступ к системе».
Acceptance Criteria (для этой истории):
Given: пользователь активен и имеет роль «Менеджер»When: администратор нажимает «Деактивировать» в карточке пользователяThen: статус пользователя меняется на «Неактивен», кнопка «Деактивировать» исчезает
Given: пользователь деактивированWhen: он пытается авторизоваться с логином и паролемThen: система показывает ошибку «Учётная запись заблокирована»Definition of Done (единый для всей команды):
- Код отревьюирован, тесты написаны и проходят
- Сообщение об ошибке вынесено в файл локализации
- Новая роль
deactivatedдобавлена в документацию ролевой модели - Задача в Jira переведена в статус «Готово»
AC описывают поведение этой конкретной фичи. DoD описывает процесс, через который прошла фича, чтобы считаться завершённой.
На практике я часто вижу, как DoD-шные «написаны тесты» или «обновлена документация» пихают в AC. Не надо. AC — про функциональность, которую заказчик может проверить. Тесты и документацию заказчик не проверяет — это внутренние правила команды, им место в DoD.
Как AC и DoD работают в тандеме
По отдельности каждый инструмент полезен. Вместе — закрывают главные источники боли в процессе сдачи задач:
На схеме — двойной фильтр. Сначала AC отсеивают несоответствия функциональности: разработчик проверяет сам (зелёные критерии?), код-ревью и QA гоняют по тем же сценариям. Если на любом из этих этапов AC не пройдены — обратно на разработку. Круг замкнулся.
Дальше — второй контур: Definition of Done. Это gate уже не про фичу, а про процессы команды. Нет тестов — доделываешь. Не обновлена документация — доделываешь. Миграции не протестированы — возвращаешься. Только когда оба фильтра зелёные, история получает статус «готово».
Ключевой момент: обратите внимание на циклы возврата. AC каскадно проверяются трижды — разработчиком, на ревью и тестировщиком. Если тестировщик нашёл расхождение, разработчик возвращается к коду. Это нормально. Ненормально — когда тестировщик впервые видит критерии только на этапе приёмки и интерпретирует их иначе, чем разработчик. Чтобы этого избежать, AC обсуждаются на груминге до старта разработки. Но это уже про процессы, вернёмся к формулировкам.
Типичные антипаттерны
1. «Всё работает»
Вариации: «Система функционирует корректно», «Фича соответствует ожиданиям пользователя», «Всё ОК». Это не критерий — это заклинание. Проверить невозможно, оспорить невозможно, и именно поэтому разработчики любят писать такое в self-check. Не принимайте.
Вместо этого: одно наблюдаемое действие → один измеримый результат. «Система показывает ошибку при пустом поле email» — проверяемо. «Платёж проходит меньше чем за 5 секунд» — измеримо. «Кнопка неактивна, пока не заполнены обязательные поля» — наблюдаемо.
2. AC сформулированы как тест-кейсы
Given: пользователь авторизован, корзина пуста, на складе 8 единиц товара SKU-001When: пользователь добавляет в корзину 3 единицы SKU-001Then: в корзине отображается «3 × SKU-001», остаток на складе — 5Формально это Given-When-Then. Фактически — расползание в детали реализации. Остаток на складе пользователь не видит. Это проверка целостности данных, а не функциональное требование. Такие критерии распухают до 15 штук на историю, и половина проверяет то, что заказчику неинтересно.
AC пишутся от пользователя. Если пользователь не видит разницы между остатком 5 и остатком 8 — это не AC. Это тест-кейс для QA.
3. Смешение DoD и AC
Встречал такое в реальном проекте:
AC:1. При нажатии «Экспорт» формируется XLSX-файл с данными за выбранный период2. Файл содержит все колонки из таблицы3. Написан unit-тест на метод ExportService.export()Пункт 3 — не Acceptance Criteria. Это DoD команды: «на все публичные методы сервисов пишутся unit-тесты». Засунув его в AC, команда либо продублирует эту строчку в каждой из 200 историй, либо начнёт забывать. И то и другое — потеря управляемости.
4. Критерии без негативных сценариев
AC, написанные только для happy path, пропускают ровно те баги, которые пользователи находят в первый час после релиза. Пустое поле, слишком длинный ввод, потеря соединения, дубль запроса — всё это должно быть в критериях.
Правило: на каждый позитивный сценарий — хотя бы один негативный. «Пользователь ввёл email» — «пользователь ввёл строку без собаки». «Пользователь нажал ‘Оплатить’» — «пользователь нажал ‘Оплатить’ дважды». Первое предложение показывает, что фича работает. Второе — что она не ломается.
5. DoD, который никто не соблюдает
Команда на ретро договорилась: «пишем тесты, обновляем документацию, прикладываем скриншоты». Записали в Confluence, разослали в чат. Через две недели половина задач закрывается без тестов. Вывод: DoD, который не встроен в workflow, — фикция.
DoD должен быть автоматизирован везде, где возможно. Проверка код-ревью — hook в GitHub/GitLab. Наличие тестов — pipeline падает, если coverage ниже порога. Jira не даёт перевести задачу в Done без заполненного поля «комментарий о сделанных изменениях». Если DoD держится на честном слове — это не DoD, а благие намерения.
Как внедрить
Начать с простого. Если у вас сейчас критерии приёмки — это «всё работает в соответствии с макетом», а Definition of Done отсутствует как понятие, не пытайтесь ввести всё сразу. Шаг за шагом:
-
Добавьте AC в шаблон User Story. Поле «Критерии приёмки» в Jira или Confluence — и договоритесь, что без заполненного поля задача не уходит на груминг. Три-пять Given-When-Then, не больше. Если ваши пользовательские истории не формализованы — начните с шаблонов функциональных и нефункциональных требований, чтобы выстроить базу.
-
Соберите DoD командой. Не спускайте сверху. Соберитесь, запишите, что каждый считает обязательным перед сдачей задачи. Проголосуйте. Оставьте пункты, с которыми согласны все. Пять-восемь пунктов — нормально для старта.
-
Привяжите DoD к воркфлоу. Если у вас GitLab/GitHub — merge request template с чекбоксами. Jira — Condition в workflow. Физически нельзя перевести задачу в Done, пока не пройдены все DoD-пункты.
-
Пересматривайте раз в квартал. Команда растёт, процессы меняются. То, что было актуально три месяца назад — тормозит сейчас. Раз в квартал ретроспектива: что из DoD устарело, чего не хватает, что занимает время без пользы.
Главное — не превращайте DoD в бюрократию. Если на проставление галочек уходит больше времени, чем на разработку, — вы перестарались. DoD должен защищать качество, а не имитировать процесс.
Чек-лист для аналитика
- AC пишутся от пользователя: наблюдаемое действие → измеримый результат
- Given-When-Then — один сценарий, один блок
- На каждый позитивный AC — хотя бы один негативный
- AC — то, что заказчик может проверить. Тесты и документация — в DoD
- DoD — единый чек-лист команды, не копируется в каждую историю
- DoD без автоматизации — не работает
- Если AC и DoD проходят, а пользователь недоволен — значит, вы неверно поняли его потребность. Откатывайтесь и пересматривайте User Story, а не правьте критерии под удобный результат