Guidelines for a healthy code review culture

Code review is emotional labour: we are emotional beings who are emotionally invested in this work, down to the code that we write. Giving and receiving feedback is hard, and we must all share this load to build a healthy code review culture.

On the surface, code review is about preventing things from breaking, and maintaining code health. In reality, it is (and should be) much more than that.

The goals of code review

  1. To work together to prevent defects or vulnerabilities from making it to production code
  2. To promote maintainability, preventing future frustration and confusion
  3. To provide an opportunity for education so collaborators can learn and grow, and to bring in new collaborators
  4. To foster shared understanding, ownership, and accountability of the code through collaboration, leading to a more functional and fulfilled team of contributors

Ultimately, code review is a dialogue, one that is especially critical to our movement since most of our work is done remotely and asynchronously. We are all part of a community of code reviewers, and working together to build trust inside this community will help us achieve the goals of code review, support existing community members, and bring in new members.

What makes a code review culture healthy?

A healthy code review culture is one in which feedback is welcomed without fear.
—Cindy Cicalese, Principal Software Engineer, Wikimedia Foundation

Let’s break this down:

  • Feedback is welcomed: In a healthy code review culture, getting feedback means that a defect was caught before going to production, knowledge was shared, and people worked together to make the code better. Working in this kind of culture is fulfilling.
  • Without fear: Psychological safety is the foundation of a healthy code review culture.[1] People need to feel comfortable providing and receiving feedback. Submitting a patch or providing criticism can be intimidating, and this process requires trust. People who feel safe are more able to propose new ideas, experiment, and grow. People who don’t feel safe will eventually stop contributing and leave.

We can create this kind of culture by defining our values and applying them to how we work.

Values of a healthy code review culture

Respect and empathy over ego

  • Our code does not define us: Though we are heavily invested in the code we write, coding is what we do, not who we are. Critique the code, not the coder.
  • Lead with compassion: Start with yourself, then extend it to everyone. We are all doing the best we can right now.[1]
  • Build trust: Kindness, empathy, and curiosity can build relationships between collaborators. Trust leads to psychological safety, which leads to great work and happy contributors.
  • Assume competence: Ask questions rather than assuming incompetence. You might be the one who is misunderstanding something.[2]
  • Be aware of power dynamics: Listen to people who have less experience than you. Lift up quiet voices. Defer to others often.


Collaboration over competition

  • Focus on collaboration: When you focus on working together, egos won’t get in the way. Collaboration empowers more people to contribute and leads to a better product.
  • Acknowledge the challenges of collaboration: Some of us find it difficult to manage our tone, some of us struggle with letting go and deferring to solutions we don't like, and some of us withhold critical but useful feedback for fear of seeming negative. Remember that everyone is different but we can all grow.
  • Embrace feedback as a gift: In a healthy culture, every piece of feedback will be welcomed as something that improved the code, taught us something, or made us think.
  • Encourage curiosity and experimentation: In a safe environment, we can learn, innovate, and have more fun through play.
  • Disagree with humility: When you disagree, state your opinion respectfully, and be open to having your mind changed. Ask yourself if something really, truly matters. Be willing to give alternate solutions a chance.

How you communicate matters

  • Consider your tone: Tone impacts morale. It determines whether code review is a productive, encouraging, and fulfilling process, or an intimidating, frustrating, and hurtful one. A kind, respectful, and non-judgmental tone will make people more open to constructive feedback.[3]  The comments “X is wrong” and “have you considered Y?” have very different effects.
  • Don’t state opinion as fact: You might shut down discussion. Instead…
  • Ask questions and make recommendations: Provide context, explain how the code could be better, and outline the impact of changing it. Provide links to documentation—doing so demonstrates that you had to look it up at least once.
  • Ask "what do you think?" and listen to the response.[4]
  • If you do state something as fact, make sure you’re right: Otherwise, the code author will waste time and be frustrated. Provide references if possible. If you’re not sure about something, ask questions instead.
  • Be clear about what’s a functional defect and what’s a preference: You might consider explicitly labeling your comments as such.
  • Express gratitude and encouragement: “Positivity” is a loaded term, and advice like “add praise to every review” can seem fake or unnecessary. Instead, be aware of opportunities to provide praise: if you learned something or were impressed, say so. Gratitude and encouragement can be a part of every review: even a simple “Thanks for doing this” or “Nice work!” with your +2 makes a difference, because positive feedback motivates further contributions and makes people more open to critical feedback.
  • Leave out judgment and sarcasm: Review the code itself, not the author. Remember that everyone makes mistakes and has room to grow, and good collaborators help each other grow. Judgmental or sarcastic comments have no place in collaborative, productive code review.
  • Be aware of people you may be silencing: A culture of negativity and unrelenting criticism silences important voices.


