DEV Community

Cover image for The Art of Code Review
Jatin Sharma for Documatic

Posted on

The Art of Code Review

As a developer, one of the most important skills is being able to write code that is clean, maintainable, and error-free. However, no matter how skilled you are, it's always possible that you may overlook certain bugs or issues in your code. This is where the code review process comes in.

If I have to put the code review process in simple words then, it is a process of having other team members review your code to check for bugs, improve the quality of your code and more. Code reviews are beneficial because they help to catch issues before they cause problems in production. It also allows other developers to learn from other people's code.

Table of Contents

In this article, we'll take a closer look at the code review process and how it can help you create better software.

Part 1: Basics of Code Review

Before we dive into the specifics of how to conduct a code review, let's clarify what a code review is. Code review is the process of inspecting code written by a developer to evaluate its quality. In the context of software development, it's typically used to catch bugs, evaluate design decisions, and ensure that the code is maintainable. Code review is generally considered a best practice in software development because it helps you catch issues before they become bigger problems.

There are various types of code reviews, but the most common approach is to have a team member review the code. This can be done in various ways, by either using pair programming or through the use of code review tools that allow developers to share and review code online. Some people also ask for an outside expert, such as a consultant. Doesn't matter which approach we use, the main objectives of code review are to increase the accuracy, readability, and maintainability of the code.

Part 2: Benefits of Code Review

Now you have an idea of what code review is. So why is code review important? Let's take a look at some of the key benefits:

Bug Detection and Prevention

Code review helps in identifying bugs and potential errors in the code before they make their way into production. By catching these issues early on, code review prevents bugs from affecting end-users and saves time and effort that would otherwise be spent on debugging.

Before Code Review:

def find_largest_word(str):
  words = str.split()
  largestWord = ""

  for word in words:
    if len(largestWord) < len(word):
      largestWord = word

  return largestWord
Enter fullscreen mode Exit fullscreen mode

In this example, the find_largest_word function appears to be working fine, but it doesn't remove any non-letter characters from the input string before operating on it. This could introduce errors if non-letter characters are present.

After Code Review:

import re

def find_largest_word(str):
  words = re.findall(r'\b[A-Za-z]+\b', str)
  largestWord = ""

  for word in words:
    if len(largestWord) < len(word):
      largestWord = word

  return largestWord
Enter fullscreen mode Exit fullscreen mode

After a code review, the reviewer suggests adding code to remove any non-letter characters from the input string before proceeding. The developer then implemented this suggestion using the re module to find all words consisting of only letters. Specifically, the re.findall() function searches for all substrings of the input string that contain only letters using a regular expression. This fix eliminates the risk of incorrectly identifying a non-letter character as part of the largest word, leading to incorrect output.

Improved Code Quality

Code review promotes high-quality code by enforcing best practices and coding standards. It allows developers to spot code smells, improve readability, simplify complex logic, and ensure code is maintainable and scalable.

Before Code Review

def count_vowels(word):
    vowels=0
    for letter in word:
        if letter in 'aeiou':
        vowels+=1
    return vowels

word = input("Enter a word:")
result = count_vowels(word)
print("Number of vowels in the word are:",result)
Enter fullscreen mode Exit fullscreen mode

This code is attempting to count the number of vowels in a word provided by the user. However, there are a few issues that can be addressed through a code review:

  • The indentation of the vowels+=1 line is incorrect and will result in a syntax error

  • Variable naming is not consistent (word vs vowels)

  • Having user input inside of the function means that the function is less reusable

After Code Review

def count_vowels(word):
    vowels = 'aeiou'
    return len([letter for letter in word.lower() if letter in vowels])

word = input("Enter a word: ")
result = count_vowels(word)
print("Number of vowels in the word are:", result)
Enter fullscreen mode Exit fullscreen mode

After a code review, the following changes were made:

  • Indentation is corrected

  • Variable naming as well as function name is more consistent and descriptive

  • User input is moved outside of the function to make the function more reusable

  • Using list comprehensions the number of vowels are counted and returned

