Completing a Code Review
Code reviews are more than just checking for bugs or syntax errors — they are a collaborative process aimed at improving code quality, ensuring readability, and sharing knowledge across the team. Code reviews can be conducted using popular source control systems like GitLab, GitHub, or Bitbucket, making it easy to comment on specific lines, suggest improvements, and track changes over time.
Why Are Code Reviews Important?
Code reviews are an essential part of the development process because they help prevent critical issues from reaching production, improve code quality, and facilitate knowledge sharing within the team. Without code reviews, it’s easy for bugs, bad practices, and security vulnerabilities to slip through unnoticed. A good code review process also helps standardize coding practices across the team, making the codebase easier to maintain and extend.
Bad Case Example: Imagine a developer pushes a new feature without any review. The feature code has a bug that results in incorrect calculation of user balances. This issue goes unnoticed until customers start reporting discrepancies in their accounts, causing major customer dissatisfaction and damage to the company’s reputation. A simple code review could have caught the issue early, ensuring that the calculation logic was correct and properly tested before being deployed.
In this blog post, we’ll explore how to complete an effective code review, with practical examples to highlight what to look for at each step.
1. Understand the Context
Before diving into the code, it’s crucial to understand the purpose of the changes. Ask yourself questions like: What problem is this code trying to solve? What feature does it enhance? Reviewing code without this context can lead to misinterpretations.
Example: If a developer is refactoring a function to improve performance, the goal isn’t just a different implementation — it’s specifically a faster one. Focus on checking the efficiency of the new implementation.
2. Check for Readability
Code readability is often more important than clever optimizations. Ensure that the code is easy to follow and that variable and function names are meaningful. Consider whether another team member could easily understand what’s happening without extra explanation.
Example:
Before:
var r = Calculate(p, q);
After:
var revenue = CalculateRevenue(productPrice, quantitySold);
Notice how the more descriptive names make the purpose of the calculation obvious at a glance.
3. Ensure Adherence to Guidelines
Check that the code follows the team’s established style guidelines. Consistency in naming conventions, formatting, and error handling helps maintain code quality. For C# developers, this means ensuring naming conventions like PascalCase for methods or camelCase for local variables are followed.
Example: In C#, private instance fields should start with an underscore, such as
_totalAmount
. This ensures consistency across the team and avoids confusion.
4. Check Against Company Guidelines
Every company should have a set of technical guidelines and coding standards that developers are expected to follow. These guidelines help maintain consistency, readability, and security throughout the codebase. During a code review, ensure that the submitted code adheres to these standards.
Example: Make sure the code follows naming conventions, proper error handling, and other rules set by your team or company.
5. Look for Edge Cases
Another crucial part of a code review is to consider how the code handles different inputs, especially edge cases. Does it account for null values? Does it prevent unexpected behavior when unusual data is passed?
Example:
public void ProcessOrder(Order order)
{
if (order == null)
{
throw new ArgumentNullException(nameof(order), "Order cannot be null");
}
// Process the order...
}
Here, the null check ensures that the method won’t throw a NullReferenceException when it’s called with a null value.
6. Evaluate Logic and Maintainability
Make sure that the code logic is correct and easy to maintain. This means watching for overly complex methods that try to do too much. Suggest breaking these into smaller, focused methods when possible.
Example: If you encounter a method called
ProcessAndValidateOrderAndSendNotifications
, it’s a good candidate for splitting into distinct methods likeProcessOrder
,ValidateOrder
, andSendNotifications
.
7. Dive Deep When Necessary
Sometimes, code changes involve complex logic or critical parts of the system. In these cases, it’s important to dive deep into the logic to ensure correctness. However, not every review requires this level of scrutiny — focus on deep dives when the task involves critical functionality, complex algorithms, or areas that could significantly impact the system if incorrect.
Example: For a new algorithm implementation that handles payments, ensure you understand the full logic and all possible scenarios. This could involve stepping through the code and asking clarifying questions to ensure the expected behavior is met.
8. Provide Constructive Feedback
While it’s important to point out issues, it’s equally crucial to keep feedback constructive. Aim for a collaborative tone, suggesting alternatives and acknowledging positive aspects.
Example:
Good Feedback: “I like how you handled the input validation here. One suggestion: consider extracting this validation into a helper function to make the main method more readable.”
Avoid: “This code is confusing. Fix it.”
9. Collaborate with the Developer
Code reviews are most effective when they’re collaborative. Engage with the developer to discuss their approach, understand their perspective, and offer guidance rather than just criticism. Good standards for discussing the code include being respectful, assuming positive intent, and being open to different solutions.
Best Practices for Collaboration:
Ask Questions: Instead of saying “This is wrong,” ask “Can you help me understand why you chose this approach?” This opens up a dialogue and can lead to better solutions.
Suggest Improvements: Frame suggestions as improvements rather than mandates. For example, “What do you think about using a different approach here for better readability?”
Acknowledge Good Work: Recognize when parts of the code are well-written. Positive reinforcement encourages good practices.
Avoid Nitpicking: Focus on meaningful changes that improve the quality of the code rather than personal preferences for formatting or style that don’t affect functionality.
10. Use Automated Tools Where Possible
Static analysis tools like SonarQube or Resharper can automate part of the review, catching common issues like unused variables or potential null dereferences. These tools can save time, allowing reviewers to focus on deeper aspects of the code, like logic and readability.
Examples of Useful Tools:
SonarQube: Great for identifying code smells, vulnerabilities, and maintaining code quality.
Resharper: Helps with refactoring, error detection, and code analysis.
CodeScene: Provides visual insights into code complexity and potential areas of improvement.
GitHub Actions: Automates parts of code testing and ensures consistency with CI/CD.
11. Consider Security (OWASP Top 10)
Security should always be a consideration during a code review. Make sure the code avoids common security pitfalls, such as SQL injection, cross-site scripting (XSS), or improper authentication. Familiarize yourself with the OWASP Top 10 security risks and check if the code follows secure coding practices.
Example: Ensure that user input is properly sanitized to prevent injection attacks or that sensitive data is not exposed in error messages.
12. Testing and Coverage
Make sure that the code has appropriate test coverage. Tests should cover both the typical cases and the edge cases. This will prevent future regressions and ensure that the new code works as intended.
Example: If a new method has been added, confirm that there is at least one unit test validating its functionality, along with tests for any failure scenarios.
Tools for Testing:
NUnit/xUnit: Widely used testing frameworks for unit testing in C#.
Moq/NSubstitute: Tools for creating mocks during testing.
Postman: Useful for testing APIs and checking request/response behaviors.
13. Use Diagrams When Needed
When reviewing complex code or architecture changes, using diagrams can be very helpful. Sequence diagrams, flowcharts, and architecture diagrams can provide a high-level overview and make it easier to understand intricate parts of the system.
Example: If the code involves multiple services communicating with each other, a sequence diagram can help visualize the flow of data and identify potential bottlenecks or logical errors.
Tools for Diagrams:
Lucidchart: Great for creating flowcharts, architecture diagrams, and more.
PlantUML: A text-based tool for generating UML diagrams.
Draw.io: An easy-to-use, open-source diagramming tool that integrates well with various platforms.
Also who said that cheapest Wacom can’t be used by developers ;) Very useful hardware for diagraming and thinking, while using your screen as a piece of paper.
14. Balance Between Perfection and Progress
Not all code needs to be perfect, especially if the feature needs to be released under tight deadlines. It’s important to balance quality improvements with getting things done. If you see an improvement that can be made but isn’t critical, you might flag it as a “Nice to Have” instead of blocking the merge.
15. Summary and Approval
Once you’ve reviewed everything, summarize your feedback. If the changes are minor, approve the code with comments. If there are significant changes needed, request modifications and set up a follow-up review.
Example Summary:
“The code looks solid overall. Great use of descriptive variable names and the new feature seems well implemented. I’ve added a few comments about refactoring a couple of functions to improve readability. Let me know if you need help with any of these suggestions!”
References and Further Reading
To further enhance your understanding of code reviews and best practices, consider exploring the following resources:
Books:
- Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin
- Code Complete: A Practical Handbook of Software Construction by Steve McConnell
- The Pragmatic Programmer: Your Journey to Mastery by Andrew Hunt and David Thomas
Blogs and Articles:
- How to Do Code Reviews Like a Human by Michael Lynch
- Code Review Best Practices by Google Engineering Practices
Final Thoughts
Code reviews are about fostering collaboration and shared understanding in the team. They help ensure quality while also serving as a platform for learning. The best code reviews strike a balance between being thorough and being supportive, helping the team grow together.