Remember the bigger picture

  • Don’t lose sight of context: Instead of focusing on obscure issues or nitpicks, focus on the overall place of the code within the codebase. Consider the larger goal by asking yourself “is this feedback valuable?” Line-by-line review is important but should be done within the context of the project as a whole. You may help the project more in the long run by encouraging a contributor rather than frustrating them.
  • Understand and adapt to different review contexts: For a significant, complex patch authored by a seasoned contributor, refining and strengthening the technical solution might be the primary goal. For a small patch uploaded by a new contributor, inclusion and education are more important. Adapt your language and level of criticism to the context at hand.
  • Avoid leaving an avalanche of comments:[5] Leaving a lot of comments at once can be overwhelming for the author, especially if done by multiple reviewers. It’s easy to feel ganged-up on. If you find yourself leaving a double-digit number of comments, especially on a smaller patch, ask yourself if these comments are really necessary or adding value. If you do have to leave a lot of comments, acknowledge this, ideally by reaching out to the author privately. Offer help and be extra kind.
  • Let go: Gracefully accept compromise or defeat.[6] If it’s not part of documented standards, prioritise the code author’s preferences. Remember that there is no such thing as perfect code: a quest for unattainable perfection leads to frustrated contributors and slow progress. Ask yourself “what’s the worst case scenario if this code gets merged as-is?” Do your best, then move on.

Thoughtful efficiency

  • Aim for clarity: Be clear about what you consider a blocker as opposed to a matter of preference or a request for clarification. Avoid euphemisms and incomplete sentences: clearly state what you mean and what you think needs to happen. Make it clear how conflicts will be resolved.
  • Provide complete reviews: Review the entire patch and raise every issue at the earliest opportunity. When a new patchset is uploaded, review only the new changes. Aim to merge the code in the fewest number of review/response cycles. If you don't feel able to provide a complete review initially (e.g. if the codebase or programming language is new to you, or for a very complex patch), consider discussing the patch with the patch submitter first.
  • ...and identify when you can't: If you don't feel able to provide a complete review, consider why: is it a question of experience, resourcing, or social dynamics? If the codebase or language is new to you, or for a very complex patch, consider discussing the patch with the patch author first.
  • Stay focused: A patch should have one idea and its consequences. If you see something in nearby code that you don't like, either as a reviewer or developer, make a note or file a task, don't add more changes to the commit. Big picture or architectural discussions should happen elsewhere.
  • Avoid nitpicking: Nitpicks are comments about minor, unimportant issues that distract from the ultimate goal of the review.
    • Two developers, given the same problem, will rarely write the same code. Respect creative differences. Don't repeat the work of the developer by asking them to write the exact code you would have written. The code just needs to be acceptable, it doesn't need to be perfect.
    • When writing a review, ensure that minor issues (like code style) are not the focus.
    • Frame your comments as helpful tips, not faults to be rectified. Mark nitpicks as such and do not allow them to block merging.
  • Respond quickly: Critical feedback goes over better if it’s provided promptly and followed up with quick responses to questions or updated code.
  • Automate: Everything you automate (via tests, linters, and CI) is no longer a burden during code review. Automate as much as you can, and note repeated discussions as potential opportunities for automation.

Refuse to normalise toxic behaviour[5]

  • Use your privilege: Whatever form it may take, use the authority you have to lift up your collaborators and correct or reject toxic behaviour.
  • Return to values: When you see a problem, point it out and back it up with a reference to these values.
  • Learn from your mistakes: We all have room to grow—apologize sincerely and learn from your mistake, then move on.
  • Don’t adapt to a toxic culture: We shouldn’t waste time policing how many emoji or exclamation points we use. Instead, we should question toxic cultures.
  • Get help when you need it: Contact the project maintainers or submit a report to the Code of Conduct Committee.



Acknowledgements

Many thanks to everyone who provided ideas, feedback, and resources that went into creating these guidelines.

References

  1. 1.0 1.1 Kadam, Aniket (1 April 2018). "Compassionate Coding: (The secret of high performance teams)" Medium.com
  2. Kammer, Liz; Hodges, Maggie; Murillo, Ambar (06 November 2019). "Code Health: Respectful Reviews == Useful Reviews". Google Testing Blog.
  3. Orosz, Gergely (30 September 2019). How to Make Good Code Reviews Better. The Overflow.
  4. Ciavolino, Amy (25 July 2018). A Guide to Mindful Communication in Code Reviews. Kickstarter Engineering.
  5. 5.0 5.1 Sankarram, Sandya (19 January 2018). Unlearning toxic behaviours in a code review culture. Medium.
  6. Atwood, Jeff (09 May 2006). The Ten Commandments of Egoless Programming. Coding Horror.