These improvements make the code more readable, reusable, maintainable and efficient.

Knowledge Sharing and Learning

Code review is an excellent opportunity for knowledge sharing among team members. Reviewers can provide feedback, suggest alternative solutions, and share their expertise, which helps in spreading knowledge and improving the skills of all team members.

Before Code Review

def find_duplicate_elements(lst):
    """
    Finds and returns a list of duplicate elements in the given list.
    """
    duplicates = []
    for i in range(len(lst)):
        for j in range(i + 1, len(lst)):
            if lst[i] == lst[j] and lst[i] not in duplicates:
                duplicates.append(lst[i])
    return duplicates
Enter fullscreen mode Exit fullscreen mode

In above example, the code reviewer identifies the need for optimization and suggests using the collections.Counter class to find duplicate elements in the list more efficiently. The reviewer explains the benefits of this approach, such as improved readability and reduced complexity.

After Code Review

from collections import Counter

def find_duplicate_elements_optimized(lst):
    """
    Finds and returns a list of duplicate elements in the given list using collections.Counter.
    """
    element_counts = Counter(lst)
    duplicates = [element for element, count in element_counts.items() if count > 1]
    return duplicates
Enter fullscreen mode Exit fullscreen mode

The code author takes the feedback and provides an updated implementation using collections.Counter. The updated code simplifies the logic by leveraging the built-in functionality, resulting in a more efficient and concise solution.

Through this code review process, knowledge is shared regarding the efficient use of built-in Python functionalities, and team members learn about alternative approaches to solving similar problems.

Collaborate with others

Collaborating with others in a code review is essential for ensuring that the code is of high quality and meets the requirements of the project. In this process, code reviewers provide constructive feedback to the code author, and together, they work towards improving the code.

Before Code Review

def sum_even_numbers(numbers):
    """
    This function takes a list of integers and returns the sum of all even numbers in the list.

    Args:
        numbers (list): A list of integers.

    Returns:
        int: The sum of all even numbers in the input list.
    """
    even_numbers = []
    for number in numbers:
        if number % 2 == 0:
            even_numbers.append(number)
    return sum(even_numbers)
Enter fullscreen mode Exit fullscreen mode

After Code Review

def sum_even_numbers(numbers):
    """
    This function takes a list of integers and returns the sum of all even numbers in the list.

    Args:
        numbers (list): A list of integers.

    Returns:
        int: The sum of all even numbers in the input list.
    """
    even_numbers = [n for n in numbers if n % 2 == 0]
    return sum(even_numbers)
Enter fullscreen mode Exit fullscreen mode

In the above example, the initial implementation of sum_even_numbers() function works correctly, but it is not written in the most pythonic way. In the code review, the reviewer suggested using a list comprehension to simplify the implementation. By working collaboratively, the reviewer and author were able to improve the function to be more efficient and readable.

Part 3: The Code Review Checklist

The Code Review Checklist is a set of guidelines and best practices that software developers follow when reviewing and evaluating code written by their peers. It helps ensure that the code is of high quality, maintainable, and adheres to industry standards. The checklist typically includes various aspects such as code correctness, efficiency, readability and maintainability.

Functionality

In terms of functionality, the code should meet all the requirements and perform as expected. The code should handle errors and edge cases gracefully. Here's an example of Python code that performs file input and output, while handling any errors that may arise:

try:
    with open("inputfile.txt", "r") as f:
        lines = f.readlines()

    with open("outputfile.txt", "w") as f:
        for line in lines:
            f.write(line.strip().upper())

except FileNotFoundError:
    print("Input file not found")
except:
    print("Error occurred")
Enter fullscreen mode Exit fullscreen mode

Clarity

The code should be easy to read, understand and maintain by other developers. Variable names should be clear and concise, and indentation should be used to improve readability. Here's an example of Python code that demonstrates clarity:

def calculate_total_price(price, quantity, tax_rate):
    """Calculate total price including tax"""

    total_price = (price * quantity) * (1 + tax_rate)

    return total_price
