Development

Best practices for performing code reviews

The process of writing code resembles the practice of normal writing - your first draft isn’t the final one. The code you write has to undergo testing, debugging, and reviews before it can be integrated into the final product and shipped off to users. Without these checks, the code would be filled with bugs and errors that may prevent it from functioning properly or cause security flare-ups.

In this article, we look at one such checking mechanism to improve code quality: code reviews. The benefits of doing a code review go beyond better-performing code, and while it is a fairly straightforward process, there are small tweaks that you can make to considerably boost its efficacy. So, how can you best perform code reviews and integrate them into your regular team workflows? Let’s find out.

What is a code review and why is it important?

Code review is a systematic approach to evaluating code for the purpose of improving its quality by discovering bugs and other mistakes. Usually, the reviewer is not the person who wrote the code.

Reviewers check for a variety of things in the code. Some of these are:

  • Gaps in the logic
  • Whether each case is covered or implemented
  • Alignment with the organization’s coding standards and style guidelines
  • Whether the code does what the author intends for it to do
  • Whether the code is legible and reproducible

By checking for these things, code reviews prove to be important feedback mechanisms that encourage developers to write and subsequently ship better code. There are several benefits to performing code reviews as part of the team’s regular workflow. These include:

  • Identifying errors early in the process: The last thing you want to do is ship bug-ridden code, so it is good practice for developers to have their source code double-checked by peers. A code review’s most fundamental benefit is the extent to which it can reduce the number of errors in a codebase. That said, it also goes one step further. Instead of waiting until the code is shipped to fix any errors, doing code reviews as soon as possible after the code is written is a sustainable approach to improving the software. There are fewer chances of the problem getting out of hand, reducing the technical debt your team has to pay. Having worked on the code recently, the engineer has it fresh in their mind and will find it easier to communicate with the reviewer and make any changes. As a result, code reviews also make the troubleshooting process more efficient.
  • Spreading knowledge: When team members review each other’s code, they learn something new. Code reviews encourage the exchange of knowledge between employees, allowing the team to grow together. They are a great way for junior members to gain insight into the workflows and coding practices of more senior members. For example, junior developers may not always know how to optimize their code. A code review presents the perfect opportunity for more experienced team members to share the best optimization techniques and help the juniors grow. Coding best practices and standards can also emerge from such knowledge transfer within and across teams.
  • Better developers: Each time a developer reviews code or has their code reviewed, they actively learn what worked and what needs to be improved. Code reviews are a form of feedback that can be constructive when carried out thoughtfully and that inculcate a sense of responsibility in the developers. Having access to such feedback on the job is instrumental in helping your developers grow and refine their skills.
  • Adherence to coding standards: Setting standards across the organization is important to maintain continuity and coherence in the code. Code reviews drive the adoption of these standards as team members hold each other accountable. Reviewers may, for instance, look out for security vulnerabilities and notify the code authors in case anything needs to be fixed. Coding standards allow developers to maintain continuity across time too. During code reviews, both parties are encouraged to think about the future of the codebase, i.e., who will manage it and make any necessary updates to it.
  • Smoother testing: When the source code has been reviewed and revised according to the organization’s best practices and standards, quality assurance testing becomes a smoother process. This is because coding standards make it easier for testers to read and understand the code, avoiding preventable hiccups and delays.
  • Team collaboration: Collaboration between team members is at the heart of any meaningful software development process. When issues are flagged in a code review, the reviewers and author put their heads together to devise new solutions for the problems. This fosters and renews a collaborative spirit among them.
  • High-quality documentation: Code reviews are a great way not only to share and produce knowledge but also to document it for developers in the future to reproduce, upgrade, and learn from.

What are some best practices around code reviews?

There is no one way to incorporate effective code reviews into your team’s workflow. Attempting to introduce multiple significant changes can throw your team off-guard and result in an inefficient transition. Instead, we recommend adopting some best practices that align with the needs of your team and the larger business.

Open draft pull requests early

In a remote-first world, your processes may be slower compared to how they functioned when working in person. To prevent this from happening, aim for quicker feedback loops that are comparable to what you would be accustomed to if the team was operating in person. One way to create that is by opening pull request drafts early.

