PREPARE THE TICKET

How to write a good development ticket: four examples

A good ticket is not necessarily long. It closes the decisions that would otherwise force a developer to guess.

5 min read

Start with the decision the ticket supports

State who needs the change, what problem it solves and what should be different afterward. Then define the scope: the screen, service or flow affected, and what is outside this task. “Improve exports” says little. “Let account managers download filtered customers from the Customers screen” gives a starting point.

Add the expected behaviour, permissions, failure cases and a way to verify the outcome. Attach a design when the interaction matters. Link an API contract or data definition when the task depends on it. Name dependencies and who owns them. Unknowns belong in a question list, not hidden inside a confident-sounding criterion.

Feature: export customers

Before

Title: Export customers

Description: Add an export button to the customer list. It should be easy to use and work for all customers.

The developer still has to guess who can export, what “all” means, which format to produce, whether filters apply, what happens with no results and whether the customer API supports this. Any estimate would contain those guesses.

After

Title: Export filtered customers as CSV

Context and goal: Account managers currently copy customer contact data manually. They need one file for a reviewed outreach list.

Scope: Customers screen, customer list and CSV export action. Out of scope: scheduled exports and email delivery.

User and permissions: The product owner must confirm which existing permission allows this export before development starts.

Expected behaviour: The export uses active filters and includes records beyond the current page. The product owner must confirm the column list, order and permitted personal data.

Edge cases and errors: Agree whether an empty result downloads a header-only file or displays a message. Show a useful error if the export request fails. Do not expose customer data to an unauthorized user.

Dependencies: Customer API support and an agreed CSV contract. Link the API specification and a design for the button and loading state.

Acceptance criteria after those decisions: An authorized user downloads the confirmed columns for all matching customers; an unauthorized user cannot export; failure and empty-result behaviour match the agreed rules.

Refinement questions: Who confirms the columns? What is the maximum supported export size? Is export synchronous or a background job? Which test dataset covers filtered and empty results?

This is a refinement draft. The named owner still needs to confirm the open decisions before work that depends on them begins.

Bug: the form sometimes fails to save

Before

“The form sometimes fails to save.” There is no reproduction path, actual versus expected result or environment. A developer can begin investigating logs, but cannot verify a fix.

After

“On the customer edit form in the staging environment, pressing Save after changing the billing address intermittently returns a 409 response. Expected: the new address persists and a confirmation appears. Actual: the old address remains and no message appears. Reproduction: open an existing customer, change the billing address and save twice within five seconds. Three of five attempts failed on the supplied test account. Attach the request ID and browser version. Check whether the issue also occurs in production before scheduling a release.”

The ticket now supports diagnosis. It does not pretend that the cause is known.

Technical task: upgrade Laravel

Before

“Upgrade Laravel.” The starting and target versions, affected dependencies and compatibility constraints are missing.

After

“Upgrade the application from Laravel 10 to the agreed Laravel 11 release. Confirm the supported PHP version and package compatibility before changing dependencies. Preserve public API behaviour, update the lockfile and run the unit and integration suites. Verify invoice creation and login in staging. List packages requiring separate work before changing them.” This is a technical task; forcing it into a user story would not make it clearer.

UI change: make a form easier to use

Before

“Make this form more intuitive.” No one knows which friction to remove or how to observe improvement.

After

“On the mobile checkout form, users often miss the required postcode field because its error appears below the submit button. Move validation feedback next to the field using the existing form pattern. On an invalid postcode, focus the field and show the agreed message; on valid input, the purchase flow continues. Confirm the message and design reference before implementation.”

The after versions stay short because each adds the few decisions that make the next step safe. Use the task readiness checklist to spot remaining gaps and the acceptance criteria guide when defining how to accept the result.

Once the ticket is clear enough, estimate the work and plan delivery separately. Before that, the task readiness tool can reveal missing decisions and draft criteria for refinement. Its verdict supports the discussion; it does not replace it.

← Back to resources