Поступает задача от product owner: «Добавить промокоды в интернет-магазин». Работу разбивают на подзадачи: создать таблицу промокодов, сделать API для их применения, добавить поле ввода в корзине и изменить расчёт стоимости заказа. Backend-разработчик начинает со схемы данных и API, frontend-разработчик параллельно добавляет поле для промокода.

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

Часть подзадач уже выполнена, но закончить пользовательский сценарий без ответов на эти вопросы нельзя.

При этом сама декомпозиция выглядит вполне разумно: есть отдельные задачи на базу данных, backend и frontend, у каждой есть исполнитель и понятный результат. Но эти результаты существуют только по отдельности. Готовая таблица или поле в корзине ещё не позволяют покупателю воспользоваться промокодом.

Проблема становится заметна только в процессе разработки: команда декомпозировала решение до того, как определила минимальный законченный сценарий.

Определить цель

Формулировка «Добавить промокоды в интернет-магазин» обозначает новую функциональность, но почти ничего не говорит о том, зачем она нужна. Бизнес может хотеть вернуть покупателей, которые давно ничего не заказывали, повысить конверсию рекламной кампании или стимулировать первую покупку. От цели зависит и то, какие промокоды действительно нужны.

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

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

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

От цели работа постепенно переходит к реализации.

Одна из историй может звучать так:

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

Большую функциональность можно объединить в эпик «Промокоды», а внутри него выделить историю. Внутри этой истории будут технические задачи: хранение промокодов, проверка кода, расчёт скидки, отображение результата в корзине. При этом команда должна сохранять связь между техническими частями и пользовательским сценарием. Готовая таблица промокодов не означает, что покупатель сможет получить скидку.

Выбрать направление декомпозиции

Задачу можно декомпозировать горизонтально или вертикально. Эти подходы не исключают друг друга: на разных этапах проекта может быть полезен каждый из них.

Горизонтальная декомпозиция разделяет работу по техническим слоям или компонентам системы. Например: отдельно подготовить базу данных, реализовать API и сделать интерфейс.

Такой подход полезен, когда сначала нужно создать основу для дальнейшей разработки. Представим новый сервис, в котором ещё нет структуры базы данных и каркаса приложения. Первые задачи могут выглядеть так:

  • подготовить схему базы данных и основные модели;
  • определить структуру API;
  • создать каркас контроллеров;
  • настроить общие зависимости и инфраструктуру.

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

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

Когда базовая структура появилась, можно перейти к вертикальной декомпозиции — по законченным пользовательским сценариям. Вместо отдельных задач «сделать таблицу», «сделать API» и «сделать frontend» команда берёт небольшой пользовательский сценарий и реализует все необходимые для него части системы.

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

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

Разделить работу по пользовательским сценариям

Для промокодов первым сценарием может быть: пользователь вводит один действующий промокод на скидку 10% и видит уменьшенную стоимость заказа.

Следующими частями могут стать:

  • промокоды с фиксированной скидкой;
  • одноразовые промокоды;
  • ограничение срока действия;
  • восстановление промокода после отмены заказа.

Каждый такой шаг расширяет уже работающую возможность и позволяет отдельно проверить результат.

Выделять небольшие сценарии можно несколькими способами:

  • По сценариям использования: сначала основной путь, затем дополнительные варианты и граничные случаи.
  • По типам данных или вариантам обработки: например, сначала процентная скидка, затем фиксированная.
  • По операциям: отдельно реализовать создание, просмотр, изменение и удаление объекта.
  • По ролям: выделять возможности покупателя, администратора или сотрудника поддержки.

Выбор зависит от задачи. Полезно проверять, можно ли показать результат каждой части, объяснить её пользу и однозначно определить, что она завершена.

При этом отложить на потом все сложные случаи не получится. Граница проходит не по сложности, а по двум вопросам: столкнётся ли с этим случаем обычный пользователь и чем обойдётся неверное поведение. Опечатка в промокоде — обычное дело, поэтому понятная реакция на неизвестный код нужна в первом же выпуске. Применение одного промокода дважды меняет сумму заказа, поэтому проверка тоже не ждёт. А восстановление промокода после отмены заказа требует отдельного редкого действия и спокойно уходит в следующую часть. Так первый сценарий остаётся пригодным для использования: он работает не только на правильно введённых данных, а во всех условиях, о которых команда договорилась.

