The single highest-leverage habit in this entire course is also the cheapest: writing down the real problem before writing any code.
1Who, What, How You'd Know
A real problem statement names three things: who experiences it, what specifically goes wrong for them, and a rough sense of how you'd know it's fixed. Missing any of the three usually means you're looking at a disguised solution instead of a problem.
2The Cost Compounds After You Build
Skipping problem framing doesn't just risk building the wrong thing — it also removes your ability to know afterward whether it worked, because there was never a stated 'how you'd know it's fixed' to check against.
3Step-by-Step Breakdown
A feature request ('add a dashboard') is not a problem. A problem is what's actually going wrong for someone ('users can't tell if their export succeeded, so they email support'). Engineers who jump straight to the feature skip the step where they'd notice a cheaper or better solution.
A useful discipline: before building anything, write the problem in one sentence that names who has it, what goes wrong, and how you'd know it's fixed. If you can't do that in one sentence, you don't understand the problem well enough to build a good solution yet.
Which of these is a well-framed problem statement, not a feature request in disguise?
- →"We need a Slack integration"
- →"Support engineers spend ~2 hours/day manually notifying users about failed exports because there's no automated alert, which delays fixes"
- →"Add more colors to the dashboard"
- →"Build an admin panel"
Skipping problem framing causes a specific failure mode: solution blindness. Once you've said 'let's build a dashboard' out loud, it's psychologically hard to consider that maybe a single automated email would fix 90% of the problem for 5% of the effort.
Why does naming the problem before proposing a solution reduce solution blindness?
- →It doesn't — the order doesn't matter
- →Because once a specific solution is proposed, people anchor on it and stop evaluating cheaper alternatives that solve the same underlying problem
- →Because problems are always solved with dashboards
- →Because it makes the ticket longer
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Frame Accessibility Problems the Same Way
'Add better accessibility' is as vague as 'add a dashboard.' Frame it concretely: 'Screen-reader users can't complete checkout because the payment step has no accessible label — 3 support tickets last month cite this,' which is buildable and measurable.
// Vague: "improve a11y"
// Framed: "screen-reader users abandon checkout at step 3 (data: N tickets)"SEO Implications
- 1
Target 'how to write a problem statement for engineers' distinct from generic PM problem-statement content
Engineer-focused readers want the habit applied to their own backlog decisions, not a PM-team workshop exercise.
Best Practices
Write the One Sentence Before Opening Your Editor
Make it a literal first step: type the who/what/how-you'd-know sentence at the top of the ticket or PR description before touching code. If you can't finish the sentence, that's a signal to go find out more before building.
Frequent Bugs
Writing a problem statement that's just the feature request with a 'because' clause tacked on (e.g. 'add a dashboard because users want visibility').
Check that the statement would survive removing your proposed solution entirely — 'users can't tell export status' survives; 'users need a dashboard because they want visibility' doesn't, since 'visibility' is just a restatement of the dashboard.
Real-World Examples
The Dashboard That Wasn't Needed
A team was asked to build an analytics dashboard for churned users. Framing the problem first revealed the real issue: sales just wanted a weekly digest of who churned and why. A scheduled email replaced a multi-week dashboard project.
// Requested: dashboard
// Real problem: "sales needs weekly churn summary"
// Shipped: scheduled_email(weekly, churn_summary)