How to Do a Good Code Review?
By: Rafiullah Hamedy
Tags: Programming, Java, JavaScript, Software Development, Technology

As a code reviewer, you have the power to approve any code, and along with that comes the responsibility to make sure that the code is in good condition. In this article, we will go through a listing of questions and points that could help code reviewers focus on what matters during a code review.

Credit: Ebenezar John Paul

If you are reading this article, you might find the following article helpful

Here are some of the questions that you can ask yourself when reviewing a changelist (pull request)

Design related aspects of code under review

Is the code well-designed? Does the code demonstrate low coupling and high cohesion? Should the code be moved elsewhere? Does the code interact well with the existing code and features? Functionality-wise, does the code do what the developer intends to do? Is the code written well-enough for both end-users and future developers to maintain and extend upon? Is the code too generic and over-engineered? Are there any edge cases, i.e., concurrency, deadlocks, or race conditions? Is the code relating to the web layer, business logic, and database in their appropriate layers? For backend development, do the endpoints return Data Transfer Objects (DTOs) or the business model (Entity)?

Carefully review any dependency changes in code

I do not suggest that you re-invent the wheel and avoid dependencies all-together however, I do strongly recommend that you think twice before adding a dependency to your codebase.

The future of open source projects is not in our hands, and their trajectory could affect products that rely on them.

For example, if a dependency is not maintained anymore and there are security or other types of vulnerabilities then you are stuck with it. Depending on the dependency, a majority of times it is really complex to remove or replace a dependency from a production system without affecting the users.

Another example, the more the dependencies the higher the maintenance of the product and this is because upgrading dependencies is a bumpy ride and depend on quite a few factors

How outdated the dependencies are?

Are there any breaking changes in dependency versions?

Are there official migration guides?

Is the dependency being forked to accommodate the product’s custom needs?

All of the above decides how complex, and expensive the upgrade process is going to be and how would it affect your customer base.

Develop an approval process for new dependency requests and define which team will own the dependency and maintan it regularly.

Here are some of the questions you can ask yourself as a code reviewer

Can the addition of the new dependency be justified? What are the pros and cons of these new dependencies? What other transitive dependencies are being pulled via this new dependency, and will there be any conflicts with existing dependencies? When upgrading/dropping an existing dependency, are we confident there will be no runtime exceptions directly from code or indirectly? Is the project active and maintained? How many open issues are there? What is the test/code coverage? How many active contributors are there? How old is the project, and are there any alternatives?

Avoid forking and changing libraries at all cost

Forking and changing an open-source library should never be an option, and that’s because it is too expensive to keep the forked version of the library in sync with the original.

The biggest challenge with forking a library is keeping the fork in-sync with the original library as it evolves over time.

Let’s say, you forked Project A and added a bunch of code to support your product’s needs. Fast-forward a few months and years down the road, Project A has moved on from when you forked it and there are a bunch of new versions and you would like to upgrade Project A. The challenge is to make sure that your custom code works with all future versions of Project A, without breaking anything. It’s almost always a bumpy ride. Good luck.

If you must fork, then make sure to keep your fork as minimum as possible and do your ultimate best to contribute back your changes to the original codebase.

Is the code forking an open-source library? Can the fork be justified? Why are we forking? Is it worth it? What alternative options do we have instead of forking? Are the original code and forked/changed code on separated commits?

Watch out for tech debt during the code review

Tech debt is almost always the result of a quick and dirty approach of coding a fix or feature due to time constraints.

Technical debt (also known as design debt[1] or code debt, but can be also related to other technical endeavors) is a concept in software development that reflects the implied cost of additional rework caused by choosing an easy (limited) solution now instead of using a better approach that would take longer. — Wikipedia

It might be difficult to avoid tech debt for new companies that do not have the financial and technical resources available to them and this is the phase where a huge volume of tech debt is added to the codebase because, the objective is to get a product that works in the market, not built a perfect product.

Tech Debt, Credit: Dilbert by Scott Adams

There is no excuse for adding tech debt to an established product that has a healthy customer base, financial and technical resources. Such companies should focus on addressing the tech debt that was added in the earlier stages of product instead of adding new tech debt.

Do the new changes degrade the qualify of the existing code? Do the new changes make a method/class candidate for refactoring? Does the changelist (pull request) introduce tech/code debt? Are there any duplicate blocks of code that could be made reusable?

Tests

During the code review, tests are probably the one area of the pull request (changelist) that would get skimmed through or ignored. Simply because a test is passing it does not mean that it is a valid test.

Are the tests correct? Do they fail when the code is broken? Do the tests cover all branches (execution paths) and instructions in the code? Are the tests independent of each other? Are the tests easy to understand and maintain? Does this feature need to be tested under load to make sure that it scales well and that there are no memory leaks?

Adding dead code

Sometimes the developer will say, well, we don’t need this block of code now but, maybe we will need it in the future. Or, a developer would make a method so generic with the hope that it covers future requirements.

Let’s cross that bridge when we get there. Don’t add dead code and hope that it resurrect in the future.

Such dead code should not be approved because there is a very high chance that the code is never used in the future or it won’t be bullet-proof enough to accommodate future needs.

Credit: Oliver Widder

Is it the right time to add this functionality? Does the code address only the acceptance criteria and nothing more or less?

Easy To Read and Maintain

Sometimes developers write super complex code for something straightforward because it makes us feel good. This is usually the case with junior or new developers.

Complexity-wise, is the code as a whole or, in part, challenging to read and understand? Is the code easy to maintain and extend? Is the code easy to test?

Naming and documentation is hard

Let’s admit it, naming is very hard and that’s why it needs the code reviewer's attention.

Credit: CommitStrip.com

The questions you should ask yourself as a code reviewer

Do the names easily communicate what the item is or does? Are the code comments easy to understand? Is the code over-commented or not commented at all? Is the comment necessary? Can a complex piece of code be refactored instead of adding comments? Are the code comments meaningful and gives more information than the actual code? Are all the documentation, i.e., test, build, release relating to the code change updated?

Not all the questions might be relevant for your specific case, feel free to pick those that matter the most.