Software Development Team Standards - Task Management and Sprints
Having worked on a number of different teams over the last 20 years, I’ve started to notice a number of trends among the higher functioning software development groups. I think at this point in our industry there’s a number of “best practices” that most software teams have adopted, and those who haven’t are often struggling with common issues that could be addressed by those same practices. Today’s article will focus on task management and sprints, two areas where there can be potentially a lot of divergence from established standards.
I write all this with a huge caveat - just because your team doesn’t score highly in one of these categories, doesn’t mean your team is bad! If anything it might give you some ideas and goals to strive for to address some of the pain points and issues you may be experiencing as a group.
This ended up being a huge post. I’m going to break it up into a few separate articles:
Task Management
Software development teams of all sizes use ticket-tracking software; Github Projects, Jira, Trello, Basecamp, and dozens of other software packages exist for all different sizes and types of projects. Outside of the standard “put your tasks in, move them along as they progress, and track their release” workflow there’s a number of best practices that can be followed while managing tasks.
A good first step is using ticket types, more specifically “epics”, “stories”, “tasks”, “bugs”, and “tech debt”. I’ve experienced teams using more than these specific task types, but almost all of them use these five at a minimum. While functionally they don’t differ much (although most teams use “templates” to ensure each type of ticket captures the information it needs), they provide an important window into where your teams are spending their time, which feeds into some of the other practices discussed below.
Another good practice is linking code (pull requests specifically, but individual commits as well as needed) to tickets. This allows users to associate work effort to stories and epics, enabling things like estimation accuracy measurements but also allowing for release management - you can quickly visualize what has changed, what has been tested based on the commits that are tied to the stories and epics that are being released.
Finally under task management I’d like to add the necessity of a “blocked” status. It’s important to have a specific holding area for tasks that can’t be moved forward due to external dependencies. This gives a clear visual indication of issues that need to be followed up on, as well as a concrete definition of why a sprint or team may not be progressing as originally planned. It’s important, when moving a task to “blocked”, to identify what is blocking the task so that anyone who’s looking can quickly see who needs to be followed up with. A categorization is also useful here, to be able to report on consistent blockers for the team so they can be mitigated in the future.
Acceptance Criteria
Most ticket types (other than perhaps subtasks) should have clear acceptance criteria. This is important for a number of reasons:
- Nothing gets lost between meetings. If you adopt a practice of keeping acceptance criteria up to date, you won’t leave weird edge cases or niche criteria on the floor between the discovery, refinement, estimation, implementation, and testing, reducing the odds of a missed requirement when it comes time to test or deploy the feature.
- Developers have a clear picture of what needs to be accomplished. People who write code aren’t subject matter experts in the business needs of the feature (nor should they be), so it’s important to spell out exactly what needs to be done (again, to avoid missed requirements)
- Estimates will be more accurate. It will be easier for implementation teams to identify dependencies and effort when it’s clear what has to be done.
- Automated testing will be more clear. Depending on your automated testing suite, you could very easily implement integration tests that are specifically called the exact same thing as the acceptance criteria, proving not only that it was implemented, but also that it continues to work as expected.
- There’s a clear definition of what a feature does (and by proxy, doesn’t) do. With a concrete list of goals for a story, it’s hard for anyone to come back later and say “oh it was supposed to behave this way”; the acceptance criteria serves as a sort of contract between the business, implementation, and testing teams of the company.
- Anyone should be able to pick up a task. There should be enough information captured on the ticket that any member of the development team could theoretically work on it. If a ticket requires specialized business knowledge in order to work on it effectively, then there’s not enough information on the ticket. Even if you lucked out and the developer who sat in on the refinement / estimation meeting is the one who ends up implementing it, odds are your testers likely will not have that context, and may not properly verify the feature.
Estimates
Estimation is a bit of an art. I’ve had teams use arbitrary numbers (fibonacci sequence) to associate “story points” to tickets. While I can appreciate that this avoids associating hard time constraints to estimated work, at the same time it becomes an obtuse abstraction layer that doesn’t provide much value and often obscures the definition of the estimate for anyone outside of the immediate team - perhaps that’s by design?
I personally prefer t-shirt sizes for estimates; they can still be used in a similar way, but can still provide value to external observers. Everyone understands the concept of “Large”, or at least within an acceptable margin of error - the actual value of large will still likely differ between teams. What’s important is a company strategy role can look and say “oh, that will be a large task compared to this small one” without having to do any sort of mental translation between “3” and “5”.
Estimates should also be managed at three different levels in my opinion. There are three times where estimates provide value:
- the roadmap stage
- when planning work at a 3-month resolution
- the refinement stage
- when breaking an epic or story down into its composite tasks and getting a feel for how much time needs to be set aside when scheduling the next quarter
- the implementation stage
- when determining how much of the current sprint will be taken up by a story
Each of these allows for a different level of estimation accuracy; you don’t need to know down to number of hours when planning the quarter.
Once estimates are in place, it’s important to reconcile them against the actual work effort completed with that task. I find a lot of teams don’t follow through on this component of estimation, despite the fact that it provides a great tool for future estimation and planning. Having a story with an estimation of “3” or “Large” doesn’t mean much if you can’t translate that to an average amount of expected work, and is a way to introduce scope creep and missed deadlines into your flow.
Bugs
Not only should your bugs be ticketed separately for reporting purposes, but there are a number of best practices around the management of bugs that most software development teams should be following:
- Bugs should have a severity. A production-environment bug that has no workarounds and is breaking important business functionality should be labeled as critical and scheduled as such, whereas an issue with page styling can likely wait until the next release. Both require a different level of attention and response from the team, so it should be clear when an issue requires an “all hands on deck” approach. Conversely, if all bugs are critical then none of them are critical.
- Bugs should have reproduction steps. Before even entering triage a bug should have the steps required to reproduce the issue, along with the expected and actual behaviour observed. This prevents developers from spending their time hunting for the issue and gives them a clear criteria for solving (and automated-testing!) the bug. In addition, going through the process of writing out the reproduction steps often highlights information that is important for determining triage and severity, or at the very least helps narrow down the affected scope of the bug.
- Bugs should have a cause. You don’t need to spell out exactly what change or line of code caused the issue, but it’s important to identify if a bug was because of a missed requirement, failed or missing test, deployment issue, conflict, or other cause. This higher-level categorization will help quickly identify what areas of the software development process are causing downstream issues with deployed bugs. In addition, if it can be associated with a feature, it should be recorded as such for later metrics (see below).
Tech Debt
Another hot topic for software development teams of any size, tech debt is the constant pain in the neck that results from maintaining and writing any amount of code. There’s no getting away from it, but there are good ways to manage it.
- Document when technical compromises are made. Where possible, if the business is deciding to implement a feature with a known technical risk, it should be documented. This is primarily to identify the cause later on when you get back to actually cleaning up the tech debt, ensuring that you don’t accidentally undo a feature or requirement while fixing it.
- Maintain the technical debt backlog. Ensure that this backlog is reviewed on a regular basis (perhaps monthly?) to keep higher risk items top-of-mind when considering plans and estimates for future work.
- Have a standard allocation for tech debt work items. Whether it’s a certain percentage per sprint, or mixed within the release cadence of the company (maybe you have a “first sprint” where you focus entirely on tech debt after a major release), it’s important to specifically set aside time to address technical issues.
- Make the tech debt visible. Whenever a tech debt item is directly impacting something, make it known. If there’s a performance or technical requirement bug that was caused by a known tech debt item, link the tasks together. If you’re estimating a new feature and it’s made more difficult because of tech debt, link the debt to the story. The more visible that the impact of tech debt is, the more likely it will be addressed.
Sprints
You can’t throw a stone without hitting a team that is practicing some form of Agile software development nowadays, with the large majority following the “scrum” ideology. A major tenant of this is the concept of “sprints”, where teams bite off small iterations of work (generally two weeks) where they can focus on short term goals and objectives. Within this practice, there’s a few gold standards to follow.
- Priorization. It should be clear which tasks have the highest priority within a sprint, so that when developers are looking for the next thing to do it’s obvious what will provide the most value.
- Estimate Tracking. Not only should you be using ticket estimates to ensure you’re not stuffing too much (or too little!) work into a sprint, but you should also be keeping track of actual work completed against those estimates to maintain metrics used in future sprints.
- Subtasking. Before or during sprint planning, larger estimated stories should be broken into individual tasks that the implementation team can pick up and run with. Ideally these tasks are small enough that they can progress at a daily rate so the story’s progression can be clearly identified.
- Retrospectives. One of the main benefits of breaking work into small sprints is the ability to reduce the feedback loop to quickly identify issues and resolve them. But if, as a team, you’re not taking the time to identify process issues that benefit quickly disappears. A simple hour spent discussing “what went well, what went poorly, and what do we want to try differently” next sprint is all that’s required, and I’d argue is one of the most important parts of the sprint philosophy.
- Standups. Another given as most teams who are practicing some form of agile often have these morning meetings, but I’m not sure a lot of teams are actually getting the intended value out of them. The idea here is to identify any immediate blockers or action items that need to be addressed, and to do it as quickly as possible to prevent any work disruptions. A lot of standups I’ve attended involved checked-out employees just regurgitating “what I did yesterday, what I’m doing today, no blockers”, which I think anyone would agree doesn’t provide a lot of value.