A ticket, or story, is a single piece of developer work, and the code from multiple tickets comes together to form bigger projects. I've dealt with a lot of poorly written tickets in my career, and at some point, I documented a process for writing good tickets for my team. I decided to blog it.

Types of Tickets

There are different types of tickets my team will usually take on:
  • Research SpikesSpikes are a research ticket. We use them to evaluate a new project and propose a solution. I have another blog post about the process I use for planning initiatives that may be worth a read.
  • Story Tickets: A story is a single piece of development work. Ideally they are small and self-contained. I want them to be small because code reviews are easier when there is less code changed. Quicker code reviews mean tickets are closed out more effectively, and our system is always evolving. I like tickets to be self-contained so that each ticket is deployable as a stand-alone until even when the stories are part of a bigger initiative. Sometimes feature flags help with that, but that is beyond the scope of this article.
  • Bugs: A bug ticket represents some problem with our code that we want to fix.
  • Tasks: A task is some action the team needs to, or wants to, take on, but does not require code changes. This may be to document a new process in our wiki, or to change some data, or run a report, or change our Github settings. I like to track this work, or else it will never rise to the priority list.

These are the four types of tickets that my current team deals with, and we've developed a very particular way of formatting the tickets.

Anatomy of a Ticket

When thinking about how to write them, I join Story Tickets, spikes, and Tasks as using the same format. Bugs are a bit different, and I'll delve into that next.

Before jumping in, I want to highlight that these tickets should be self-contained and should be deployable and reviewable without parallel dependencies. When dependencies do exist, tickets should be implemented in dependency order, so all dependencies are cleared before we start the reliant ticket. For major initiatives, we use feature flags to hide functionality and code, so we can keep our continuous deploy process.

I like to split up my ticket into four parts. A summary, a description, any tech details--if applicable, and the acceptance criteria. Let's explore each piece of a good ticket.

Summary

The summary is the elevator pitch for this ticket. What do we want to do and why do we want to do it? Who do we want to use it for? I like to write these as:

As a User, I want to Action, because of Reason.

There are three main aspects of this:

  • User: This is the type of person we are doing the fix for. I absolutely hate it when I see 'user' used in a ticket summary, because it is not descriptive enough. Is the user a developer? Or a product owner? Or a designer? Additionally, I work on an app with different aspects of permissions. Are we helping an admin users? Or a read only users? Or someone who can access the dashboard? Or someone who can edit data? Or someone who needs to approve data changes before they propagate to a live system? The context of knowing who this is for helps the developer plan out an appropriate fix.
  • Action: This defines a quick summary of what we want to do. It represents the new piece of code that this ticket will encompass.
  • Reason: This defines the business case for building this ticket. This is the piece I most often seen left out of the ticket, but I like it when it is there because I find it important.

Here are some examples:

  • As a Team Developer, I want to integrate SonarQube with Github so I can get notified of code smells when I open a new PR.
  • As a Content Editor, I want to bulk delete entries from the content list screen so I save a lot of clicks.
  • As a Content Viewer, I want to go to the content list screen as soon as I login, so I don't have to search around for the proper button.
  • As a Team Designer, I want to implement the company's standard styles, so that this application's look and feel is consistent with other internal applications.
  • As a Product Owner, I want to link to the request access from the "no access" page, so people will stop reaching out to me personally to give them access.

Every one of these tells the person requesting this change--or who the change is for; what the actions are, and why there is a benefit to doing this task. These details can help the team leaders evaluate priority of the requests.

Description

The description of a ticket is more free form than the summary. It allows the ticket writer to expand on anything they want. I expect it to include things like the screen that is being modified, or details on the data we want to collect, or define a new process we want to implement. Sometimes this section will link to a more detailed product brief, Request for Comments Document, or even a slack thread as part of context for the ask.

Tech Details

The tech details of a ticket are the place for the ticket writer to dictate an architecture. Programmers, or leads, are the ones who are most likely to write this section. It may include things like class names, REST endpoints, database changes, or other code details.

