← Back to Blog

How to Write Tickets and Document Your Work

TL;DR - A good bug ticket has three parts: steps to reproduce, expected behavior, and actual behavior. Include environment details. - Feature tickets need a problem statement and acceptance criteria. Scope limitations matter as much as the requirements. - PR descriptions explain what changed and why, not just what. The diff already shows what. - Code comments explain the reasoning behind non-obvious decisions, not the mechanics of the code itself. - The meta-skill: writing things down so the next person does not have to ask. - Junior engineers who document well get a reputation for professional maturity that accelerates their careers.


Writing good tickets and documentation is not glamorous. It does not show up in a portfolio. It will not win you a technical interview. But it is one of the clearest signals of professional maturity that senior engineers look for in junior teammates.

The engineer who writes a clear bug ticket saves a colleague thirty minutes of archaeology. The engineer who writes a thorough PR description speeds up code review and reduces back-and-forth. The engineer who leaves useful code comments means the next person does not have to schedule a meeting to ask what this function does.

These small acts of documentation compound over time. After six months, the engineer who documents their work consistently is noticeably easier to work with than one who does not. That reputation shapes who gets trusted with independent work, who gets asked to take on stretch assignments, and eventually who gets promoted. Read how to get a raise or promotion in your first engineering job for the full picture of what visibility and track records actually look like.


How to Write a Bug Ticket

The three required elements

Every bug ticket needs three things: steps to reproduce, expected behavior, and actual behavior.

Steps to reproduce is the most important part. If someone cannot reproduce your bug, they cannot fix it. Write the steps as a numbered list, specific enough that anyone on the team can follow them on their own and arrive at the same result.

Bad: "The form breaks when you submit it."

Good: 1. Log in as a user with a standard account (not admin). 2. Navigate to the profile settings page. 3. Change the email field to any new valid email address. 4. Click Save. 5. Observe: the page returns a 422 error and the change is not saved.

The second version is actionable. The first version requires a follow-up conversation before anyone can even start.

Expected behavior: what should have happened. In the example above, it should have saved the updated email and shown a success message.

Actual behavior: what actually happened. The error message and code, if available.

Environment details

Include the environment where you encountered the bug. Production, staging, local development. Browser and version if it is a front-end issue. Operating system if relevant. App version or recent deployment if known.

This matters because bugs are sometimes environment-specific. A bug that only appears in production with the latest migration and not in staging with the previous one is a different kind of problem than a bug that appears everywhere. Environment details help the person fixing it narrow the search immediately.

Severity and context

Not every bug is equally urgent. A ticket that crashes the app for all users is different from a ticket where a button in a rarely-used admin panel is misaligned.

Include a severity assessment. Does this block any users from completing critical actions? How frequently does it occur? Is there a workaround?

You do not need to solve the problem in the ticket. You need to give enough information that the engineer who picks it up can reproduce it, understand what is wrong, and have some sense of priority.


How to Write a Feature Ticket

Start with the problem, not the solution

A common mistake in feature tickets is jumping straight to the implementation. "Add a button on the profile page that allows users to export their data as CSV."

That is a solution. Before you write a feature ticket, you need to establish the problem.

"Users currently have no way to export their account data. This comes up frequently in support tickets from users who want to switch platforms or keep offline backups. We need a way for users to export their data in a format they can use."

The problem statement does not need to be long. Two to four sentences. But it needs to exist because it is the foundation for every decision that gets made during implementation. When questions arise mid-sprint about what to include and what to skip, the problem statement is what you return to.

Acceptance criteria

Acceptance criteria are the specific conditions that must be true for the feature to be considered done. They should be written so that anyone can verify them without judgment calls.

Format: write each criterion as a statement beginning with something testable. "The user can..." or "When the user does X, Y happens."

Example acceptance criteria for the export feature: - The user can trigger a data export from the account settings page. - The exported file includes all profile information, order history, and saved addresses. - The exported file is in CSV format. - The user receives a confirmation message after triggering the export. - The export completes within 30 seconds for accounts with fewer than 1,000 records.

Notice what is not in this list: anything about how the export is implemented. That is intentional. Acceptance criteria define what, not how.

Scope limitations

Good feature tickets also state what is explicitly out of scope. This prevents scope creep during implementation and gives the engineer permission to say "that was not in this ticket" when stakeholders start asking for additions mid-sprint.

"Out of scope for this ticket: real-time export status updates, support for JSON or XML formats, and bulk exports for admin accounts. These can be addressed in follow-on tickets."

Writing scope limitations requires predicting what people will want to add. After you have been on a team for a while, this becomes easier because you learn what tends to expand.


How to Document a Pull Request

What a PR description is for

The diff in a PR already shows what code changed. The PR description exists to explain the context that is not visible in the diff: why this change was made, what problem it solves, how to think about reviewing it, and what to look for when testing.

A PR description that says "Updated the user controller" tells the reviewer nothing they could not see from opening the files. A good PR description saves the reviewer time and makes thoughtful code review possible.

What to include

