Work Decomposition

Break features into small, deliverable increments that can be completed in 2 days or less.

Phase 1 - Foundations | Scope: Team

Trunk-based development requires daily integration, and daily integration requires small work. This page covers the techniques for breaking work into small, deliverable increments that flow through your pipeline continuously.

Why Small Work Matters for CD

Continuous delivery depends on a core principle: small changes, integrated frequently, are safer than large changes integrated rarely.

Every practice in Phase 1 reinforces this:

  • Trunk-based development requires that you integrate at least daily. You cannot integrate a two-week feature daily unless you decompose it.
  • Testing fundamentals work best when each change is small enough to test thoroughly.
  • Code review is fast when the change is small. A 50-line change can be reviewed in minutes. A 2,000-line change takes hours - if it gets reviewed at all.

The DORA research consistently shows that smaller batch sizes correlate with higher delivery performance. Small changes have:

  • Lower risk: If a small change breaks something, the blast radius is limited, and the cause is obvious.
  • Faster feedback: A small change gets through the pipeline quickly. You learn whether it works today, not next week.
  • Easier rollback: Rolling back a 50-line change is straightforward. Rolling back a 2,000-line change often requires a new deployment.
  • Better flow: Small work items move through the system predictably. Large work items block queues and create bottlenecks.

The 2-Day Rule

If a work item takes longer than 2 days to complete, it is too big.

Two days gives you at least one integration to trunk per day (the minimum for TBD) and allows for the natural rhythm of development: plan, implement, test, integrate, move on.

When a developer says “this will take a week,” the answer is not “go faster.” The answer is “break it into smaller pieces.”

What “Complete” Means

A work item is complete when it is:

If a story requires a feature flag to hide incomplete user-facing behavior, that is fine. The code is still integrated, tested, and deployable.

Story Slicing Techniques

The INVEST Criteria

Good stories follow INVEST:

CriterionMeaningWhy It Matters for CD
IndependentCan be developed and deployed without waiting for other storiesEnables parallel work
NegotiableDetails can be discussed and adjustedHelps find the smallest valuable slice
ValuableDelivers something meaningful to the user or the systemPrevents technical stories that stall the product
EstimableSmall enough that the team can reasonably estimate itLarge stories hide unknowns
SmallCompletable within 2 daysEnables daily integration
TestableHas clear acceptance criteria that can be automatedSupports the testing foundation

Vertical Slicing

The most important slicing technique for CD is vertical slicing: cutting through all layers of the application to deliver a thin but complete slice of functionality.

Vertical slice (correct):

“As a user, I can log in with my email and password.”

This slice touches the UI (login form), the API (authentication endpoint), and the database (user lookup). It is deployable and testable end-to-end.

Horizontal slice (anti-pattern):

“Build the database schema for user accounts.” “Build the authentication API.” “Build the login form UI.”

Each horizontal slice is incomplete on its own. None is deployable. None is testable end-to-end. They create dependencies between work items and block flow.

Vertical slicing in distributed systems

Not every team owns the full stack from UI to database. A subdomain product team may own a service whose consumers are other services, not humans. The principle still applies: a vertical slice cuts through all layers your team owns and delivers complete, observable behavior through your team’s public interface.

Does this change deliver complete behavior through the interface your team owns? For a full-stack product team, that interface is a UI. For a subdomain team, it is an API contract. If the change only touches one layer beneath that interface, it is a horizontal slice regardless of how you label it.

See Horizontal Slicing for how layer-by-layer splitting fails in distributed systems.

Slicing Strategies

When a story feels too big, apply one of these strategies:

StrategyHow It WorksExample
By workflow stepImplement one step of a multi-step process“User can add items to cart” (before “user can checkout”)
By business ruleImplement one rule at a time“Orders over $100 get free shipping” (before “orders ship to international addresses”)
By data variationHandle one data type first“Support credit card payments” (before “support PayPal”)
By operationImplement CRUD operations separately“Create a new customer” (before “edit customer” or “delete customer”)
By performanceGet it working first, optimize later“Search returns results” (before “search returns results in under 200ms”)
By platformSupport one platform first“Works on desktop web” (before “works on mobile”)
Happy path firstImplement the success case first“User completes checkout” (before “user sees error when payment fails”)

