From Ticket to Production: How I Break Down a Feature
The hour before you write code decides most of what happens after. What I do in that hour.
The strongest predictor of whether a feature goes smoothly isn't difficulty. It's whether anyone spent an hour on it before opening the editor. Here's what that hour looks like for me.
Step 1: find the actual request
Tickets describe solutions. "Add a CSV export to the reports page." Before building that, I want to know what happens after the download.
Asked once, the answer was: "I open it in Excel and make a pivot table of hours by project, then email it to the client." They didn't want a CSV export. They wanted a monthly per-project summary they could send to a client. The CSV was their workaround for us not having that.
We shipped a summary view with a PDF export. Two days instead of one, and it eliminated a recurring manual process rather than automating one step of it.
The question is always some version of: what will you do with it once you have it?
Step 2: write the states before the happy path
Every screen has more states than the design shows, and the ones missing from the mockup are the ones that generate bugs:
- Empty — no data yet. What does it say? What's the next action?
- Loading — skeleton or spinner? Does it block the whole screen or one panel?
- Error — which errors are possible, and what can the user do about each?
- Partial — some data loaded, some failed. Extremely common, almost never designed.
- Too much — 10,000 rows. Does the page survive it?
- Permission — a viewer sees this. What's hidden versus disabled versus absent?
Writing these down takes ten minutes and surfaces the questions worth asking a designer *before* they're expensive. It also makes the estimate honest — most underestimates are the happy path estimated accurately and everything else forgotten.
Step 3: draw the data flow
On paper, badly. Where does the data come from, what shape is it in, where does it get transformed, what does the component finally receive.
This is where you catch the N+1 that would have been a production incident, and where you notice the API returns user IDs but the design shows names — which is a backend conversation you want to have on day one, not on day four when your PR is blocked.
Step 4: cut into shippable pieces
Each piece should be mergeable on its own without breaking anything. Not "part 1 of 3 that only works once part 3 lands."
1. API endpoint + types (merge, behind nothing)
2. Read-only view, no filters (merge behind a flag)
3. Filters + pagination (merge behind the flag)
4. Export action (merge behind the flag)
5. Turn the flag onFour small reviewable PRs instead of one 1,200-line PR that gets a rubber-stamp approval because nobody has two hours to read it properly.
Step 5: decide what "done" means, in writing
Before starting, not after. Otherwise "done" expands during the work and you can't tell whether you're finished.
Done when:
- Manager can filter by project and date range and see hours
- Empty, loading, and error states implemented
- Works at 360px
- Keyboard navigable, focus visible
- Loads under 2s with the largest client's data (~40k rows)
- Feature flag on for internal usersThat last-but-one line is the kind of thing that gets discovered in production if it isn't written here. Someone's real dataset is always ten times your test dataset.
The rest of it
Then you write the code, which is the part everyone thinks is the job. Two habits during:
- Demo the ugly version early. Day two, not day nine. Feedback on something real is worth ten times feedback on a description, and it's cheap to act on while nothing is finished.
- Log the surprises as you hit them. They're the content of your handover, your PR description, and the reason the estimate moved. Reconstructing them on Friday doesn't work.
None of this is a methodology and none of it needs buy-in. It's an hour of thinking, written down where someone else can read it, and it's the difference between a feature that lands and one that drifts.