Start with the problem or requirement. One or two sentences explaining what prompted this change. Link to the ticket if one exists.

Describe what changed at a high level. Not a line-by-line walkthrough of the diff, but a summary that orients the reviewer. "This adds a new endpoint for user data export, introduces a background job to handle the file generation, and updates the profile settings view to include the export button."

Explain any non-obvious decisions. If you chose one approach over another, briefly say why. "I used a background job here rather than a synchronous response because export times can vary significantly and we did not want to tie up the web process." The reviewer now understands your reasoning without having to ask.

Include testing notes. What manual testing did you do? Are there specific scenarios the reviewer should verify?

Flag anything that needs attention. Known issues, temporary solutions, areas of uncertainty. "This approach handles accounts with fewer than 10,000 records. We will need a different approach for large accounts, which can be addressed in a follow-on PR."

What not to include

A PR description is not a place to prove how much work you did. You do not need to list every file you touched or every decision you considered. The reviewer will read the diff. Give them the context they need to do that intelligently, then trust them.

You also do not need to apologize or hedge excessively. "I am not sure if this is the best way to do this but..." signals uncertainty that may be appropriate to express in a comment requesting specific feedback, but not as a general disclaimer in the description.


Code Comments

The purpose of a code comment

Code comments are not for explaining what the code does. The code explains that. Comments are for explaining why the code does it, especially when the reasoning is not obvious.

A comment that says "# Increment the counter" above a line that increments a counter is useless. A comment that says "# We use a counter here instead of querying the database on each request because this endpoint is called frequently enough that the database query was causing latency spikes" is useful. The code does not explain the context. The comment does.

When to write a comment

Write a comment when:

You made a non-obvious implementation choice and the reasoning matters for future maintenance. Future engineers (including future you) will wonder why this was done this way. The comment answers that before they have to ask.

You are working around a bug or quirk in a library or framework. Note the bug, link to the issue if one exists, and explain what you are doing to work around it.

The behavior is intentional but looks like a mistake. "This function deliberately returns nil rather than raising an error. The caller handles the nil case and an exception here would be swallowed upstream."

You are leaving something incomplete for a known reason. "TODO: This approach does not handle accounts created before 2025 because those records are missing the required field. Will address in ticket #1234."

When not to write a comment

Do not write comments that describe what obviously readable code does. If your function is named calculate_tax_rate and it calculates the tax rate, it does not need a comment.

Do not leave stale comments that no longer reflect the code. A comment that was accurate six months ago but now describes behavior that has changed is worse than no comment. It misleads future readers. If you change code that has a comment, update or remove the comment.


The Meta-Skill: Writing for the Next Person

What ties all of this together

Whether you are writing a bug ticket, a feature ticket, a PR description, or a code comment, the underlying skill is the same: anticipate what the next person needs to know.

You know the context. You have been living in this problem for hours or days. The next person comes in cold. They need enough information to pick up where you left off without a meeting.

This skill takes deliberate practice because it requires temporarily setting aside your own knowledge and imagining what someone else would need. Engineers who develop this skill early become significantly easier to collaborate with. Over months, that ease compounds into trust, which compounds into opportunity.

It is also, practically speaking, a form of insurance. If you are sick for a week, or you leave the company, or you get pulled onto a different project, the work you documented clearly can be picked up by someone else. The work that exists only in your head cannot.

This connects directly to writing good enough code on a real team. Clean, readable code is part of writing for the next person. Documentation completes the picture.

How this builds your reputation

Junior engineers who document their work consistently develop a specific reputation on their team: they are trustworthy with independent work.

A senior engineer who knows that if they hand you a ticket it will come back with a clear PR description, good commit messages, and any follow-on issues already documented, will hand you more tickets. They will hand you bigger tickets. They will advocate for you in performance conversations.

The engineer who ships good code but leaves a trail of confusion about what they did and why requires ongoing hand-holding that limits how much independence they can be given.

Documentation is not separate from doing good engineering work. It is part of it. A clear PR with thorough notes is a better PR than an identical diff with no context. The git workflow on a real team covers commit conventions and PR process in the broader context of team version control.


Practical Starting Points

If you are not currently writing PR descriptions beyond a title, start there. Before you request review on your next PR, add three to five sentences covering the problem, the change, and any testing notes. Do this for the next five PRs. Notice whether review comments change.

If your sprint tickets tend to be vague, practice writing acceptance criteria for each one before you start. Write three to five specific conditions that must be true for the ticket to be done. This forces clarity before implementation rather than during.

For code comments, set a standard for yourself: any time you have to stop and think for more than thirty seconds about why code does something a certain way, add a comment explaining it.

These are small habits. They have outsized effects.


Read More

For a broader look at how professional habits compound in your first engineering role, the first 90 days as a software engineer covers the full picture.

For the git side of documenting your work, the git workflow on a real team covers commit messages, PR conventions, and branch strategy.

If you want structured support building the professional habits that accelerate an engineering career, here's how the Globally Scoped program works.

Interested in the program?