Point of code review (Basic)

noboru_i

Noboru Ishikura

Posted on September 12, 2021

Point of code review (Basic)

overview

When I review the code at work, I follow the flow below.

  1. Develop locally by the implementer.
  2. Push the code to GitHub.
  3. Create a Pull Request (PR).
  4. Assign to the reviewer.
  5. Review and add some comments.
  6. The implementer replies with a comment or pushes modified code.
  7. 4. Return to
  8. When there are no comments in the review, it is merged and the work is completed.

I wrote a basic "code review point" in this article.
Because I want the implementer to check it myself before requesting a review.
That makes improving the accuracy of the code review.

For more details, please read O'Reilly's "The Art of Readable Code".

Write PR description

Describe the reason for code changes and overview in the "Summary" of the PR.
At a minimum, issues and ticket links that triggered the change are required.

detail

It's a pain to read through the code without knowing any overview of what the changes are.
By reading the "Summary", the reviewer can imagine the code difference and easy to review.

TODO comment

Leave "TODO comments" if you have uncompleted tasks in the PR.

detail

Ideally, one PR should complete one "task".

However, for various reasons during development, there will be situations like "I want you to review it in the middle".
At that time, it is difficult for the reviewer to read while understanding "what is done and what is not done".
TODO comments in the code help it.

In addition, the editor or IDE has a function that lists "TODO comments", which is also effective for organizing remaining issues later.

good

function foo() {
  // TODO: foo API is not implemented. So I return dummy data.
  return {};
}
Enter fullscreen mode Exit fullscreen mode

Delete comment out

Delete physically the code that is temporarily written for debugging or that is to be deleted. (unless there is a special reason.)

detail

We are developing with history management on GitHub.
We can search deletion history by PR search and git blame.
So you should remove any code you no longer need.

If a lot of useless code remains as a comment, it will be noisy when searching for the code, and the code will be difficult to read.

Early return

Make good use of the return statement.

detail

When reading the code, we basically read from top to bottom.
However, if there is an if statement, we may read the contents after knowing "whether else-if continues, and what we are doing after they are finished".
If "actually, the content of the function was only an if statement", it would be a waste of time on the reviewer.

It will be easier to read if the code has a return statement and shows it clearly to exit the function.

bad

function some_long_method() {
  if (foo) {                // 1. find if block. search end of the block.
    // some long process    // 4. read inside the block.
    if (bar) {
      return a;
    } else if (baz) {
      return b;
    }
  }                         // 2. find end block. read next line.
  return null;              // 3. find "return". So I know "if !foo, return null only". So scroll up to read inside the block.
}
Enter fullscreen mode Exit fullscreen mode

good

function some_long_method() {
  if (!foo) {           // 1. find if block. Also find next "return" line.
    return null;
  }
  // some long process  // 2. read the process.
  if (bar) {
    return a;
  }
  if (baz) {
    return b;
  }
  return null;
}
Enter fullscreen mode Exit fullscreen mode

boolean variable naming

Name the boolean variable name as isXXX so that it can be read like an English sentence such as {class name} is XXX.

detail

For example, if the variable name is isUplaod, it is "be verb + verb".
So it cannot be read like an English sentence.
If it is isUplaoding, it can be read as English like "{The class} is uploading".

However, boolean types do not necessarily have to be in the form isXXX.
canUpload and hasChildren are good names because you can understand "when the value is true".

Commonization

Extract methods that are likely to be used on other screens of the system, so that they can be used in common.
Such as tax-excluded / tax-included amount calculation and special date formats.

detail

Some calculations (such as the amount excluding tax) don't change for each process.
And, the same calculation should be performed the same work through the system.
If such calculations are scattered throughout the code, it is difficult to find and correct when the calculation is wrong or when the requirements change.
Therefore, the same process should be cut out into a single function and shared.

However, there are some cautions.
Don't be commonize the processes that are "accidentally" matched.
For example, the calculation of "the game score multiplied by 1.1" and "the calculation of the tax-included price with a tax rate of 10%" should not be commonized even at the same 1.1 times.

Reduce "state"

Reduce "states" as much as possible.
Calculate values that can be calculated from other "states".

detail

You can give a class a "state" just by writing let foo;.
However, if you have it as a "state", you have to think about various things.

  • When will it be initialized?
  • When will it be updated?
  • What is the value when this function is called?
  • What value can be taken when another "state" is a specific value?

The more "states" you manage, the harder it is to read the code and the more causes to bug.
Calculate the value that can be calculated from other "states" by calculation.

bad

let hasError = false;
let errorMessage = null;

function setError(newMessage) {
  hasError = true;
  errorMessage = newMessage;
}

function printError() {
  if (!hasError) {
    return;
  }
  console.log('message is ' + errorMessage);
}
Enter fullscreen mode Exit fullscreen mode

good

let errorMessage = null;
function hasError() {
  return errorMessage != null;
}

function setError(newMessage) {
  errorMessage = newMessage;
}

function printError() {
  if (!hasError()) {
    return;
  }
  console.log('message is ' + errorMessage);
}
Enter fullscreen mode Exit fullscreen mode

Manage const values (even if the values havn't been determined)

Even if the information is not determined at the time of implementation, make constant according to the meaning.

detail

bad

function method1() {
  location.href = ""; // TODO: Change value if tems URL is fixed.
}
function method2() {
  location.href = ""; // TODO: Change value if tems URL is fixed.
}
Enter fullscreen mode Exit fullscreen mode

good

// TODO: Change value if tems URL is fixed.
const TERMS_URL = "";

function method1() {
  location.href = TERMS_URL;
}
function method2() {
  location.href = TERMS_URL;
}
Enter fullscreen mode Exit fullscreen mode

Make visibility as low as possible

Keep unnecessary things out of sight.

detail

If unnecessary functions/values have "export", it will be difficult to understand "where is it used" and "what is the range of side effects if the contents are changed".
Don't "export" it now even if it "may be used in the future".

Similarly, when declaring variables, try to reduce the number of lines that can be accessible.

Read your changes again

detail

Read the diffs again before requesting a PR review.
If you look at GitHub in your browser, you'll see a tab called "Files changed" that makes it easy to see the differences that are included in the PR.

In particular, check the following points.

  • Are not there any changes you didn't intend? (e.g. Accidentally touched the keyboard. Changes that are not related to PR.)
  • Are there all changes you intended?
  • Does the difference match what you wrote in the PR overview?

Finally

It is tiring to point out small details or point out a simple mistake.
Let's make our code review meaningful by being careful at the time of implementation and before review.

💖 💪 🙅 🚩
noboru_i
Noboru Ishikura

Posted on September 12, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related