коротко

Большая задача — это задача, которую нельзя честно оценить, нельзя распараллелить и нельзя сдать по частям. Декомпозиция чинит всё три: мелкий кусок оценивается точнее, куски берут разные люди, а первая ценность доходит до пользователя раньше. Главный приём — вертикальная нарезка: каждый кусок — тонкий, но сквозной срез через все слои (интерфейс, логика, данные), который сам по себе приносит пользу. Антипаттерн — горизонтальная нарезка по слоям («сначала вся база, потом весь бэкенд, потом весь фронт»): по отдельности куски бесполезны, ценность приходит только в самом конце. Хороший кусок проверяют по INVEST: независимый, обсуждаемый, ценный, оцениваемый, маленький, тестируемый.

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

Декомпозиция — это не «нарезать помельче, чтобы было много тикетов». Это умение отрезать кусок так, чтобы он сам по себе что-то значил. Этому навыку учатся дольше, чем написанию требований, и именно он отличает аналитика, который двигает поставку, от того, кто плодит карточки.

Зачем вообще дробить

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

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

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

Вертикальная и горизонтальная нарезка

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

Горизонтальная нарезка режет по техническим слоям. Сначала «сделать всю базу данных», потом «весь бэкенд», потом «весь фронтенд». Звучит логично для разработчика — каждый делает свой слой. Но для поставки ценности это антипаттерн: ни один кусок по отдельности не работает. Готовая база без интерфейса не показывает пользователю ничего. Ценность появляется только когда сойдутся все слои — то есть в самом конце, как в моей истории с личным кабинетом.

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

flowchart TB
  subgraph H["Горизонтально (антипаттерн)"]
    direction TB
    H1["Вся база данных"] --> H2["Весь бэкенд"] --> H3["Весь фронтенд"]
    H3 --> HV["ценность только в конце"]
  end
  subgraph V["Вертикально (как надо)"]
    direction LR
    V1["Кусок 1: UI+логика+данные"] --> VV1["польза сразу"]
    V2["Кусок 2: UI+логика+данные"] --> VV2["польза сразу"]
    V3["Кусок 3: UI+логика+данные"] --> VV3["польза сразу"]
  end

Схема выше противопоставляет два подхода. Сверху горизонтальный: три слоя идут друг за другом — сначала база, потом бэкенд, потом фронт, — и пользователь не получает ничего, пока не готов последний слой, ценность капает одним разом в самом конце. Снизу вертикальный: три независимых куска, и каждый — это тонкий срез сразу через все слои (немного интерфейса, немного логики, немного данных), поэтому каждый кусок приносит пользу сразу после готовности. Главное отличие: горизонтальные куски бесполезны поодиночке, вертикальные — каждый ценен сам по себе. Поэтому режьте поперёк слоёв, а не вдоль.

Признак, что вы режете горизонтально

Если в названиях ваших кусков есть слова «база», «бэкенд», «фронтенд», «API», «интеграция» — почти наверняка вы режете по слоям. Имя хорошего вертикального куска описывает пользовательский результат: «пользователь видит имя и email в профиле», а не «эндпоинт GET /profile». Кусок должен называться тем, что станет правдой для пользователя, когда кусок готов.

Каким должен быть хороший кусок: INVEST

Чтобы не спорить «достаточно ли мелко» на ощущениях, есть чек-лист — аббревиатура INVEST. Шесть свойств хорошего куска (обычно — user story; что это такое, разбирается в записи про user story и use case).

БукваСвойствоЧто значит на практике
IIndependent (независимый)Кусок можно сделать и выкатить отдельно, не дожидаясь трёх других
NNegotiable (обсуждаемый)Это не жёсткий контракт, а повод договориться о деталях с командой
VValuable (ценный)Приносит пользу пользователю или бизнесу сам по себе
EEstimable (оцениваемый)Команда понимает, что внутри, и может прикинуть срок
SSmall (маленький)Влезает в один спринт, лучше — в несколько дней
TTestable (тестируемый)Есть критерии приёмки, по которым видно, что кусок готов

Не нужно молиться на каждую букву. INVEST — это лупа, через которую смотришь на кусок и видишь, что с ним не так. Не можете оценить (E)? — внутри слишком много неизвестного, копайте. Не ценен сам по себе (V)? — вы, скорее всего, отрезали горизонтальный слой. Не тестируемый (T)? — нет критериев приёмки, кусок не готов идти в работу.

