はじめに
エンジニアにとっての”バイブル”とも呼べる「リーダブルコード」。
今回は復習も兼ねて、まだ読んだことのない方に向けて内容を簡単にまとめてみました。
この本は何度でも読み返すべきオススメの一冊なので、まだ読んだことがない方はぜひ実際に本を手にとって読んでみてください。
すでに読まれた方にとっては、内容を思い出すきっかけとなれば幸いです。
コードは「他人」が最短時間で「理解」できるように書く
コードは短くリファクタリングしたほうがいい。しかし、それ以上に「理解するまでにかかる時間」を短くするほうが大切。
・ここでの「他人」には、”未来の自分”も含まれている。
・ここでの「理解」とは、変更を加えたりバグを見つけたりできるという意味。
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章から成り立っています。
章立ては「難易度」の順番になっていて、読み進めていくほど応用的な内容となっています。
今回は、第一部「表面上の改善」の内容を取り上げてみました。
第二部「ループとロジックの単純化」、第三部「コードの再構成」の内容に関しては、リファクタリングについて書かれたこちらの記事が参考になるかと思います。