Photo by John Schnobrich on Unsplash
Code reviews can be contentious. I had an incredible experience giving my first conference talk titled â€œUnlearning Toxic Behaviors in a Code Review Cultureâ€at AlterConf. I went into the experience preparing for any pushback and criticism that I might receive while encouraging software teams to create supportive code review environments.
But I totally underestimated how supportive and receptive the AlterConf community is. I worried about pushback, but that community greeted me with kindness and encouragement instead. â¤
Twitter was extremely supportive.
Iâ€™ve been asked to share my slides (and I have), but I now worry that the slides alone are unhelpful and easily taken out of context, because the deck lacks context and explanations. Since my slides are floating around the internet without these key features, I decided to do a write-up to elaborate upon my talking points. The video recording was released a few months after this article was published.
Iâ€™ve listed below some common unhelpful behaviors people display during code reviews, and some recommendations on how software teams can make their teams more supportive by refusing to normalize toxicity. All of the behaviors I describe were either witnessed by me or happened to an industry contact of mine. Iâ€™ve been guilty of several of these behaviors in the past, too.
Unhelpful behavior #1: passing off opinion as fact
Donâ€™t make claims unless you can cite documentation, formalized guidelines, and coding examples to back those claims up. People need to know why they are being asked to make a change, and another developerâ€™s personal preference isnâ€™t a good enough argument.
Instead of saying:
This component should be stateless.
â€¦provide some context behind the recommendation:
Since this component doesnâ€™t have any lifecycle methods or state, it could be made a stateless functional component. This will improve performance and readability. *Here* is some documentation.
Passing off opinion as fact is also common when developers discuss style and syntax preferences. These are really important discussions to have, but never in a code review, because style and syntax have nothing to do with the issue the developer was initially trying to solve.
Have these discussions separately and decide which style guidelines you will be following as a group. Implement a linter and an automatic code fixer. This way, you can reference your style guidelines, and not your personal opinion, during the code review when you see inconsistencies.
It is especially important not to pass off your opinion as fact when you have higher rank and authority within your team or company. If you do this, developers will feel they have no choice but to quietly implement your demands.
Unhelpful behavior #2: overwhelming with an avalanche of comments
When a person makes an error, chances are high that they have made the same error in several places in their changeset. I have noticed that reviewers sometimes point out every single one of an errorâ€™s many occurrences instead of leaving one detailed note with links to helpful resources.
Consolidating comments allows you to convey the same message without overwhelming the review seeker. An avalanche of comments for one problem, duplicated, comes off as nitpicking.
Unhelpful and overwhelming:
Leaving multiple comments for â€œone error, duplicatedâ€ (trailing whitespaces)
I can understand the argument that pointing out every place an error occurs on a PR can sometimes be useful, since the comment disappears when the developer resolves the issue in subsequent commits. However, after this error has occurred across a changeset, it should be clear that the developer was not aware of a certain guideline and simply needs to be pointed to the correct resources.
Unhelpful behavior #3: asking engineers to solve problems they didnâ€™t cause â€œwhile they are at itâ€
Avoid asking developers to solve issues that arenâ€™t directly related to their changeset or the problem their changeset is trying to solve. Even if a developer is extending or modifying a messy part of the code that is rife with bad practices, donâ€™t ask the developer to fix them in that pull request just because their changeset happens to touch the messy code.
I am not suggesting that developers should feel no accountability for code just because they didnâ€™t initially introduce it. In fact, it is not collaborative to say something like, â€œnot my code, not my problem.â€ I am just suggesting that it would be more appropriate to create a separate ticket and PR to address the messy code. This way, you avoid drastically increasing the scope of someoneâ€™s work, but the messy code still gets fixed.
TL;DR: Donâ€™t ask devs to fix problems â€œwhile they are at it.â€ If the code solves the issue/ticket the dev was working on and doesnâ€™t introduce any new issues to the codebase, give the pull request a â€œthumbs upâ€ and then create a ticket to clean up the bad code.
Unhelpful behavior #4: asking judgmental questions
Avoid asking judgmental questions like:
Why didnâ€™t you just do ___ here?â€
Asking such questions implies that a perceived simple solution should have been obvious. It also forces developers to have to defend themselves.
Oftentimes, these judgmental questions are just veiled demands. Instead, provide a recommendation (with documentation and citations) and leave out harsh words.
You can do ___, which has the benefit of ____.
Unhelpful behavior #5: being sarcastic
There is no appropriate time to be sarcastic when offering someone feedback. Sarcastic comments tend not to provide context or actionable feedback. Instead, describe the issue with details and provide recommendations, but leave the caustic jokes out.
Did you even test this code before you checked it in?
This breaks when you enter a negative number. Can you please address this case?
Here is another example of a code review comment that isnâ€™t funny or helpful:
I donâ€™t mean weâ€™re mean-spirited. I just mean that we are merciless. Youâ€™ll notice that I left the comment â€œBeep!â€ on the imports of every file you touched. What I meant was, â€œYour imports violate our standard convention â€” we order them by built-ins, then third party, and then project level,â€ but that was too much to type on every file.
In the above example, â€œbeep!â€ is not helpful or descriptive. This practice is simply pedantic humor that does nothing to better the review seeker.
Unhelpful behavior #6: using emojis instead of statements to point out issues
Avoid using the thumbs-down or puke emoji to point out issues in code. This is as unhelpful as sarcasm for similar reasons. Emojis are cryptic and easy to misconstrue. Emojis waste peoplesâ€™ time as they try to figure out what you mean.
Donâ€™t use emojis to point out coding problems
You shouldnâ€™t be having visceral reactions to peoplesâ€™ coding mistakes anyway.
Itâ€™s okay to use emojis like â€œthumbs-upâ€ or â€œhoorayâ€ to signify that code looks good, but donâ€™t use them to point out problems.
Emojis are great when used to praise
Unhelpful behavior #7: not replying to all comments
Review seekers can contribute to unsupportive environments, too. If you merge code without addressing all the feedback, people are left wondering why they bothered to help you, and you send the message that some opinions are worth more than others.
If a comment is out of scope or you wonâ€™t be taking action on the feedback, just provide a brief note explaining why.
Donâ€™t ghost people.
Merging code without addressing all the feedback
Unhelpful behavior #8: ignoring toxic behaviors from high performers
Toxic behaviors should not be ignored or deemphasized because a developer is a high performer and extremely productive. Though this developer might be doing a fantastic job, it is important to keep in mind that this developerâ€™s toxic behaviors make them draining and stressful to work with for other developers.
On working with developers who commonly display toxic behaviors:
Others will find working with this individual draining and demotivating. Theyâ€™ll find themselves going to great lengths to avoid interacting with them, even if it means negatively impacting their own ability to complete tasks. Communication will shut down throughout your organization. If it becomes bad, your team will start looking for opportunities elsewhere. While you deal with the fallout of the exodus of talent and failing projects, this particular kind of developer will happily continue working as if nothing was wrong. â€” Joseph Gefroh
Not taking steps to unlearn these toxic behaviors can have serious setbacks for the team, as developers feel overwhelmed, attacked, and demotivated. They start to dread the feedback processes that are supposed to help them grow.
I would personally feel a lot of anxiety whenever I got an email that a previous coworker (who was known for delivering toxic, unhelpful feedback) had commented on my pull request. Though toxic behaviors affect everyone differently, we can all agree that no one benefits from this toxicity.
Note: I want to be clear that slipping up and displaying one of the above toxic behaviors alone doesnâ€™t make a developer â€œtoxic.â€ Repeat offenses and patterns of caustic feedback say a lot, though.
Helpful Code Review Practices
The following are some recommendations that can apply to any person in a collaborative, feedback-driven environment, even if they are filtered through the lens of a software engineerâ€™s eyes and are in the context of code reviews.
Helpful Behavior #1: use questions or recommendations to drive dialog
Never make demands for people to implement changes or ask judgmental questions, because this does not open up a dialog between you and the person whose code you are reviewing.
Why didnâ€™t you just pull these translations into a constants file?
Though the above is a question, it doesnâ€™t create a dialog between you and your review seeker. It just forces them to defend themselves. Instead, ask what the review seeker thinks of your proposed solution, like:
What do you think about pulling these translations into a constants file? There are a lot, and a separate file might make sense at this point
â€¦or make a recommendation like:
You introduced a lot of translation calls for â€œfeature xâ€ in this file. It might make sense to create a separate file devoted to â€œfeature xâ€ constants.
Helpful Behavior #2: collaborate, donâ€™t back-seat drive
When you pair-program with another person, you should be there to ask questions, debate, and point to resources.
â€œâ€¦when you want to help out or work with others, you should fully engage and not just butt in sporadicallyâ€ â€” Recurse Centerâ€™s User Manual
Helpful Behavior #3: respond to every comment
If you as a review seeker donâ€™t plan to apply a personâ€™s feedback, just leave a note letting them know. Donâ€™t ignore those who take time to help you.
Person A: What do you think about creating a helper function for this api call? Looks good to me otherwise
Person B: That line wasnâ€™t part of my changeset. Iâ€™ll merge this code for now, but Iâ€™ll also create a separate GitHub issue for the api call and put it in our groupâ€™s backlog of to-do items.
Helpful Behavior #4: know when to take a discussion offline
After dozens of contrasting PR comments and proposed solutions, it should be clear that online communication has become unproductive for the issue at hand. Send a meeting hit to involved members to discuss the issue offline.
This way, your group can come to a decision more quickly and apply the solution.
The kinds of problems that take hours and tons of comments can usually be resolved in a few minutes of productive talk. â€” Tidy Java
Helpful Behavior #5: use opportunities to teach, and donâ€™t show off
Before choosing to participate in a code review, ask yourself:
Is your comment helping the other developer learn or are you nitpicking to participate?
Reflect on why you are participating. Remember that the goal behind code reviews is to teach and help other developers grow. The goal isnâ€™t to grandstand.
Helpful Behavior #6: donâ€™t show surprise
Be careful not to show surprise that someone doesnâ€™t have the same knowledge that you do on a topic. Being comfortable admitting you lack experience with a topic is a great way to ask for help. Donâ€™t make people feel bad that they â€œshould already have knownâ€ this piece of info.
For more on this, see Recurse Centerâ€™s Social Rule â€œDonâ€™t Feign Surpriseâ€
Helpful Behavior #7: automate what can be
Reviewing issues that can be caught by linters, git hooks, or automated tests are unhelpful because they often result in an avalanche of comments and come off as nitpicking. People are not particularly good at catching these issues, which is why automation tools exist.
There are also tools out there that will run your tests when code is checked in and display warnings that a changeset is in violation of any of these tests. TeamCity and Jenkins CI both offer this functionality.
Also, use git hooks. Git hooks run tests and linters when someone tries to check code in and they will intercept the commit if any buggy, unlinted code was introduced.
Let the tool point out issues so people donâ€™t have to.
Helpful Behavior #8: refuse to normalize toxic behavior
Donâ€™t join in and contribute to code review toxicity because it seems like the status quo, a hazing ritual for new developers, or just the way things are.
Search for teammates who are supportive and who will back you up.
If you notice someone being unhelpful during code reviews, consider letting them know (if you feel safe in your role/company doing so) and be direct.
Helpful Behavior #9: managers â€” hire carefully, listen to your team, and enforce
Managers have a lot of power to create positive and supportive cultures on their teams.
To paraphrase the advice from â€œToxic Developers Considered Harmfulâ€:
- Prevent toxic developers from joining your team. During the hiring process, donâ€™t just stress the technical. Learn how your candidate collaborates and communicates. Critically analyze their work and see how they react. Make sure every hire is a culture add, not just a culture fit.
- When toxic developers trickle in or you inherit them, ask your direct reports how their experience is working with others on the team during 1:1â€™s. If you have a toxic dev, your direct reportsâ€™ feedback will show it.
- Talk to your toxic dev. Give them specific examples and actionable feedback. Work with them throughout your manager/direct report relationship.
- Donâ€™t isolate the toxic developer (*)
- Iterate that you expect your team to contribute to a supportive environment
(*) Though the article suggests to isolate toxic developers, I believe itâ€™s important to encourage the toxic developer to continue to collaborate with the rest of the team, but in more healthy ways. Isolating toxic workers wonâ€™t solve the problem. Though giving this dev independent work allows the team to suffer less toxicity in the short run, this toxic developer has not unlearned unhelpful behaviors. Theyâ€™ve just lost the platform to display these behaviors.
Helpful Behavior #10: set the standard as your team is small and growing
Teams that are small enough can adopt ideas and implement them from the start. Even if you donâ€™t think itâ€™s necessary to set a standard of what is and isnâ€™t okay because your team is currently collaborating well, remember that you want your team to stay great as you invite new members in.
Helpful Behavior #11: understand you might be part of the problem
In order to foster more supportive environments, itâ€™s important for people to be honest with themselves and reflect on any unhelpful behaviors they may have ever displayed.
As a junior engineer, there were several occasions when I noticed a bug in someoneâ€™s code and delighted, because it meant that I could point it out and be part of the review. I know now that I was using the opportunity to show off, not teach. I am trying to be mindful of this going forward.
I think everyone should have this tough moment of self-reflection too.
One last thingâ€¦
I am not policing the content of feedback, just asking people to be mindful of their tone
I know feedback is important and I am not waging a war on feedback. Iâ€™m also not asking teams to compromise their code quality. A supportive code review culture and high code quality DONâ€™T have to be mutually exclusive.
I simply hope people take steps to provide constructive, actionable feedback and create more supportive environments, so developers feel comfortable to learn, grow, and make mistakes. We can all improve together.