How to set up efficient Code Reviews and improve your team's codebase
Israel Heringer
Posted on November 22, 2023
Introduction
As software systems become more complex and integrated into all aspects of modern life, it is critical to ensure their maintainability, security, and efficiency. Code review is a very efficient process to achieve this higher quality code standard. Similar to peer review in academic writing, it entails a thorough examination of the source code by one or more developers who did not create the original code. Its primary goal is to detect, early in the development cycle, bugs and vulnerabilities such as security or privacy, reducing the risk of affecting the software users, as well as the cost and effort required to fix them later.
It is also beneficial for the team to develop consistent coding practices, which aid in the software's maintainability and scalability. As a nice bonus, code reviews also contribute to spreading knowledge through the team and serve as a good opportunity for developers to learn with each other when analysing different approaches in the code.
However, establishing a code review process is many times a challenging process, and can have a significant impact on a project's eventual success. In this article, we'll go over the key steps to take to ensure that the code review process helps meet all of its objectives.
Part 1. What to do before introducing Code Review
To ensure the success of the code review process, we must first see the big picture: Understanding our team, with its codebase and goals is critical for establishing streamlined processes.
Understand the team
To set up efficient code review processes, we must first understand who are the developers on our team:
What’s the level of seniority? A team full of senior engineers will definitely require a different review process than a team where most of the engineers are in the beginning of their careers.
How many engineers are familiar with the specific parts of the codebase that are being changed? A small startup, for example, may only have a couple of engineers who know the entire codebase, whereas a larger organisation may have multiple teams with specialised knowledge.
Identify whether the team works independently or collaboratively. Remote teams may rely more on asynchronous communication, whereas co-located teams interact more face to face. Setting up a synchronous review process, then, is more likely to work for co-located teams. Asynchronous code reviews, on the other hand, usually work well for both scenarios.
If the team is distributed globally, consider how different time zones may affect the review process and turnaround times.
Focus on the core problems
Finding the primary issues that the code review is meant to address shapes the entire process and ensures its success. For example:
If the goal is to improve code quality, focus the review on identifying errors, improving readability, and ensuring best practices.
When there is a concern about a lack of testing, make sure that reviews check test code coverage and emphasise the quality of the test cases for any new features or bug fixes.
When the team (or some members of it) or project is new, it may be a good idea to concentrate reviews on how aligned is the new code with the established patterns and architectural standards.
If the goal is to minimise side effects when launching the change, the process should include a more in-depth code analysis and request stronger testing evidence, especially in complex systems.
New code vs legacy code
Dealing with legacy codebases presents a number of challenges, such as the lack of coding standards and the many "hacky" solutions implemented under previous constraints or objectives. A cautious approach is necessary to ensure that new changes do not disrupt the legacy system's functionality and introduce new issues. In such scenarios, abruptly adopting strict code practices and trying to enforce them through code review will not work. Instead, we should aim for small improvements on each change, and slowly bring the codebase to a better state. Let’s say, for example, there’s no automated test. Instead of creating a whole suite of tests, we could start by testing particular functions that are being updated or introduced, maybe with some small refactoring, and then, even if with only small steps each time, the codebase will get progressively better.
A new codebase, on the other hand, provides the opportunity to establish and enforce well-defined coding standards and architectural guidelines from the start, and the code review process is the key to making this work. This initial setup is critical because it establishes the precedent for future software development and maintenance.
Code Reviews and time management
Time is frequently a big constraint in software development. I don't think I've ever worked on a project where time wasn't an issue, at least in part. Under time constraints, it's critical to strike a good balance in the code review process to avoid either of the two common extremes:
- Code review becomes a mere formality, with new pull requests approved almost without review, just to complete the process.
- Code review process fails to take into account project constraints, slowing down team progress rather than helping to optimise team output.
One very useful approach is to make code review an intentional part of the developer's daily tasks. Rather than viewing code reviews as an afterthought or a task to be squeezed in at the end of the day, dedicating time slots throughout the day or week makes it easier to balance both time and quality of code review. Different teams will have different answers for when and how long these code review time blocks should be, but these two principles should help in the decision:
Be realistic: if we can't find 1 hour for code review in a week, blocking 40 minutes every day is unlikely to work. However, two 30-minute sessions may work.
Avoid lengthy review sessions: Reviewing code is a demanding cognitive activity, and we naturally become tired after a while. It is far more efficient to have two or three code reviewing sessions of 15-20 minutes each than one single session of 45-60 minutes, lowering the risk of missing critical details.
Writing code for other engineers
One interesting fact about source code is that it is much more likely to be read multiple times than it is to be written or rewritten multiple times. Engineers debugging a problem, auditing system behaviour, reviewing the design for new features, and so on will read it. Even ourselves, when revisiting the code after a few years, will read it almost as if for the first time as memory fades.
But why is this reflection relevant for code reviews? When we write code with readers in mind (even if it's our future selves), we're more likely to write cleaner, easier-to-digest code. This mindset will also make reviewing the code much easier because it will result in cleaner code.
Before we move on to the next section, it's important to mention one final strategy that has a significant impact on code reviewing practice: smaller pull requests. It's much easier to read, review, and provide feedback on a change that affects 20 lines of code than it is to read, review, and provide feedback on a change that affects 200 lines of code. When each pull request contains small and independent changes, cognitive load is significantly reduced, allowing reviewers to delve deeper into each of the specific changes. Furthermore, the changes appear less intimidating, and we end up with higher engagement than with large pull requests.
Part 2: How to improve the Code Review process
Start small, grow with time
Implementing a code review process in the team should be an iterative process. It’s better to start with something (and improve it) than to spend too much effort attempting to create a ‘perfect’ process, only to find out later that the process doesn’t reflect the team's needs or doesn’t adhere to reality. If the team is finding it hard to know how to begin, here are some ideas that could be used to to begin with:
- Start the process for only specific projects or subsets of the code base (such as those that are critical to the project), and gradually expand the scope of review.
- Start by sampling pull requests instead of reviewing all of them. Then, as the team becomes more accustomed to the process, gradually incorporate more.
- Start with non-mandatory or non-blocking pull requests. Maybe even reviewing only on demand, by request from the author of the pull request.
Automate what we can
We don’t want to waste hours of engineers reviewing, for example, if the correct code format was applied, or if the indentation (for languages that indentation is not an inherent part of) is using spaces or tabs. There are many tools that we can use to perform automated checks on formatting, syntax, and other common issues. It’s actually very easy to set up code linters like SonarQube and ESLint, , two tools that examine the source code to detect bugs, code smells, and security vulnerabilities. They can even be integrated to the CI pipelines to give automated feedback to the code author before the change is made available for review.. With smart automation strategies, human review efforts can focus on complex aspects such as business logic, code/architectural patterns, privacy or performance.
Encourage open discussion
When we make the review process collaborative, everyone feels empowered to influence the process and the result is more likely to be a well-adapted practice that fits the needs of the team and is well adopted by the team members. We should then engage with the team on a regular basis to gather feedback on the review process, whether through team meetings, surveys, or informal discussions.
As we mentioned before, it’s important to adjust the pace based on the team's level of comfort and maturity. If necessary, it’s ok to slow down the process’ adoption to incorporate feedback, and then speed it up when things are going well.
Lastly, it’s important to remember that code review should not be seen as a finger-pointing process, but rather an opportunity for learning and knowledge sharing. A good code review process should encourage team members to share their code and different perspectives, fostering a collaborative learning environment.
Avoid the gatekeeper
In order to meet the team goals, we must ensure the team is ready to contribute in code reviews. However, this may be challenging in teams where one or two developers have a more centralised role. Here are some pointers for an effective team-wide code review process:
- Avoid focusing on a single engineer or a small subset of the team for code reviews. When only a few people are in charge of reviews, it can slow down progress, create bottlenecks, and cause problems if these key reviewers are unavailable.
- Any team member should take part in the review. This not only spreads the workload, but also improves the team's overall understanding of the codebase. Actually, code reviewing is a very good opportunity for new members to onboard in the team’s codebase, coding practices and overall process.
Having said that, we must acknowledge that sometimes expert input will be required. It could be because the change affects a very sensitive part of the system or offers a bigger risk in case of failures. In such scenarios, it’s perfectly fine (and even recommended) to request a specialist review, as they can provide the necessary depth of analysis to de-risk that change.
Evaluate results and recognise contributors
Lastly, it’s very important to recognise those who effectively contribute to the team through code reviews:
- Appreciate team members who are proactive in reviewing and providing timely feedback, thereby keeping the project moving.
- Value contributions from team members who use the review process as an opportunity to teach better coding practices, raise the team’s code quality bar and to guide less experienced colleagues.
- Recognise the efforts of those who are skilled at identifying gaps in business logic or potential improvements, as their insights are critical to the project's overall quality.
- Encourage developers who are more on the “learning” side and acknowledge how they are improving over time.
Conclusion
Code review is a development cycle component that is very important in today's competitive digital industry. We scrutinised some steps involved in preparing and conducting streamlined code reviews, as well as how to keep it as lightweight as possible.
A good code review process should be collaborative, efficient, and able to recognise the contributions of all team members by following the guidelines outlined in this article. Code review not only improves code quality, but it also fosters a positive and inclusive team culture.
Posted on November 22, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.