Avoid waiting until the very last second to open up a pull request and ask for it to be reviewed. Instead, create a culture of opening pull requests early and getting feedback early so that the developer has enough time to work on any fixes.

Once you have something in working condition, open a pull request and make sure that your approach is in the right direction. You can choose to add your own comments to the draft and offer explanations for certain coding decisions. This will help reviewers, and it creates a culture of quick iterations.

Define the scope

It is also good practice to open small pull requests. If you have code that might result in a thousand or ten thousand line change, open smaller pull requests. You can even open a target branch, i.e., create a feature branch and open several small pull requests against it. Then, you can merge them with the primary one. You can do this even when it is something that has to be merged all at once.

That way, the chunks that reviewers must look at are much smaller and easier to go through. The reviewers can think about each aspect of the feature in isolation. If you submit code that includes a wide range of bugs or features, the reviewer will be unable to give their full attention to each. Lack of clarity regarding the purpose of that code chunk could lead to unnecessary discussion and prolong the review. There is no fixed rule, but for most reviewers exceeding 200-400 lines of code per review may negatively impact the quality of their inspection.

Why is this important? Not only is it a more efficient approach to reviewing large code chunks, but it is also mindful of the reviewers’ time. In a way, the reviewers are also doing you and the team a favor by reviewing your code. They have other things on their plate, including their own code.

So, small pull requests make it easier for reviewers to inspect the code. They also review faster, which allows you to fix any errors and merge the pull requests faster. 

In addition to narrowing their scope by opening small pull requests, the author of the code must spend some time ensuring that the code is ready to be reviewed. The code must be complete and have passed all relevant tests and checks before it is handed over to a reviewer.

Merge pull requests quickly

Don't leave pull requests open for a very long time. Code that is not in production is risky. The longer it is open, the more it is out of date, and the fewer people are aware of it. The environment around it will have changed in that time, which can increase the risk of errors cropping up in that code due to incompatibility. The most effective solution to this is to review the code quickly and not let it live in the backlog for a long time.

Reach out to reviewers

Build a culture in which it is acceptable to message team members about pull requests. Encourage developers to make it quick by sending a message in the team’s Slack channel or to the potential reviewer directly to ask for a code review. Let that be something that's okay to do as part of your internal culture. This saves time and allows authors and reviewers to collaborate closely with one another throughout the process.

Keep in mind that at least one of the reviewers should be a senior developer or a project lead. It is best to limit the number of reviewers to one or two. Involving too many people in a review can end up being counterproductive. It also helps if the reviewers are already familiar with the particular codebase to some extent.

Use code owner files

If you are a large organization or working in a monolith, use code owner files. This way, if somebody opens a pull request, you are automatically notified about it as you are the owner of that particular part of the codebase. This is another way to speed up the time that it takes to review a pull request. Code reviews are sometimes viewed as being time-consuming, so it is in your best interest to speed up the process as much as possible without losing out on review quality.

Build a positive culture

Build a culture in which code reviews are perceived as an opportunity for collective growth. Avoid making developers feel discouraged by the reviews. One way to do this is by clearly distinguishing between the developer and their code and only critiquing the latter. Pull requests are not for comments on the developer’s skills.

Reviewers should then aim to provide constructive feedback, ideally in the form of specific suggestions and open-ended questions.

Suggestions like “Hey, have we thought about this? Here’s another way we could potentially do this.” are a lot more effective and foster clear communication between both parties. To ensure clarity and comprehension, reviewers can make their suggestions specific, as well as highlight the part of the code that they are referring to. Because there are often multiple approaches to solving the same problem, explaining why you are making a particular suggestion is more helpful to the developer as it gives them something concrete to work with. Alternatively, writing some pseudo-code can also give the author a clearer picture of the reviewer’s ideas and approach to the code.

Open-ended questions also are welcome, as they encourage discussion and reflection. While critique is essential for improvement, leaving positive feedback or highlighting that you learned something new is never a bad idea.

Code authors, on the other hand, must remember that the objective is to release the best possible code as a team for your users. It is not as much about any individual’s code or skill. At the end of the day, code reviews serve as teaching moments for everyone involved. As the owner or author of some code, it is a good idea, then, to not take feedback personally. Instead, take the comments seriously and respond to each of them, even if it is to seek clarifications regarding the feedback.

