Breaking down dev work into detailed tickets, subtickets, stories, tasks, etc. takes effort. Is it really worth it? I believe there’s a common failure mode where dev teams break down their work too far, especially in Jira whose design implicitly encourages it. I want to argue for a different approach.
Let’s step back a second. Every tracking tool has a fundamental unit of work, usually called an “issue”, a “work item”, or (in Constructor) a “ticket”. But that leaves open a critical question. At what level should your team define each ticket? Is each ticket a discrete code change, expecting just one (or perhaps a small number) of pull requests by a single developer? Or is a ticket something higher level, like a unit of business value, possibly requiring many developers and pull requests to address?
Your team’s development process will have to answer this question. Many teams answer it implicitly, just following whatever approach their early engineers were accustomed to or that their tool seems to be designed for. But I believe it’s one of the more important decisions affecting the health of your team’s development process, and you should give it some thought.
Before I get into that, let me mention some related goals that most teams want in their development process:
We all know that small PRs are better than large ones. Small PRs are easier and faster to review, so they tend to get reviewed sooner. They also tend to get better quality code reviews, because the reviewer isn’t overwhelmed and tempted to skim like they would a giant PR diff. And if your team does continuous deployment to production, small PRs are safer to land and easier to roll back.
Having large numbers of tickets, each perhaps with lots of subtickets and PRs, makes it harder to find what you’re looking for, to collaborate in context, and to see the big picture.
A sense of progress
Imagine your team is working hard, but because of how your work is broken down or your board is structured, there’s no apparent visible progress. It’d be demotivating! And that demotivation can cause the team’s actual progress to slow! On the flip side, seeing and feeling continuous progress is a virtuous cycle.
Clarity on what’s been shipped
It can sometimes be challenging to know with certainty whether a feature or bugfix has actually been shipped to users, even for teams practicing continuous deployment. Did the production deploy fail? Did we enable the feature flag? Did the change get reverted? Did we ship only a subset of the planned functionality, with the rest coming soon? A team’s development process shouldn’t make answering these questions unnecessarily more difficult.
Simple and practical process
Developers and other team members shouldn’t have to struggle to understand or follow your team’s process and norms. Extra friction adds up.
What not to do: define tickets as discrete coding tasks
Many teams break down their work so that each ticket is a discrete coding task, like a ticket for adding a new parameter to an existing API endpoint in support of a new feature, or a ticket for each of several subcomponents needed to compose a new UI, or a ticket for each database migration or backfill script. A ticket usually requires just one pull request, or sometimes a few to keep each one small. Bugs are usually individual tickets that stand alone, while tickets for features are grouped together under an epic. If there’s a feature flag, enabling the flag is often its own separate ticket.
Before I talk about what I think is wrong with this approach, let me concede some advantages. It tends to promote smaller PRs, because tickets are defined at a level that can be addressed in one PR (or at most, a few). It can help with estimation, because you’ve broken down the work to a level where you probably have a decent grasp of the effort required. And it lets each ticket be owned by a single person. (Indeed, some teams end up in this pattern because their tracking tool only lets tickets have a single owner, so they have to break down the work at least that far.)
So, why do I think this approach is a bad idea? Several reasons:
- No matter what tool you’re using, breaking down work to this level takes thought and time. As I’ll argue below, I think that time is rarely well spent, especially for smaller, nimble teams.
- You’ll end up with lots of tickets and subtickets, vastly increasing the clutter of your tracking tool. Clutter imposes a constant tax that eats into your team’s productivity.
- Because tickets are defined at the level of code changes, not at a level meaningful to the business, the board is less useful to non-devs. Yes, they can look at a separate view of epics, but now all dev work has to roll up to an epic for it to be visible and understandable to the rest of your team.
- As a project progresses, things inevitably change: the goalpost moves, pieces are punted and others are added, decisions are reconsidered, and unexpected obstacles arise. It can be burdensome to keep all of the project’s tickets up-to-date with the latest thinking.
What’s the alternative?
What I recommend: define tickets as units of business value (most of the time)
Tickets usually represent a shippable unit of business value (or at least a major step toward business value) rather than a discrete code change. Their titles express the value in a way that’s recognizable to everyone on the team, including non-developers. Some tickets end up requiring only one PR (a small bugfix or refinement), but most require several. A ticket can still be broken down, but the breakdown usually uses something lightweight like a checklist. It’s OK for a ticket to involve more than one developer.
I prefer this approach for many reasons. The overhead is limited, since you’re not creating and managing lots of tickets and subtickets. Your board remains uncluttered and keeps everyone focused on delivering business value. It’s flexible: you can start a ticket with no breakdown and add substructure in the form of checklists, or even subtickets, only when you find it’s actually helpful. It lets you incorporate small technical investments or refactors into larger product work without having to necessarily split them out as separate tickets (which may not be recognized as valuable by non-devs).
The title above says “most of the time”, and that was intentional. Sometimes it’s warranted to have a lower-level ticket for a discrete coding task. That’s perfectly fine! The point is to be flexible, not dogmatic.
Here are a few details to be aware of:
- Very junior developers may find this model harder, preferring tickets defined as low-level discrete coding tasks, because they’re less ambiguous and have clearer scope.
- Developers may be tempted to open larger PRs than they should, PRs that deliver the whole value of the ticket rather than incremental steps toward it. Your team will need a separate norm that encourages small PRs.
- Sometimes a ticket will have more than one person involved. You’ll need a tool that supports it. Shameless plug: Constructor allows designating a single owner on a ticket for clear accountability, plus additional optional collaborators who are also involved in the work.
- Your tickets won’t move as rapidly across your board, because each represents a larger unit of value than a discrete coding task. Shameless plug: in Constructor, checklists are tied to the stages of your board, and progress is displayed on the card when it’s in that stage, so you’ll still get a sense of progress even if the ticket doesn’t move.
Don’t take my word for it. Think about how your team operates and find the process that works for you. Constructor is designed to be flexible and let your team evolve over time.