Приёмы: как именно резать

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

  • По сценариям и шагам. Фича «оформление заказа» = выбор товара → адрес доставки → оплата → подтверждение. Каждый шаг — отдельный кусок.
  • По данным. Сначала вывести в профиле только имя и email, потом — телефон, потом — историю заказов. Каждое поле или группа полей — кусок.
  • По правилам. Сначала оформление без скидок, потом отдельным куском — скидки, потом — промокоды. Каждое бизнес-правило накручивается поверх работающего минимума.
  • Happy path сначала. Первый кусок — только успешный сценарий (карта валидна, всё хорошо). Обработка ошибок, повторов, граничных случаев — следующими кусками. Так вы быстро получаете работающий скелет, а потом наращиваете надёжность.

Happy path — самый недооценённый приём

Соблазн — сразу описать все ветки и ошибки в одном куске. Но «оформить заказ, когда всё хорошо» и «обработать десять способов, которыми оплата может упасть» — это очень разный объём работы и риска. Отрежьте happy path первым: он маленький, ценный (демо уже можно показать) и тестируемый. Ветки ошибок добавляйте отдельными кусками — каждый со своими критериями приёмки.

Пример: режем «фильтр каталога»

Прилетела задача: «сделать фильтрацию товаров в каталоге». Звучит как один тикет. Разрежем вертикально.

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

Теперь по правилу — каждый кусок сквозной и ценный сам по себе:

Кусок 1 (happy path, по данным):
  фильтр по одной категории — выпадающий список + запрос + выдача.
  Пользователь уже может сузить каталог. Можно выкатывать.

Кусок 2 (по данным):
  добавить фильтр по цене (от/до) поверх работающего куска 1.

Кусок 3 (по правилам):
  показывать рядом счётчик «найдено N товаров».

Кусок 4 (ветка):
  пустая выдача — экран «ничего не найдено, сбросить фильтры».

После куска 1 у пользователя уже есть работающая фильтрация по категории — узкая, но настоящая, её можно выкатить и собрать обратную связь. Каждый следующий кусок накручивает ценность поверх работающего, а не достраивает половину системы в надежде, что в конце всё сойдётся. Если после куска 2 приоритеты сменятся — вы остановитесь с работающей фичей, а не с грудой недоделанных слоёв. И заметьте: критерии приёмки к каждому куску пишутся отдельно — это часть того, чтобы кусок вообще был готов идти в работу, про что подробнее в записи как написать ТЗ.

Откуда это взялось

Критерии INVEST сформулировал Билл Уэйк в 2003 году — он же придумал саму аббревиатуру как удобную проверку качества user story в Extreme Programming. Сама практика «нарезки историй» (story splitting) выросла в agile-сообществе в 2000-х вместе с короткими итерациями: раз спринт всего две недели, большую фичу физически нельзя взять целиком — приходится резать. Идея вертикального среза («walking skeleton», тонкий работающий скелет через все слои) старше и шире agile, но именно итеративная разработка сделала её повседневным навыком аналитика, а не теорией.

Частые вопросы

Как декомпозировать большую задачу?

Режьте её вертикально — тонкими сквозными срезами через все слои (интерфейс, логика, данные), где каждый кусок приносит пользу сам по себе и его можно выкатить отдельно. Не режьте горизонтально по слоям («вся база», «весь бэкенд») — такие куски бесполезны поодиночке. Рабочие приёмы: резать по шагам сценария, по данным (поле за полем), по бизнес-правилам и отрезать happy path первым. Каждый кусок проверяйте по INVEST: независимый, ценный, оцениваемый, маленький, тестируемый.

Что такое INVEST?

INVEST — это чек-лист из шести свойств хорошего куска работы (обычно user story): Independent (независимый, делается отдельно), Negotiable (обсуждаемый, не жёсткий контракт), Valuable (ценный сам по себе), Estimable (оцениваемый), Small (маленький, влезает в спринт), Testable (тестируемый, есть критерии приёмки). Это не закон, а лупа: если кусок не проходит по какой-то букве, она подсказывает, что с ним не так.

Чем вертикальная нарезка отличается от горизонтальной?

Горизонтальная режет задачу по техническим слоям: сначала вся база, потом весь бэкенд, потом весь фронт — и ценность доходит до пользователя только в самом конце, когда слои сойдутся. Вертикальная режет поперёк слоёв: каждый кусок — тонкий сквозной срез сразу через интерфейс, логику и данные, который работает и приносит пользу сам по себе. Для поставки ценности горизонтальная нарезка — антипаттерн, режьте вертикально.