At the end of the day, code reviews are a collaborative effort and benefit from the author and reviewers communicating in a mindful and dedicated manner. Encouraging interactions between team members outside of code reviews can do wonders for them. It helps developers trust each other and learn how to better work with one another, which in turn contributes to improving the overall developer experience.

Consider pair programming

Pair programming is an effective alternative to a constant back-and-forth in the comments of a pull request. It makes it easier for the developers to share knowledge and arrive at a solution together, especially if the task at hand is particularly complicated or challenging. Not only can it be more efficient, but it also creates a more flexible and collaborative environment for developers to work together.

Track code review metrics

Have metrics around code reviews, such as review time and size. Don't fall into the trap of blocking pull requests on these metrics, but track them. If you are taking too long to do code reviews, it is worth discussing with the team during your retrospectives. Treat this exercise as a core part of your engineering process.

Examples of questions surrounding metrics include:

  • Are we doing reviews in a reasonable time? If not, why?
  • Where are our bottlenecks?
  • Are the pull requests too big?
  • Are the build times very slow?
  • How long does it take to find errors? Do we need better tests?

Knowing what to fix in your code review process is essential to doing the reviews regularly. To that end, discuss the process with the team frequently and tweak it where needed.

Prioritize coding standards

Reviewers may sometimes get hung up on tiny details that are not relevant to the larger objective of the review or feel strongly about doing something a certain way. In times like these, it is useful to bring one’s attention back to what matters and what the coding standards of the organization dictate. It is not advisable to stray away from these standards as they are essential to maintaining consistency.

Create a checklist

One way to streamline and standardize the code review process is by creating a code review checklist. With a checklist in hand, reviewers need not rack their brains trying to remember all the things they need to look out for and can instead focus on actually conducting the review. The checklist can be modified based on your business needs, but some standard criteria may include the legibility of the code, how secure it is, and the amount of test coverage.

Emphasize efficiency

Developers often shy away from code reviews because they can, admittedly, be time-consuming. Although comments and conversations are encouraged and conducive to knowledge sharing within the team, they take up significant time and energy that could otherwise be spent on writing other code. Without a balance, it is also easy for the code that is under review to block the development of other code that depends on it.

To avoid this, it is important to strike a balance between how thorough and quick the reviewer is expected to be. While catching bugs or functional errors is a no-brainer, they can be asked to spend less time on any styling concerns not covered by the team’s style guide if the reviews are taking longer than anticipated. As a reviewer, it can be tempting to nitpick and comment on each line of the code, but this is not necessary to ensure code quality and can slow you down considerably. The risks outweigh the benefits. Instead of aiming for perfection, focus on ensuring that the pull request does not do serious harm to the software and is a meaningful contribution to its development.

Automate where possible

Although there are undeniable benefits to a reviewer manually inspecting the code, there are some parts of the development process that can be automated to save time. You can, for example, use a static analysis tool to examine the source code before it is executed. This helps discover any bugs early in the process. The code that is passed on for code review eventually will then not be as riddled with bugs. This allows the reviewer to focus on issues that automated tools may not be able to pick up on, such as those of program logic.

Cortex has a range of tools that can come in handy. You can, for example, set and implement coding standards with Scorecards. Code reviewers need only look at the appropriate Scorecard to understand which criteria the code in front of them needs to meet to align with the rest of the software. The Scorecards can be made using data from custom resources and Cortex Query Language (CQL). CQL also facilitates the querying of data so that authors and reviewers alike can quickly find answers in your team’s documentation to any questions they have that are relevant to the review at hand.

What next?

Now that you know what makes a code review productive and successful, It’s time to put these practices to use. If you are overwhelmed by the list, remember to start small. Whether this means emphasizing the need to open small pull requests often and early or setting up the tools that will automate part of the process is up to you. Focus on what can be integrated into your team’s existing workflows without causing too many disruptions. At the same time, don’t let the team get too comfortable if you notice room for improvement.

The point is to do code reviews regularly and to do them well so that they can have a positive impact on the quality of your software.