Enter fullscreen mode Exit fullscreen mode

Structure

The code should be well-organized and structured. Functions should have a single responsibility, and the overall architecture should be easy to follow. Here's an example of Python code that demonstrates good structure:

def process_data(data):
    """Process data and return results"""

    filtered_data = filter_data(data)
    transformed_data = transform_data(filtered_data)
    results = analyze_data(transformed_data)

    return results
Enter fullscreen mode Exit fullscreen mode

Maintainability

Review the code for maintainability. It should be easy to modify, test and debug. Also, ensure that the code follows coding standards and naming conventions. Here's an example of Python code that demonstrates good maintainability:

class Calculator:
    def __init__(self):
        self.result = 0

    def add(self, num):
        self.result += num
        return self.result

    def subtract(self, num):
        self.result -= num
        return self.result
Enter fullscreen mode Exit fullscreen mode

Performance

Evaluate the performance of the code. It should perform well, and all resource utilization should be optimized. Here's an example of Python code that demonstrates good performance:

import time

start = time.time()

# code to be timed

end = time.time()

print("Time elapsed:", end - start, "seconds")
Enter fullscreen mode Exit fullscreen mode

Security

Ensure that the code is secure and free from vulnerabilities. Input validation should be used to prevent injection attacks, and sensitive data should be encrypted. Here's an example of Python code that uses input validation:

import re

def validate_email(email):
    """Validate email using regular expressions"""

    pattern = r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"

    if re.match(pattern, email):
        return True
    else:
        return False
Enter fullscreen mode Exit fullscreen mode

Documentation

Review the code documentation. It should be clear, concise, and up-to-date. Documented code makes it easier to understand and maintain. Here's an example of Python code that demonstrates good documentation:

def fibonacci_sequence(n):
    """Generate the fibonacci sequence up to n"""

    # check for invalid input
    if n < 1:
        return []

    # initialize sequence
    sequence = [0, 1]

    # generate sequence
    while sequence[-1] + sequence[-2] <= n:
        sequence.append(sequence[-1] + sequence[-2])

    return sequence
Enter fullscreen mode Exit fullscreen mode

Testing

The code should be adequately tested, and all test cases should pass. Unit testing should be used to ensure that the code functions as expected. Here's an example of Python code that demonstrates good testing:

import unittest

class TestCalculator(unittest.TestCase):

    def setUp(self):
        self.calculator = Calculator()

    def test_add(self):
        result = self.calculator.add(2)
        self.assertEqual(result, 2)

    def test_subtract(self):
        result = self.calculator.subtract(2)
        self.assertEqual(result, -2)

if __name__ == '__main__':
    unittest.main()
Enter fullscreen mode Exit fullscreen mode

By using this code review checklist and the detailed Python code examples above, you can assess the quality of code and ensure that all important aspects are covered. The checklist is not limited, it will depend on your organization.

Part 4: Tips for Conducting Code Reviews

Following are a few tips that will give you some insight into how it will work:

Certainly! Here's an example for each section of the code review process:

Understand the context

Familiarize yourself with the purpose and requirements of the code being reviewed. Understand the expected functionality and any relevant design considerations.

Read the code thoroughly

Take your time to read the code carefully, paying attention to the logic, data flow, and error handling. Understand how different components and modules interact with each other.

def calculate_average(numbers):
    total = sum(numbers)
    count = len(numbers)
    average = total / count
    return average
Enter fullscreen mode Exit fullscreen mode

Analysis: The code reads a list of numbers, calculates the sum and count, and then computes the average. It appears straightforward and readable.

Follow style guidelines

Check if the code follows the organization's style guidelines or a widely accepted Python style guide (e.g., PEP 8). Consistent and readable code is easier to maintain.

def calculate_average(numbers):
    total = sum(numbers)
    count = len(numbers)
    average = total / count
    return average
Enter fullscreen mode Exit fullscreen mode

Analysis: The code follows the PEP 8 guidelines with clear and readable naming conventions, consistent indentation, and appropriate use of whitespace.

