GitScrum / Docs
All Best Practices

Writing Effective User Stories | INVEST Criteria Guide

Master user stories with INVEST criteria and Given-When-Then acceptance criteria. Learn story splitting techniques. GitScrum tracks stories in sprints.

9 min read

User stories are not requirements documentsβ€”they're placeholders for conversations. A good user story captures who needs what and why, is small enough to complete in a sprint, and invites discussion about the details. This guide covers writing stories that actually help teams build the right thing.

Story Elements

ElementPurposeExample
User RoleWho benefits"As a customer..."
GoalWhat they want"...I want to save my cart..."
BenefitWhy it matters"...so I can return later"
CriteriaDefinition of done"Cart persists for 30 days"

Story Format

The Classic Template

USER STORY TEMPLATE
═══════════════════

FORMAT:
─────────────────────────────────────
As a [user type]
I want [goal/desire]
So that [benefit/value]

Acceptance Criteria:
β”œβ”€β”€ Given [context], when [action], then [outcome]
β”œβ”€β”€ Given [context], when [action], then [outcome]
└── ...

EXAMPLE:
─────────────────────────────────────
As a frequent shopper
I want to save items to my wishlist
So that I can easily find them later for purchase

Acceptance Criteria:
β”œβ”€β”€ Given I'm on a product page
β”‚   When I click "Add to Wishlist"
β”‚   Then the item appears in my wishlist
β”‚
β”œβ”€β”€ Given I'm viewing my wishlist
β”‚   When I click "Add to Cart" on an item
β”‚   Then the item moves to my cart
β”‚
β”œβ”€β”€ Given I have items in my wishlist
β”‚   When I return next week
β”‚   Then my wishlist items are still there
β”‚
└── Given an item becomes unavailable
    When I view my wishlist
    Then I see "Out of stock" on that item

COMPONENTS EXPLAINED:
─────────────────────────────────────
USER TYPE:
β”œβ”€β”€ Who is this for?
β”œβ”€β”€ Be specific: "New user" vs "Admin" vs "Premium subscriber"
β”œβ”€β”€ Persona if you have them
└── Helps prioritize and design

GOAL:
β”œβ”€β”€ What do they want to do?
β”œβ”€β”€ Functional capability
β”œβ”€β”€ Not HOW, just WHAT
└── User language, not technical

BENEFIT:
β”œβ”€β”€ Why does this matter?
β”œβ”€β”€ The real motivation
β”œβ”€β”€ Helps understand trade-offs
└── Sometimes reveals better solutions

INVEST Criteria

Story Quality Check

INVEST CRITERIA
═══════════════

I - INDEPENDENT
─────────────────────────────────────
Stories should be completable on their own.
Not: "User can pay (requires cart story)"
Yes: Each story deliverable independently

If dependencies exist, note them but minimize.

N - NEGOTIABLE
─────────────────────────────────────
Stories are conversation starters, not contracts.
Details emerge through discussion.
Don't over-specify upfront.
Room for team input on implementation.

V - VALUABLE
─────────────────────────────────────
Each story delivers value to someone.
Not: "Install database" (no user value directly)
Yes: "User can save preferences" (value)

Technical work can be stories, but link to value.

E - ESTIMABLE
─────────────────────────────────────
Team can estimate the effort.
If not estimable:
β”œβ”€β”€ Too vague β†’ Need more detail
β”œβ”€β”€ Too big β†’ Need to split
β”œβ”€β”€ Too new β†’ Need spike/research
└── Team must understand scope

S - SMALL
─────────────────────────────────────
Completable in a sprint, ideally 1-5 days.
If larger: Split into multiple stories.
Smaller stories = faster feedback.

T - TESTABLE
─────────────────────────────────────
Clear acceptance criteria.
You can verify it works.
Not: "Fast performance" (vague)
Yes: "Page loads in under 2 seconds" (testable)

Acceptance Criteria

Writing Good Criteria

ACCEPTANCE CRITERIA
═══════════════════

PURPOSE:
─────────────────────────────────────
β”œβ”€β”€ Define "done" for the story
β”œβ”€β”€ Enable testing
β”œβ”€β”€ Clarify requirements
β”œβ”€β”€ Prevent scope creep
└── Agreement between team and PO

FORMAT (Given-When-Then):
─────────────────────────────────────
Given [precondition/context]
When [action/trigger]
Then [expected outcome]

EXAMPLE STORY:
─────────────────────────────────────
As a user
I want to reset my password
So that I can regain access to my account

Acceptance Criteria:

βœ“ Given I'm on the login page
  When I click "Forgot Password"
  Then I see a form requesting my email

βœ“ Given I enter a registered email
  When I submit the form
  Then I receive a password reset email within 5 min

βœ“ Given I click the reset link in email
  When the link is less than 24 hours old
  Then I see a form to enter new password

βœ“ Given I click the reset link in email
  When the link is more than 24 hours old
  Then I see "Link expired" with option to request new

βœ“ Given I enter a new valid password
  When I submit
  Then my password is changed and I can log in

βœ“ Given I enter invalid password (too short)
  When I submit
  Then I see validation error, password unchanged

CRITERIA GUIDELINES:
─────────────────────────────────────
β”œβ”€β”€ 3-8 criteria per story typically
β”œβ”€β”€ Cover happy path AND edge cases
β”œβ”€β”€ Specific and measurable
β”œβ”€β”€ Written before development
β”œβ”€β”€ Refined in grooming
└── Team and PO agree

Splitting Stories

When and How