Example: Decomposing a Feature

Original story (too big):

“As a user, I can manage my profile including name, email, avatar, password, notification preferences, and two-factor authentication.”

Decomposed into vertical slices:

  1. “User can view their current profile information” (read-only display)
  2. “User can update their name” (simplest edit)
  3. “User can update their email with verification” (adds email flow)
  4. “User can upload an avatar image” (adds file handling)
  5. “User can change their password” (adds security validation)
  6. “User can configure notification preferences” (adds preferences)
  7. “User can enable two-factor authentication” (adds 2FA flow)

Each slice is independently deployable, testable, and completable within 2 days.

Use BDD scenarios to find slice boundaries

BDD scenarios are the most reliable way to find slice boundaries. Each Given-When-Then scenario becomes a candidate work item with clear scope and testable acceptance criteria. A brief “Three Amigos” conversation (business, development, testing perspectives) before work begins surfaces these scenarios naturally.

Given-When-Then: user login scenarios
Feature: User login

  Scenario: Successful login with valid credentials
    Given a registered user with email "user@example.com"
    When they enter their correct password and click "Log in"
    Then they are redirected to the dashboard

  Scenario: Failed login with wrong password
    Given a registered user with email "user@example.com"
    When they enter an incorrect password and click "Log in"
    Then they see the message "Invalid email or password"
    And they remain on the login page

Each scenario is a natural unit of work. Implement one scenario at a time, integrate to trunk after each one.

Task Decomposition Within Stories

Even well-sliced stories may contain multiple tasks. Decompose stories into tasks that can be completed and integrated independently.

Example story: “User can update their name”

Tasks:

  1. Display the current name on the profile page (read-only, end-to-end through UI and API, integration test)
  2. Add an editable name field that saves successfully (UI, API, and persistence in one pass, E2E test)
  3. Show a validation error when the name is blank (adds one business rule across all layers, unit and E2E test)

Each task delivers a thin vertical slice of behavior and results in a commit to trunk. The story is completed through a series of small integrations, not one large merge.

Guidelines for task decomposition:

  • Each task should take hours, not days
  • Each task should leave trunk in a working state after integration
  • Tasks should be ordered so that the simplest changes come first
  • If a task requires a feature flag or stub to be integrated safely, that is fine

Common Anti-Patterns

  • Horizontal Slicing: Stories organized by layer (“build the schema,” “build the API,” “build the UI”). No individual slice is deployable.
  • Monolithic Work Items: Stories with 10+ acceptance criteria or multi-week estimates. Break them into smaller stories using the slicing strategies above.
  • Technical stories without business context: Backlog items like “refactor the database access layer” that do not tie to a business outcome. Embed technical improvements in feature stories and keep them under 2 days.
  • Splitting by role instead of by behavior: Separate stories for “frontend developer builds the UI” and “backend developer builds the API” create handoff dependencies and delay integration. Write stories from the user’s perspective so the same developer (or pair) implements the full vertical slice.
  • Deferring edge cases indefinitely: Building the happy path and creating a backlog of “handle error case X” stories that never get prioritized. Error handling is not optional. Include the most important error cases in the initial decomposition and schedule them immediately after the happy path, not “someday.”

Measuring Success

MetricTargetWhy It Matters
Story cycle time< 2 days from start to trunkConfirms stories are small enough
Development cycle timeDecreasingShows improved flow from smaller work
Stories completed per weekIncreasing (with same team size)Indicates better decomposition and less rework
Work in progressDecreasingFewer large stories blocking the pipeline

Next Step

Continue to Code Review to learn how to keep review fast and effective without becoming a bottleneck.