This section is important for larger initiatives where a lead developer is writing dozens of tickets, with a planned architecture. They want to make sure that the implementation stays true to the planned architecture, because one ticket off in the dependency chain will complicate future tickets.

There is a balance here that is hard to maintain between developer autonomy, and how this code fits into the larger architecture of the application. I want developers to be able to take a ticket and have leeway to make their own decisions. I also want the tickets to properly slot into the larger project that the ticket is most likely a part of. Finding the balance between those two can be hard.

For better or worse, this section is most likely to be combined with description or left out entirely. I'm fine with that for on off tickets, but it frustrates me for tickets that should be thought out.

Acceptance Criteria

Finally, a ticket has acceptance criteria. This is usually a bulleted list of items that can be used to prove the ticket implementation was successful. It helps the developer determine they have met all the requirements when building the ticket. It helps QA, or other stakeholders, test the ticket's successful completion.

Final thoughts on Story Tickets

There are three types of tickets: Stories, Spikes, and Tasks which I prescribe to follow the same format. They start with a summary is a quick pitch of who we're doing the fix for, and why they would care. It includes a description, which includes more details of the ask. A tech details section will describe the technical changes, and how they fit into the larger architecture of the overall application or project. And finally, it includes a list of acceptance criteria (or AC), which tells us how to evaluate the correctness of the ticket.

Bug Tickets

I like to use a different template for bug tickets. What is important for fixing a bug ticket is capturing what the bug is, why it was wrong, and how to reproduce it. It is less about dictating an architecture of a long-term project, and more about fixing a problem of the moment.

I like five sections of a bug ticket: A Summary, steps to reproduce, what happened, what should have happened, and any additional info. Let's look at each one.

Summary

The summary of a bug ticket is just a text description of what is wrong. I hope this will capture the action and the incorrect outcome:

Performing action resulted in Error State.

Bugs are universal to everyone that is an app stakeholder, so I don't see a benefit to focusing on the affected user for a bug ticket. Although, the permission of the affected user may be a beneficial piece of information to debug the ticket.

Here are a few samples of bug ticket summaries:

  • Saving the document returned an error.
  • Opening the saved document did not show the updates from yesterday.
  • After inputting the date properties, the publish button was disabled.
  • Clicking the "additional info" button on the Detail Screen of application did not automatically log me in the "additional info" application.
  • Entering the app with a deep link into 'screen 1' loaded data for 'screen 2'.
  • The published JSON did not include the legalInfo property, which is required in our shared schema.

These are all just short descriptions, highlighting the action taken, and the incorrect behavior.

Steps to Reproduce

The steps to reproduce should list detailed steps to reproduce the bug. Sometimes this can include links to a production site, and details about specific data sets. Depending upon whom is writing the bug, it may be hard to get specific details. I find programmer found bugs are very well documented here, and on the other end of the spectrum, bug reports from our (internal) users are usually even better. But, the folks that lie between the dev team and the consumers--such as product owners, designers, or project manager / scrum masters-- often lack the detail I wish we had.

What Happened?

After you took the steps to reproduce, what did happen? What were the results you saw? Was there a UI change, or was data published incorrectly? Did it affect our system, or some other system down the processing chain?

What Should have Happened?

After you took the steps to reproduce the bug, l what did you expect to have happened? Or to put it another way, why was the 'what did happen?" wrong? This is not always intuitive to share, and bug reports often tell you something is wrong without documenting the expected behavior.

Additional Info

Additional info is anything that didn't fit elsewhere. It might be a link to a slack thread about the bug, or screenshots from the app, or documented output from the app. It could be a link back to the original requirements expanding why our input was incorrect.

Final Thoughts on Bug Tickets

A bug ticket should cover everything a developer needs to know to reproduce the bug, including steps to reproduce, a description of what happened, and documentation as to why that was wrong. Formatting bug tickets like this really helps your devs get good footing for finding a fix.

Final Thoughts Overall

Putting up-front effort into curating good tickets is important to have an effective, and efficient, developer culture. This article should have helped give you a perspective on how I approach ticket writing. My teams have had a lot of success by mirroring this approach, and I think it can work for you too.