Identify potential bugs

def calculate_average(numbers):
    total = sum(numbers)
    count = len(numbers)
    average = total / count
    return average
Enter fullscreen mode Exit fullscreen mode

Analysis: The code doesn't account for the case when the numbers list is empty, which could lead to a ZeroDivisionError. A check for an empty list should be added. You can simply catch that by using try...except block.

Verify input validation and error handling

Check if the code adequately validates user inputs and handles potential errors, exceptions, or edge cases. Look for proper handling of exceptions, resource cleanup, and appropriate error messages.

def calculate_average(numbers):
    if not numbers:
        raise ValueError("The input list is empty.")
    total = sum(numbers)
    count = len(numbers)
    average = total / count
    return average
Enter fullscreen mode Exit fullscreen mode

Analysis: The code now includes a check for an empty list and raises a ValueError with a helpful error message when encountered.

Review performance considerations:

Evaluate the code for any performance bottlenecks, such as inefficient algorithms, excessive database queries, or excessive memory usage. Suggest optimizations where applicable.

def calculate_average(numbers):
    total = 0
    for num in numbers:
        total += num
    average = total / len(numbers)
    return average
Enter fullscreen mode Exit fullscreen mode

Analysis: The code originally used the sum() function to calculate the total, but it can be optimized by directly summing the numbers in a loop.

Ensure proper documentation:

Review the code's comments and documentation to ensure clarity and accuracy. Code should be self-explanatory, but additional comments can help explain complex logic or assumptions.

def calculate_average(numbers):
    """
    Calculates the average of a list of numbers.

    Args:
        numbers (list): A list of numbers.

    Returns:
        float: The average of the input numbers.
    """
    total = sum(numbers)
    count = len(numbers)
    average = total / count
    return average
Enter fullscreen mode Exit fullscreen mode

Analysis: The code now includes a docstring that explains the purpose of the function, describes the input and output, and provides a clear usage example.

Provide constructive feedback

Focus on providing actionable feedback that helps the developer improve the code. When providing feedback, be specific and provide concrete examples. This will make it easier for the developer to understand what changes need to be made.

By following these examples, you can conduct a comprehensive code review while providing constructive feedback to improve the code's quality and maintainability.

Automated vs Manual Code Review

Automated and manual code reviews are two methods of reviewing code during the software development process. Each method has its advantages and can complement each other.

Automated Code Review

Automated code review involves using specialized tools to scan source code for potential issues. Automated code review tools can catch issues such as syntax errors, memory leaks, and security vulnerabilities. These tools often use static code analysis, which involves analyzing the code without executing it. Automated code review tools can be integrated into the continuous integration/continuous deployment (CI/CD) process, allowing issues to be caught and addressed early in the development cycle.

Benefits of Automated Code Review

  • Faster than manual review.

  • Consistently applies best practices.

  • Able to scan a larger percentage of all code changes.

  • Can catch simple issues like syntax errors, inefficiency, and security vulnerabilities.

Manual Code Review

Manual code review involves human review and analysis of the code. Manual code review can identify issues that automated code review tools may miss, including design issues, performance problems, and inconsistencies in style and readability. Manual review is likely to improve the understanding and collaboration between the development team.

Benefits of Manual Code Review

  • Can catch complex issues that automated tools can't.

  • Implements critical and creative thinking in the code review process.

  • A detailed review can identify issues with design, maintainability and scalability.

  • The personal touch of manual code review creates awareness of anti-patterns and best practices etc.

Comparison

Automated Code Review Manual Code Review
Consistent application of best practices Critical and creative thinking in the review process
Faster iteration times Ability to catch complex issues
Scans a larger percentage of code changes Better performance reviews
Can catch simple issues like syntax errors Understanding, collaboration and communication between team
Able to consistently apply set rules Ability to identify, anti-patterns and best practice guidelines
Increases efficiency and productivity of the development team Creates awareness of project targets and unit tests

Which method is better?

