Tickets are the most common unit of work I use as a software engineer, they often come from a product manager, program manager or even other engineers. In my time being a contractor, engineering manager and full time team member I have seen several styles for writing tickets not all of them good. This post is my attempt to write what I believe to be good practice when writing tickets and the minimum fields required in the hopes that your journey in software engineering is efficient, tickets are not wasted and your work remains high quality.
Start with the minimum
The fields needed for ticketing is often less than consultants would have you believe. The best form of ticket creation is the one used by the team, adding many fields and locked workflows can serve to prevent ticket creation and thus lose work that is needed for your application. Simply having title, description, status and due dates is enough to get the message across on where and when work should be completed. Anything additional is up to the individual organization. It is important to trust the entire team, if a person is making poorly formed tickets it is better to train that individual rather than slow everyone else down with more process.
Define clear acceptance criteria
The skill of the engineer will often be your determining factor when it comes to how much detail should be added to a ticket. Don’t be fooled though, just because someone is more experienced does not mean they can intuit context that does not exist. A ticket’s description or goal should be defined by acceptance criteria. This criteria is best when it is concise, perhaps bullet pointed and, has a clear result. Acceptance Criteria such as “User can book a room” for a hotel app is too vague and should be broken down further. When criteria is that broad there is too much room for interpretation, a user could book a room via SSH but I doubt that is what the ticket creator is expecting, thus it is important the acceptance criteria is a blend from engineering, product and design.
Designs and documentation
When providing designs in tickets it is best to include an image of the completed ticket so engineers looking at the ticket for the first time can make a rapid assessment of the work involved. This image should be used for information only and not the design reference itself which should live in whatever design tool the team uses e.g. Figma. By giving the latest design links to the engineers the team can avoid rework if designs change during the development phase. If a design changes after work has begun it is critical that the team is informed directly in-person as well as the ticket being updated and in some cases a new ticket being made that supercedes the original. Rebuilding something after a large design change is the source of many project overruns, and it is not enough to expect engineers to check Figma and understand what has changed without being informed especially if they have already completed that work and may not be checking it again.
In the same way as design, engineering documentation must live both in and out of the ticket. Many teams use wikis like Notion and Confluence to store their longer term documentation. This is a good choice since these wiki platforms often have better search than ticketing platforms and can be linked to other documentation that may not live in the same place as tickets e.g. strategy documents and product roadmaps. It is dangerous to include much of a document without including all of it since an engineer will read the ticket, assume they have the information and move on even if that ticketed documentation is now out of date and the main document has been updated.
Assigning tickets
Assigning tickets should be easy. A ticket should be assigned to the least skilled engineer that can complete the task. If you are assigning a simple ticket to change the color of a button to your most senior engineer you either do not have difficult enough work or you are procrastinating on more difficult tasks. Over time your engineers should become more skilled and able to handle more difficult work, this is a two part challenge, you must first assign them work just out of their skillset’s range so they can face and overcome difficulty, secondly you should give them a healthy amount of work within their skillset so that they can master their current level. It is only by frequently solving problems are we able to solve them faster. Assigning tickets can be done by anyone, it should not be controversial that an engineer assigns a ticket to someone or that a product manager assigns it back. Who ever is currently assigned to the ticket is the owner of that ticket, in this way, ownership changes frequently as work travels through the pipeline. Anything assigned to an engineer should be in a work-ready state with no blockers prior to starting, if a ticket is not in a work-ready state it must be assigned to the person that can unblock it. An unassigned ticket shows that work is not ready yet, on some projects this might be because engineers are swarming the work and whoever picks it first will work on it in other cases it might be far down the road and irrelevant to current planning - for example a vendor integration happening next year.
Commenting on tickets
Comments on tickets are a must and should be used for frequent discussion. You should sort comments with oldest at the top, newest at the bottom to create an easily readable stream to understand the ticket. If a ticket’s conversation runs too long and involves too many topics then separate sub-tickets should be made to manage discussion, this is not dissimilar to splitting out files in code to reduce complexity. When replying to a person and expecting a response from them a ticket should be assigned back to that person so they know they are now the owner of that ticket and expected to reply. Using ownership in this way means someone can easily open their project management tool (Jira, Linear, Shortcut etc) and see what is expected of them in terms of replies and actual output.
Connect tickets to pull requests
Links to pull requests should be added automatically by your team’s integration. Jira and Linear both have first-party integrations with most source control websites to automatically connect pull requests to tickets. A software engineering team that has this automatic connection will be much faster at assessing bugs, resolving production outages and reviewing past work even if it is years old. A team that does not connect their tickets and code will be lost once a team member leaves, taking the knowledge of their work with them. Tying your tools together supercharges basic commands like git blame to show exactly why work was completed in a certain way.
Testing
Testing tickets is fundamental to the existence of a ticket and if there is no way to test then the ticket should be rejected by the one working on it and corrected before work starts. Testing instructions should be as explicit as they need to be, in cases where design is being reviewed simply saying so is enough since the design mocks can be used as acceptance criteria. For more behavioral work where a the technical output matters then including dot points of steps to test is useful. A tester should have all expected links, accounts, access levels or whatever else is needed to test without going back to the engineer. Testing instructions should include information on what is out of scope for a ticket, the navigation may be broken on a page but that is irrelevant to the testing of the body text component for example. Testers must be smart enough to limit their feedback to the ticket itself, other tickets can always be made and assigned to resolve bugs later. Testing instructions should allow for some freedom from the tester, if instructions are too specific then an engineer may only write code that resolve the specific use case and not other unwritten user behavior like error states and validation. A tester must have the ability to use the application as a user would. If a feature is targeting engineers that will need a different kind of tester compared to a public web application. Failures in testing should be added to the ticket as a comment with clear checkboxes, error messages and screenshots. It is an engineer’s responsibility to understand the feedback, assess its requirements and if necessary, fix the problem. Some testers will not have the ability to verbalize their problems, this is where product and engineering must use their brains and discover what the actual problem is. Clear checklists help avoid bugs being missed in paragraphs and reduce risk of misinterpretation. Most operating systems have a way to markup screenshots to highlight areas with problems. It is not a failure if a ticket does not fit what the writer had in mind, it is the responsibility of design, product and the business to make sure work being provided to engineers is ready to be worked on. If after seeing a feature live the business decides they want something else a new ticket should be made with the criteria and the previous ticket should be marked off as complete. Avoid redesigning an entire feature within an existing ticket since it can become very confusing and difficult for anyone to read especially those outside your project.
Tickets should have several states they can exist in but they must only exist in a single state at a time. Some examples are: Todo, In Progress, Review, Deployed. The number of states and their names is dependent on each organization, ones with large disconnected teams may have more, tight agile teams may have less. What is important is that the states are meaningful within an organization and everyone on the team knows what each step entails. It is often the case that specific team members are more responsible than others when a ticket is in a given state. Engineers may have more work in-progress while product have more tickets assigned in review, this is normal and to be expected as each role conducts specific work related to the project.
Completing work
Once a ticket has been completed and is marked ready to deploy it is common for teams to add release numbers to track which tickets were deployed at a time, it is also common for tickets to be deployed after merging to main with no release numbers or versions. Really this is up to the specific organization and what kind of deployments they use. For companies that do not deploy frequently or require a slower candence using release numbers can be an easy way to talk about an application internally. On larger teams with frequent deployments it is more common to use specific commit numbers when discussing released work. A ticket being marked ready for production or ready for deployment should be deployed at the earliest possible time. It is better to release smaller packages to prevent difficulty in debugging applications that have errors in production and it will reduce the amount of testing required for several new components being deployed at the same time. By having smaller, more frequent deployments a team is expected to test their work against the latest production release.
Tickets may come back for further testing and patching after a release goes wrong, it is better that a new ticket is created to fix the bug with the workflow continuing forward instead of going back to the past and previously completed work. A bug that was not found prior to release is a new bug and thus requires a new ticket. These bugs should be worked on immediately and have priority over other work. Post-mortems and other engineering practices should follow their unsuccessful release. Once a ticket is closed it must remain closed, the closed state means it has been deployed and marked as a successful release. Any new work in the same area must be a new ticket even if it is directly related to the previously released feature.
Wrapping up
Writing and managing tickets can be as difficult as you make it. It is not hard to keep tickets simple with screenshots, dot point descriptions, testing criteria and simple feedback managed through comments. Much like our code, tickets should be small, single-responsibility and easy to test individually. Mega tickets that have several complex pieces of functionality are doomed to fail as engineers lose track of what they are building and how it should be managed. Large tickets make deployments riskier with more complex pieces touching several parts of a system more prone to breakage than simple issues.
Keep your work small, testable and clear. The rest is easy.