Перед стартом разбиение полезно перечитать ещё раз. Вернуться к нему стоит, если:

  • подзадача названа процессом, а не результатом: «работать над расчётом скидки» вместо «применять процентную скидку к стоимости заказа»;
  • у подзадачи нет владельца: её никто не берёт, потому что непонятно, чья это часть;
  • подзадачи можно делать только последовательно: в нарезке не осталось параллельной работы, и весь сценарий движется со скоростью одного человека;
  • закрытие подзадачи не приближает сценарий к готовности: на доске видно движение, а в продукте нет.

Исследовать то, что пока нельзя спланировать

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

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

Если способ реализации пока неясен, можно выделить spike — ограниченное по времени исследование, которое помогает снизить неопределённость перед разработкой.

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

Исследование считается завершённым, когда команда получила ответ, решение или список обнаруженных ограничений. На этой основе команда сможет осознанно выделить время на продолжение исследования или изменить подход.

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

Описать результат и границы задачи

Фразы «сделать промокоды» или «добавить скидки» оставляют слишком много места для интерпретаций.

Хорошее описание отвечает на вопросы:

  1. Почему задача нужна? Context.
  2. Какой конкретный результат требуется?
  3. Что находится за её пределами? Out of scope.
  4. По каким условиям результат будут принимать? Acceptance criteria.
  5. Какие технические материалы и зависимости нужно учитывать?
  6. Какие общие требования качества необходимо выполнить? Definition of Done

Для первого сценария с промокодами можно явно определить границы.

В задачу входит один тип промокода — процентная скидка. Пользователь может применить только один промокод. Промокод действует только на товары без других скидок.

Фиксированные скидки, несколько промокодов одновременно, админка промокодов и остальная функциональность относятся к следующим этапам.

Такие границы помогают удерживать объём работы и обсуждать новые требования как изменение плана.

Можно использовать набор вопросов для самопроверки INVEST — короткий чек-лист качества пользовательской истории.

Критерий Вопрос к задаче
I — Independent (независимая) Можно ли сделать и проверить её, не дожидаясь другой задачи?
N — Negotiable (обсуждаемая) Сказано ли, что нужно пользователю и зачем, без готового решения за команду?
V — Valuable (ценная) Видно ли, какую проблему пользователя или выгоду бизнеса она закрывает?
E — Estimable (оцениваемая) Хватает ли команде контекста, чтобы оценить объём?
S — Small (компактная) Можно ли закончить её внутри одной итерации?
T — Testable (проверяемая) Есть ли проверяемые критерии приёмки?

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

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

Разделить DoR, критерии приёмки и DoD

Definition of Ready, Acceptance Criteria и Definition of Done отвечают на разные вопросы.

Договорённость Основной вопрос Содержание
Definition of Ready (DoR) Можно ли начинать работу? Контекст, границы, согласованные требования, понятные зависимости
Acceptance Criteria (AC) Получено ли нужное поведение? Проверяемые условия конкретной задачи
Definition of Done (DoD) Соответствует ли результат стандарту команды? Ревью, проверки, документация и другие согласованные требования качества

Definition of Ready помогает избежать ситуации из начала статьи. До старта разработки команда могла проверить, определены ли основные правила применения промокода:

  • можно ли применять его к товарам со скидкой;
  • сколько промокодов можно использовать;
  • в какой момент промокод считается использованным;
  • что происходит при отмене заказа.

Если эти решения необходимы для первого сценария, отсутствие ответов означает, что задача ещё не готова к полноценной реализации. Наличие списка технических подзадач само по себе не делает её готовой.

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

  • задача описана: есть контекст, границы и то, что за них вынесено;
  • критерии приёмки сформулированы и согласованы;
  • задача оценена командой;
  • макеты готовы, если они нужны;
  • зависимости от других команд и сервисов прояснены;
  • задача помещается в одну итерацию.

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