Automated and manual code reviews both have their strengths and weaknesses. While automated code review is quicker and more consistent, manual review is more thorough and can catch more complex issues. That being said, the best approach is to use them both together. Automated code review tools can catch simple errors and free up team resources, while manual code review can focus on more complex issues and provide more detailed feedback. Both methods, when used together, can improve code quality and ensure that software is secure, efficient, and reliable.

Wrapping up

In conclusion, a well-executed code review process is a crucial aspect of software development. Through this process, developers can collaborate more effectively, catch bugs sooner, and maintain a high level of code quality. By incorporating best practices such as checklists, clear feedback, and consistent standards, teams can ensure that their software is reliable, efficient, and easy to maintain. Additionally, implementing automated code review tools can help streamline the process and provide a second layer of quality assurance. While the code review process may take time and effort, the benefits in terms of better software, more productive teams, and satisfied customers are well worth it.

If you want more explanation on similar topics just let me know in the comments section. And don't forget to ❤️ the article. I'll see you in the next one. In the meantime you can follow me here:

Namaste

Top comments (7)

Collapse
 
sloan profile image
Sloan the DEV Moderator

Hey, this article seems like it may have been generated with the assistance of ChatGPT.

We allow our community members to use AI assistance when writing articles as long as they abide by our guidelines. Could you review the guidelines and edit your post to add a disclaimer?

Collapse
 
jacob1507 profile image
Jacob • Edited

IMO adding docstrings that have similar info to function names is poor decision.
For example

AvgNumber = float


def calculate_average_of_numbers(numbers: list[int]) -> AvgNumber:
    total = sum(numbers)
    count = len(numbers)
    average = total / count
    return average

Enter fullscreen mode Exit fullscreen mode

is more readable in code base than:

def calculate_average(numbers):
    """
    Calculates the average of a list of numbers.

    Args:
        numbers (list): A list of numbers.

    Returns:
        float: The average of the input numbers.
    """
    total = sum(numbers)
    count = len(numbers)
    average = total / count
    return average
Enter fullscreen mode Exit fullscreen mode

Maybe I am just nitpicking stuff, but adding long vertical docstrings that give same information that could be provided by better planning your function names and typing is kinda lazy. At the end of the day it is better than nothing i guess :D

Collapse
 
alvarolorentedev profile image
Alvaro • Edited

Nice & clean written article 🙂.
I want to say, code reviews, are a generally overused in practice, and that shows on the amount of articles I have seen around it lately.
Personally I must disagree on this being a good practice and the value expresed in this post. As humans we are unable to detect bugs, performance and security issues, specially with a low context of a peer reviewer that has not worked on it. Our brain is not an execution engine, is an simulation engine, meaning is not factual.
Its also important to notice that code reviews as explained here relate to an async process, so a lot of waste has been already generated as the feedback is generated at the end of the development cicle and provided as a whole, again without the capability to demonstrate if that feedback is actually factual.
Peer reviews are good but there are other methods that provide a better return on investment, like pair programming. Async code reviews, alias pull requests, where only created for zero trust environments (OSS), and highly distributed teams.
By experience, please dont PR if you dont need to, find a more efective peer review process.

Collapse
 
knitevision1 profile image
Vlad Shulha

The begining of the article mentions checking buga. Code Reviews checking for bugs is a bit questionable. Certainly, a reviewer can pinpoint a flaw in logics, but catching bugs in a true sense is only possible when the code executes. And a reviewer shouldn't really run the code.

Collapse
 
alais29dev profile image
Alfonsina Lizardo

nice article, I actually tried implementing code review with my team recently and it has helped us catch some bugs and readability issues, it has also helped the junior dev on my team on learning some good practices, it has been a nice experience that I wish could have had as a junior developer.

Collapse
 
llorx profile image
Jorge Fuentes

I prefer the first vowels example over the reviwed one (apart from the indentation bug). Looooong one-liners are a red flag that reduces readability.

Collapse
 
adeojo9 profile image
Oluwaseun Adeojo

Very informative. I learned a lot!