Stop Starting Vague Tickets
Reader takeaway: how to turn a fuzzy “add city” ask into a safe first release you can extend.
Ticket from the board:
“Add City to filters, add dropdown for Countries and Cities in add/update candidate fields with Geolocation API so that by results of filtering we can see profiles from that city. On Career they use Geolocation API.”
At first glance, this is “add two dropdowns.” I paused. That sentence hides decisions about users, data, rules, and risk. Skip that work, ship something that looks done, then spend a sprint fixing it.
The real problem
This is not a UI task. It is a product decision with a UI surface. City filtering touches who uses it, what they trust, and how data is shaped across the system. When engineers treat it as “add two fields,” the team pays later in rework and data cleanup.
What was actually missing
User and outcome. Who needs city filtering and why? Recruiters narrowing outreach lists is very different from finance reporting.
One surface first. Search results, reports, or the candidate form. Pick one so the slice is testable.
Source of truth. Country and city need normalized values from one canonical list. Mixing the career site provider with a new one will skew the counts.
Rules. Country drives City. Single select or multi select. What happens when a record has no normalized city?
Constraints. Privacy and permissions. Latency on large datasets. Language coverage and accessibility.
Migration. Free text values will not map cleanly. Decide what to backfill now and what to defer.
None of this is red tape. It protects value and reduces churn.
The smallest useful slice
We framed a slice that delivers value fast and sets a foundation.
User and outcome. A recruiter can filter candidates by Country, then City, on the Candidate Search page. They trust the result and can act on it.
Scope. Search page only. Country required, single City select. No profile edits yet. No reports yet.
Data. Store normalized country code and city ID fields from a single canonical list. No free text.
Rules. The City list is derived from the selected Country. Records without a normalized city do not appear in City results. The UI shows that some records are missing city data, so no one assumes bad matches.
Constraints. Filter interactions feel snappy. Keyboard and screen reader support is correct. City names appear in one language for now.
Migration. Backfill recent records in a small, safe batch. Older data waits for a later step.
Verification. A recruiter validates common searches and gets correct counts. Product and design review behavior. Data review confirms normalization.
Boring is good here. Boring means predictable, safe, and easy to extend.
Decisions that saved us later
One canonical list for countries and cities, shared across the product.
Country drives City. No free text. Clear behavior for missing data.
A visible indicator for “records missing city,” so results are honest.
Accessibility and keyboard use treated as part of the slice, not an afterthought.
A simple performance budget for filter interactions. If it drifts, we notice early.
What we delayed on purpose
Exports, multi‑city selection, scheduled reports, and editing city values in the profile. Each builds on the same normalized data and rules. Ship the slice first. Let real usage guide the rest.
What to watch once it ships
Filter latency in production.
Share of records without a normalized city.
Top searched cities that produce no matches.
These tell you whether to improve data, add language coverage, or adjust the slice.
Try this on your next ambiguous ticket
Before you touch code, write three short answers in the ticket:
Who is the user, and what outcome do they need?
What single surface and smallest slice delivers that outcome now?
What rules and data make the result trustworthy?
Paste it. Then build.
Simple rules I follow
Treat “use X API” as a hint, not a decision.
One surface, one slice, one owner.
Normalize data before screens. UI is the last step, not the first.
Why this matters
This is what product ownership looks like in practice. You turn a fuzzy request into clear choices, trade‑offs, and a minor release that is safe to extend. You boost team productivity. You prevent future work from breaking when data and rules are inconsistent.