Acceptance Criteria описывают ожидаемое поведение готовой задачи в проверяемом виде. Для сценария с промокодом это может выглядеть так:

  • действующий промокод уменьшает стоимость подходящих товаров на 10%;
  • после применения пользователь видит размер скидки и новую итоговую стоимость;
  • неизвестный или недействующий промокод не изменяет стоимость заказа;
  • к одному заказу можно применить только один промокод;
  • промокод не применяется к товарам, которые уже участвуют в акции.

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

Плохие критерии выглядят иначе — их нельзя ни принять, ни отклонить:

  • «Промокод работает корректно» — что здесь считать корректным?
  • «Корзина быстро пересчитывается» — быстро это сколько?
  • «Пользователю понятно, что скидка применилась» — понятно кому и по какому признаку?

Помогает простая проверка: критерий должен быть проверяем человеком за короткий промежуток времени. Если проверка превращается в отдельное расследование, формулировку нужно уточнить.

Definition of Done задаёт общую планку качества: код прошёл ревью, необходимые тесты выполнены, критерии приёмки проверены, изменения доступны, документация обновлена. DoD одинаков для всех задач команды, а критерии приёмки свои у каждой.

Проверить, одинаково ли команда понимает сценарий

Даже хорошо описанные задачи могут привести к разным результатам, если участники по-разному понимают общую логику.

Перед началом работы полезно вместе пройти весь сценарий:

Пользователь добавляет товары → вводит промокод → система проверяет его → рассчитывает скидку → показывает новую стоимость → пользователь оплачивает заказ → использование промокода фиксируется.

Уже при таком проходе появляются вопросы:

  • Что происходит, если срок действия промокода закончился, пока пользователь оформлял заказ?
  • Что делать, если после применения промокода изменился состав корзины?
  • Когда считать промокод использованным: при создании заказа или после оплаты?
  • Можно ли повторно использовать его после отмены заказа?

Для более сложных процессов можно использовать Event Storming: совместное обсуждение системы через события, команды и бизнес-правила. Результатом обсуждения становятся согласованные правила, список открытых вопросов и черновая декомпозиция. Вопросы, требующие исследования, можно вынести в отдельные spike-задачи.

Определить зависимости и порядок работы

Небольшие задачи не обязательно независимы. Frontend-разработчик может быстро сделать поле для ввода промокода, но для полноценной интеграции ему потребуется API. Backend-разработчик при этом может начать с административного создания промокодов и оставить метод применения на конец спринта. Обе задачи формально имеют высокий приоритет и находятся в одном спринте. Но порядок работы приводит к тому, что frontend заканчивает свою часть и ждёт backend.

Если зависимость видна заранее, порядок можно изменить: сначала реализовать минимальный контракт применения промокода, а административные возможности закончить позже. Другой вариант — заранее согласовать контракт и использовать mock, если это действительно позволяет независимо проверить часть работы.

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

Контракт API
  ├── API применения промокода ──┐
  └── Поле ввода в корзине ──────┴──> Сквозной тест «заказ с промокодом»

Админка создания промокодов — в сценарий не входит, идёт параллельно

Когда контракт согласован, backend реализует API, а frontend собирает поле ввода на mock-ответах: эти задачи идут одновременно. Сквозной тест возможен только после того, как готовы обе части. Админка в сценарий не входит, поэтому её ведут рядом, не встраивая в цепочку.

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

                     ┌──> API применения (3 д) ─────┐
Контракт API (1 д) ──┤                              ├──> Приёмка (1 д)
                     └──> Поле в корзине (2 д) ─────┘

Админка промокодов (3 д) — в сценарий не входит, идёт параллельно

Самая длинная цепочка проходит через API: 1 день на контракт, 3 дня на реализацию и 1 день на приёмку — всего 5 дней. Раньше этого срока сценарий не закончится при любом числе людей в команде. Уложится ли он ровно в 5 дней, зависит уже от того, успеют ли к приёмке параллельные ветки.

