I keep having the same argument.
Someone writes a ticket. "Add a dropdown for country selection on the signup form." Fine. An engineer builds it. Ships it. The stakeholder looks at it and goes "No, that’s not what I meant." Now everyone’s annoyed and a meeting gets scheduled.
Forty-five minutes into that meeting, it comes out that the real problem was international users bailing on signup because the phone number field was confusing. Nobody needed a dropdown. The dropdown was just… the first idea that occurred to someone while they were thinking about the signup page.
That ticket wasn’t wrong. It was an answer to a question nobody bothered to write down.
A ticket should transfer understanding, not just instructions.
I see this constantly. Somebody already has a fix in their head, so they write the fix as the ticket instead of writing the problem. It feels efficient. Feels like you’re helping your engineers by being specific. You’re actually doing the opposite. You’ve locked the team into one approach before they understand the actual need.
Why do people do this? Because writing the solution feels faster. It feels decisive. It feels concrete. It feels like momentum. But it’s usually fake speed. You save ten minutes writing the ticket and then lose hours to rework, back-and-forth, and preventable meetings.
The problem is not naming a solution. The problem is naming a solution instead of naming the problem.
User Stories (The One Everyone Knows and Nobody Does Right)
As a [user persona], I want [goal/desire], so that [benefit/value].
The part people skip is the "so that." That’s the entire point. If you can’t finish that sentence, you haven’t figured out the problem yet. Full stop.
Quick test: does your "I want" clause have implementation details in it? "I want a dropdown menu." "I want a modal dialog." "I want an API endpoint." If yes, you’ve already decided the solution. Back up. Rewrite it as what the user actually needs: "I want to quickly indicate my country during signup."
Also, I need to rant about this for a second: "As a system, I want to…" No. Systems aren’t users. Who is the person on the other end? What do they care about? Write it for them.
Good for features and enhancements. Anything where a real person interacts with the thing.
Jobs to Be Done (JTBD)
When [situation/context], I want to [motivation/job], so I can [expected outcome].
Looks like a user story. Different animal. User stories describe how someone uses your product. JTBD describes what they’re trying to accomplish in their life, with or without your product. The key rule is that a good JTBD statement never mentions a specific solution. It has to work even if your product didn’t exist.
Instead of "Let me add tags, labels, and folders to my email program so I can sort things my way," the JTBD is just: "Find emails and files quickly." One of those sentences has already decided the answer. The other one left room for somebody to invent Gmail search.
From my own work:
- Nope: "Add a WARC data integration panel to the dashboard."
- Better: "When a brand strategist is preparing a campaign brief, they want to access advertising effectiveness benchmarks so they can back up their creative recommendations with evidence."
"How Might We" (HMW)
How might we [achieve some outcome] for [user] in [context]?
Comes from Procter & Gamble in the 1970s, got picked up by IDEO, then spread everywhere. Every word matters:
"How" = we don’t know the answer. "Might" = whatever we come up with is one option, not THE option. "We" = it’s everybody’s problem, not one person handing down instructions.
You have to get the scope right. "How might we redesign travel?" Too big, useless. "How might we build a recycled airplane seatbelt?" Too small, you already picked your answer. You want the version that names the user, the problem, and the situation but stops before naming any solution.
I use this all the time for spike tickets. Instead of "Investigate WebSocket options" (which has already decided WebSockets are the answer), try: "How might we give survey respondents real-time feedback that their submission was received?" Now the engineer can come back and say "Server-Sent Events would be way simpler here" without feeling like they’re going off-script.
Bug Reports
What happened → What should have happened → Steps to reproduce → Who cares and how much
Everybody wants to diagnose. "The database is probably timing out." "I think the cache is stale." Stop. You’re a witness, not a detective. Tell the court what you saw. The forensics team (your engineers) will figure out why.
The template I use:
- Environment: What device, browser, OS, which environment, what account
- Precondition: What was the state of things before it broke
- Steps: Numbered. Specific. Not "click around in settings"
- What happened: Just the facts
- What should have happened: The expected behavior
- Who’s affected and how badly: This is the one people forget and it’s the one that matters most for prioritization
Applies to literally every bug you will ever file.
Tasks and Tech Chores
What → Why → Acceptance criteria → Boundaries
Refactoring, infrastructure, migrations, dependency bumps. The unglamorous stuff that keeps the lights on. These tickets need the "why" more than any other type because there’s no user to point to.
The question I make people answer before I’ll accept one of these tickets:
"If we don’t do this, what gets worse? For who? How fast?"
This filters out "nice to have" busywork AND gives real infrastructure work the business case it needs.
- Nope: "Migrate to new auth provider."
- Better: "Our auth token refresh logic causes ~3% of API calls to fail without any error message when traffic spikes. This hits our data provider integrations hardest. A failed call there means a hole in the client report. Fixing the token management (approach TBD) should get rid of these silent failures."
Given / When / Then
Given [precondition], When [action], Then [observable outcome].
Not a ticket type. A format for acceptance criteria on any ticket. Comes from BDD and the whole trick is that it forces testable, observable language. You can’t write "Then the system is faster." You have to write "Then results load in under 200ms."
"Users can pay with Google Pay or Apple Pay at checkout" = acceptance criterion. "Write HTML that makes it possible to pay with Apple Pay" = implementation instruction. One of those belongs in your ticket. The other doesn’t.
The "5 Whys"
Not a template. A thinking exercise you do before you write the ticket. Ask "why" five times until you hit the root cause instead of a symptom. It’s from Toyota’s production system and I’m continually surprised by how few people actually do it.
"The site is slow." Why? The survey results page takes forever. Why? We load all responses at once. Why? Nobody added pagination. Why? The original feature assumed small datasets. Why? We never spec’d for enterprise accounts.
Now you can write a ticket for the actual problem instead of "make the site faster."
A Note on Solutions in Tickets
None of this means you can never include a proposed solution. Sometimes the constraint is real. Design has already locked in an interaction. Legal requires a specific workflow. Architecture rules out half the options before you start.
That’s fine. The important thing is knowing the difference between a real constraint and a premature decision.
- Constraint: "Must support SSO through our approved identity provider."
- Premature decision: "Build a new login modal with provider-specific tabs."
One gives direction. The other jumps straight to wiring diagrams.
If you include a proposed approach, label it as a proposal. Make it clear the team can push back. The ticket should still stand on its own even if someone throws out your suggestion and starts over from the problem statement.
Cheat Sheet
| Ticket Type | Question to Answer | Framework |
|---|---|---|
| Story | What does the user need and why? | User Story / JTBD |
| Bug | What broke, how do I prove it, who’s hurting? | Prosecutorial brief |
| Task / Chore | What needs doing, what gets worse if we skip it? | Context + Constraint |
| Enhancement | What falls short, what does better look like? | User Story + Given/When/Then |
| Spike | What don’t we know, what decision does the answer unlock? | How Might We |
One Last Thing
Before you submit any ticket, read it like a stranger. No Slack threads. No hallway conversations. No "you know what I mean."
Could someone reading only this ticket understand the problem well enough to propose a solution you hadn’t thought of?
If not, the ticket isn’t done.
A good engineer should be able to read your ticket and suggest a better approach than the one you had in mind. That’s not a failure of the ticket. That’s the whole point.
When a ticket leaves no room for that to happen, you don’t just constrain the implementation. You constrain the thinking. And that’s how teams end up shipping exactly what was asked for and still missing what was needed.
Jason Roell is Head of Engineering at Vurvey, where he spends a lot of his time asking people to rewrite their JIRA tickets. He writes at jasonroell.com.