Software Development Team Standards - Development Practices

It’s post two of my series on software development team standards! Today’s post focuses on development practices - the particulars of writing and managing code. Here’s a few best practices I’ve observed, implemented, and/or witnessed over the years from high functioning teams.

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:

Development Processes

For any group of more that one developer, development processes are important. These allow you to review and implement consistent, working code with as few roadblocks and conflicts as possible.

Version Control

Everyone and their dog is generally using Git for their source control management, sometimes at a different host like bitbucket over github, so I’m not necessarily referring to that. What I’ve seen is more along the lines of branching strategy, where the way teams manage their develop, feature, release, hotfix, and master branches can cause cascading issues.

Complicating what can be tested and when, adding overhead and complexity to release management, lengthening the feedback loop, and even causing production-environment issues are all potential symptoms of a poor branch management strategy.

I’m a personal fan of Gitflow (and have been since it’s inception over 15 years ago), and successful teams I’ve worked with have used some flavour of that.

Definition of Done

One of the best things a software development team can do is agree on a definition of done. This is a “contract” of sorts that covers each task type that lays out exactly what needs to be completed for the implementation team to consider a task completed. This often includes items such as:

  • Working build; the build system has successfully compiled the project code and all automated gates (automated tests, lints, etc.) have passed
  • Pull request accepted; other teammates have reviewed the changes and any comments have been addressed
  • Automated tests added to cover ticket success criteria. This could be both unit and/or integration tests, depending on the situation
  • For stories, the feature has been demonstrated either through recorded video or to one or more stakeholders

This contract is important to avoid any inconsistency issues between developers as well as to cover all the important parts of increasing release confidence.

Context Switching

One important metric with development processes that I find not a lot of teams talking about is “context switching”. It’s well documented that context switching has a cost associated with it, but I don’t know if there are a lot of teams that are proactively trying to manage context switching as part of the development workflow.

One way to approach this is to ensure there’s as little friction between when a developer starts a task and when they’ve finished. If there’s a lot of blockers, down time when deploying to test, large gaps of time between submitting and reviewing a pull request, these are all times when your teammates will often switch to something else while they wait. While this might look good on paper, having a developer with 6 active tickets at any given time actually reduces their overall productivity and increases the risk of missed requirements, bugs, etc.

Another way to identify context switching issues is to check if there are any stages in your development processes that “wait” on other, non-story-related tasks to complete before proceeding. For example, if you test a batch of stories together rather than independently, it creates another bottleneck where individual stories have to wait on external blockers before proceeding.

Code Reviews

Code reviews (aka Pull Requests) is a standard practice nowadays, but even within that I’ve seen variation into exactly how teams perform their code reviews. Some teams rarely, if ever, actually leave comments on reviewed code, where other teams fill PRs with pedantic rejections based on whitespace and brackets. It’s important to identify what kind of reviews a team finds valuable (which can definitely vary based on the experience, tooling, and coding practices of the team) and get a consensus on what exactly a PR should and shouldn’t be responsible for.

Code reviews should be mandatory before code is merged into a main branch to ensure every bit of code has a second set of eyes on it, and a code review should have some level of commentary within it. This obviously scales based on the number of developers on the team as well as the size of the feature, but a good rule of thumb I’ve tried to follow is to leave at least one comment on any given review. Even if it’s a “I like how this turned out” or “I’ve never seen this before, what does it do?”, it’s important to be engaged with the PR that you’re reviewing, and I’ve found this little metric enables me to focus on the code rather than just scrolling through pages of text.

Age of Tickets

Another important metric to keep track of is how “old” a ticket is once it’s been started. The longer a story or task stays in an implementation state, the higher risk for merge conflicts, integration bugs, and other issues. If a story or task isn’t progressing every day, it should be considered blocked, and (as mentioned earlier) should have a clear indication of what it’s waiting for / how it could proceed.

Assignability

A rough anti-pattern I’ve seen some teams adopt in the past is certain tickets requiring specific employees in order for them to be implemented. Whether it’s because of specialized knowledge or experience, it’s an easy pattern for team leads to fall into. Ideally, the tasks within a team should be able to be picked up by any team member, and if there’s a gap in knowledge or ability, efforts should be made to share that information so that more people on the team can be more productive over time.