Эта цепочка и есть критический путь: задержка API на день сдвинет приёмку, а вместе с ней и весь сценарий. Ветка через поле занимает 4 дня против 5, то есть у неё день запаса: опоздание на день срока не изменит, опоздание на два сделает критической уже её. Параллельно на схеме при этом не значит одновременно в жизни: админку делает тот же backend, и если он начнёт с неё, API сдвинется вместе с критическим путём.

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

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

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

Выбрать способ показывать план

План отвечает на три разных вопроса, и одна картинка редко закрывает все три. Обычно достаточно трёх простых представлений, у каждого своя роль:

  • Список сценариев в порядке выпуска (roadmap): показывает направление. Не «сделать API промокодов», а «пользователь применяет процентный промокод в корзине», затем фиксированные скидки, затем админка. Дат внутри списка не нужно: важен порядок.
  • Доска текущих задач: показывает состояние. Видно, что в работе прямо сейчас и что стоит заблокированным, но не видно, почему задачи идут именно в таком порядке.
  • Граф зависимостей с оценками: показывает порядок и критический путь, как в примере выше. Его хватает набросать текстом на две-три строки, чтобы обсудить, кто кого ждёт.

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

Отдельный вопрос — как показывать прогресс. Проценты плохо показывают продуктовый прогресс: 80% выполненных технических задач ещё не означают, что пользователь может воспользоваться функциональностью. Полезнее понимать, какой сценарий уже работает целиком и что отделяет следующий сценарий от выпуска.

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

Помогать команде завершать начатое

Если разработка начинает новые задачи быстрее, чем команда завершает уже начатые сценарии, растёт объём незавершённой работы. Её называют WIP (work in progress) — это всё, что уже начали, но ещё не довели до пользователя.

Например, API применения промокода готово, поле ввода в корзине готово, но сценарий не выпущен: целиком на стенде его ещё никто не прошёл, тексты ошибок для пользователя не согласованы, и нет ответа, что происходит с промокодом после отмены заказа. Backend в это время берёт из бэклога второй тип промокодов, frontend — административный интерфейс.

Формально команда занята и закрывает отдельные технические задачи. С точки зрения пользователя промокодов в магазине всё ещё нет, а «почти готово» держится неделями.

Проверка выпала не случайно. У каждой подзадачи были свои критерии приёмки, и каждый их выполнил: backend прогнал тесты API на своих данных, frontend проверил форму на заглушках. Сквозной проход «пользователь ввёл промокод и увидел итоговую сумму» не входил ни в одну из задач — он возможен только тогда, когда обе части впервые оказываются на одном стенде. Отдельной задачи на него нет, ответственного тоже. Тестировщик в команде ничего не меняет: ему пришли те же две задачи по отдельности, и он закрыл их по отдельности.

Поэтому сквозной проход стоит держать в критериях приёмки сценария, а не подзадач. Тогда он виден в плане как работа, а не как «само проверится».

Остаток сценария обычно не привязан к стеку, поэтому забрать его может любой, кто освободился: пройти сценарий на стенде с истёкшим, исчерпанным и неподходящим к товару промокодом; проверить чужой pull request хотя бы в части контракта и текстов ошибок; получить у product owner недостающее правило; подготовить выкатку за фича-флагом и посмотреть первые ошибки после неё. Backend здесь не садится писать frontend — он доводит до пользователя общий сценарий.

Удерживать WIP помогает WIP-лимит — договорённость о том, сколько работы команда ведёт одновременно. Ограничивают не людей, а единицы работы: например, не больше одного пользовательского сценария в работе или не больше двух задач в колонке «в разработке». Смысл не в том, чтобы работать медленнее, а в том, чтобы законченное появлялось чаще: чем больше начато одновременно, тем дольше каждая вещь ждёт ревью, проверки и выкатки, и тем позже пользователь видит первый результат.

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

Что должен делать лид

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

Постоянная декомпозиция силами одного человека создаёт зависимость от него. Полное делегирование без обсуждения и проверки тоже оставляет риски. Команде нужны ориентиры и возможность разбирать собственные решения.

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