1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GENEROSITYAdvent Calendar 2024

Day 18

「リーダブルコード」から得た実践的知識まとめ

Last updated at Posted at 2024-12-18

はじめに

エンジニアにとっての”バイブル”とも呼べる「リーダブルコード」。
今回は復習も兼ねて、まだ読んだことのない方に向けて内容を簡単にまとめてみました。
この本は何度でも読み返すべきオススメの一冊なので、まだ読んだことがない方はぜひ実際に本を手にとって読んでみてください。

すでに読まれた方にとっては、内容を思い出すきっかけとなれば幸いです。

コードは「他人」が最短時間で「理解」できるように書く

コードは短くリファクタリングしたほうがいい。しかし、それ以上に「理解するまでにかかる時間」を短くするほうが大切。
・ここでの「他人」には、”未来の自分”も含まれている。
・ここでの「理解」とは、変更を加えたりバグを見つけたりできるという意味。

短く簡潔だが、理解が難しいコード例
const fizzBuzz = (n: number) =>
  Array.from({ length: n }, (_, i) => (++i % 3 ? "" : "Fizz") + (i % 5 ? "" : "Buzz") || i);
長いが、理解がしやすいコード例
//1から指定された数値nまでの数を処理し、3の倍数なら"Fizz"、5の倍数なら"Buzz"、
//3と5両方の倍数なら"FizzBuzz"、それ以外の場合はその数値を、配列にして返す関数
function generateFizzBuzz(n: number): (string | number)[] {
  const result: (string | number)[] = [];
  
  // 1からnまで順にループ
  for (let i = 1; i <= n; i++) {
    if (i % 3 === 0 && i % 5 === 0) {
      result.push("FizzBuzz"); // 3と5の倍数
    } else if (i % 3 === 0) {
      result.push("Fizz"); // 3の倍数
    } else if (i % 5 === 0) {
      result.push("Buzz"); // 5の倍数
    } else {
      result.push(i); // それ以外の数値
    }
  }
  return result;
}
結果はどちらも一緒
console.log(fizzBuzz(15));
console.log(generateFizzBuzz(15));

[1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, "Fizz", 13, 14, "FizzBuzz"]

名前に可能な限りの情報をつめこむ

変数名や関数名、クラス名やファイル名、などなど。名前をつける際には的確な情報をつめこむ。
const getPage()(悪い例)
const getTopPageFromAPI() (良い例)

1. より明確な単語を選ぶ

getData()よりもfetchData()downloadData()
stop()よりもkill()pause()を使ったほうが、どんな関数なのかが想像しやすい。

2. 汎用的な名前を避ける

result = よりもsum_squares = のほうが、どんな値を持つ変数なのかをイメージできる。
(例外)
2つの変数の値を入れ替える際に使うtmp = は”ただの一時的な入れ物”という意味が込められているのでそのままがよい。

3. ループ処理のイテレータ変数

for (let i = 0; i < orange; i++) {
    for (let j = 0; j < banana; j++) {
      for (let k = 0; k < apple; k++) {
        array.push([i, j, k]); // i, j, kの現在の値を配列に追加
      }
    }
  }

上記のような場合は、i, j, kを使うよりも単語の頭文字からoi, bi, aiを使うほうがミスを減らせる。

4. 重要な属性を追加する

password = ではなくplaintext_password = とすることで、後で暗号化する処理を忘れずにすむ。
size_mb = sleep_ms = のように、単位に複数の可能性がある場合は明確にする。

5. ブール値の名前

ブール値を返す関数や、ブール値を持つ変数の名前は、疑問形で"Yes,"もしくは"No,"で答えられるis, has, can, shouldを先頭につけるとわかりやすい。
(例)
isAdmin = false
canReserve = true

コメントすべきことを知る

大前提として、通常は「補助的なコメント」が必要になることはない。(そういうわかりやすいコードを書くべき)
優れたコード > ひどいコード + 優れたコメント
コメントを書くと、その分だけコードを読む時間は長くなってしまう。そのため、コメントには存在するべき価値をもたせるべき。

価値のないコメント
//新しいスタートタイムを設定する
start_time = setStartTime()
価値のあるコメント
# 2番目の'*'以降をすべて削除する
name = '*'.join(line.split('*')[:2])

1. その瞬間の自分の考えを記録する

(例)
//いろんなソートを比較してみた結果、このソートが最適だった
→ このコメントがあれば下手に最適化しようとして時間を無駄にしなくてすむ

//このmodelファイルには関係のない関数が多くあるので、helper関数ファイルに移動させたほうがいいかも
→ 初めてこのファイルを読む人が悩まずにすむし、誰かに修正を促している。

2. 修正箇所にコメントをつける

(例)
//TODO(田中さん):多言語に対応する
//maybe-later:もっと高速なアルゴリズムを使う

3. 定数にコメントをつける

(例)
capacity = 15 //今回のイベントは一度に入場可能な人数が最大15人
ratio = 0.72 //いろいろ試した結果、この比率が一番キレイだった

4. 呼び出す際に注意が必要な関数にコメントをつける

(例)

//メールを送信する外部サービスを呼び出している(1分でタイムアウト)
void SendEmail(path, subject, body)

5. ファイルにコメントをつける

(例)
//このファイルには管理者権限を操作するためのヘルパー関数が含まれています。
//このファイルは「注文確認ページ」のbuttonコンポーネント

おわりに

この「リーダブルコード」は、全3部構成で、合計15章から成り立っています。
章立ては「難易度」の順番になっていて、読み進めていくほど応用的な内容となっています。
今回は、第一部「表面上の改善」の内容を取り上げてみました。

第二部「ループとロジックの単純化」、第三部「コードの再構成」の内容に関しては、リファクタリングについて書かれたこちらの記事が参考になるかと思います。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?