STORY SPLITTING TECHNIQUES
══════════════════════════

SPLIT WHEN:
─────────────────────────────────────
β”œβ”€β”€ Story is > 8 points (too big)
β”œβ”€β”€ Can't estimate (too vague)
β”œβ”€β”€ Multiple acceptance criteria clusters
β”œβ”€β”€ Different user flows
β”œβ”€β”€ Takes more than one sprint
└── Team feels uncertain

SPLITTING PATTERNS:
─────────────────────────────────────

1. BY WORKFLOW STEP
   Original: "User can purchase product"
   Split:
   β”œβ”€β”€ User can add to cart
   β”œβ”€β”€ User can enter shipping
   β”œβ”€β”€ User can enter payment
   └── User can confirm purchase

2. BY DATA VARIATION
   Original: "User can log in"
   Split:
   β”œβ”€β”€ User can log in with email/password
   β”œβ”€β”€ User can log in with Google
   └── User can log in with SSO

3. BY BUSINESS RULE
   Original: "User can apply discount"
   Split:
   β”œβ”€β”€ User can apply percentage discount
   β”œβ”€β”€ User can apply fixed amount discount
   └── User can apply free shipping discount

4. BY OPERATION (CRUD)
   Original: "User can manage contacts"
   Split:
   β”œβ”€β”€ User can create contact
   β”œβ”€β”€ User can view contact
   β”œβ”€β”€ User can edit contact
   └── User can delete contact

5. BY PLATFORM
   Original: "User can view dashboard"
   Split:
   β”œβ”€β”€ User can view dashboard (web)
   β”œβ”€β”€ User can view dashboard (mobile)
   └── User can view dashboard (tablet)

6. BY COMPLEXITY
   Original: "User can search products"
   Split:
   β”œβ”€β”€ User can search by name (simple)
   β”œβ”€β”€ User can filter by category
   └── User can use advanced filters

BAD SPLITS:
─────────────────────────────────────
βœ— Frontend / Backend (not independent)
βœ— Design / Development (not independent)
βœ— Happy path / Error handling (both needed)
βœ— Implementation phases (not valuable alone)

Common Mistakes

What to Avoid

USER STORY MISTAKES
═══════════════════

TOO VAGUE:
─────────────────────────────────────
βœ— "As a user, I want the system to be fast"
βœ“ "As a user, I want search results in < 1 second"

TOO TECHNICAL:
─────────────────────────────────────
βœ— "As a developer, I want to refactor the auth module"
βœ“ "As a user, I want login to work reliably"
   (refactoring is HOW, not WHAT)

NO BENEFIT:
─────────────────────────────────────
βœ— "As a user, I want a blue button"
   Why? What value does blue provide?
βœ“ "As a user, I want clear call-to-action 
   so I know what to do next"

SOLUTION IN STORY:
─────────────────────────────────────
βœ— "As a user, I want a dropdown menu with..."
   That's a solution. What's the need?
βœ“ "As a user, I want to select my country
   so I see relevant content"
   (dropdown might not be the best solution)

TOO BIG:
─────────────────────────────────────
βœ— "As a user, I want to complete the checkout process"
   This is an epic, not a story. Split it.

NO ACCEPTANCE CRITERIA:
─────────────────────────────────────
βœ— Story with no criteria = no definition of done
   Team guesses what's expected
   Arguments at demo

FAKE USER:
─────────────────────────────────────
βœ— "As a system, I want to send emails"
   Systems don't "want" things
βœ“ "As a customer, I want email confirmation
   so I know my order was received"

GitScrum Stories

Story Management

GITSCRUM STORY FEATURES
═══════════════════════

CREATING STORIES:
─────────────────────────────────────
Task β†’ Type: User Story

Fields:
β”œβ”€β”€ Title: "As a... I want... so that..."
β”œβ”€β”€ Description: Full story text
β”œβ”€β”€ Acceptance Criteria: Checklist format
β”œβ”€β”€ Story Points: Estimate
β”œβ”€β”€ Labels: Feature area
└── Sprint: When planned

ACCEPTANCE CRITERIA AS CHECKLIST:
─────────────────────────────────────
In description or custom field:

☐ Given logged in, when click wishlist, then see items
☐ Given item unavailable, when view wishlist, then see status
☐ Given 30 days passed, when return, then items still there

Check off as you complete.
All checked = story done.

STORY HIERARCHY:
─────────────────────────────────────
Epic: User Authentication
β”œβ”€β”€ Story: Login with email/password
β”œβ”€β”€ Story: Login with Google
β”œβ”€β”€ Story: Password reset
β”œβ”€β”€ Story: Remember me
└── Story: Logout

Each story independent and valuable.

REFINEMENT WORKFLOW:
─────────────────────────────────────
Status: Draft β†’ Refined β†’ Ready β†’ Sprint

Draft: Initial capture
Refined: Discussed, criteria added
Ready: Estimated, team understands
Sprint: Committed to sprint

Best Practices

For User Stories

  • User language β€” Not technical jargon
  • One thing β€” Single piece of value
  • Conversation β€” Story invites discussion
  • Acceptance criteria β€” Clear done definition
  • INVEST β€” Check all criteria
  • Anti-Patterns

    STORY MISTAKES:
    βœ— Requirements documents disguised as stories
    βœ— Technical tasks as user stories
    βœ— No acceptance criteria
    βœ— Epic-sized stories
    βœ— Solution before problem
    βœ— No user benefit stated
    βœ— Written in isolation (no team input)
    βœ— Never refined before sprint
    

    Related Solutions