はじめに
「リーダブルコード」を読んで、自分として新たな発見があった点をメモ。
※内容を全て要約した記事ではありません。
参考文献:リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック
1章 理解しやすいコード
<読みやすさの基本定理>
コードは他の人が最短時間で理解できるように書かなければいけない
2章 名前に情報を詰め込む
2.1 明確な単語を選ぶ
GetPage
という命名は、簡潔にわかりやすい命名だと思ってしまうが、「get」はあまり明確な単語ではない。
この命名を見ただけではページをどこから取得するのか定まらない。
- ローカルキャッシュから?
- データベースから?
- インターネットから?
例:インターネットから取得する場合、FetchPage
やDownloadPage
の方が明確
3章 誤解されない名前
3.3 限界値を含めるときは min と max を使う
// 曖昧な記述
CART_TOO_BIG_LIMIT = 10;
if shopping_cart.num_items() > CART_TOO_BIG_LIMIT;
Error("カードにある商品数が多すぎます。")
これでは「未満(限界値を含まない)」なのか、「以下(限界値を含む)」なのか明確でない。
// 適切な記述
MAX_ITEMS_IN_CART = 10;
if shopping_cart.num_items() > MAX_ITEMS_IN_CART;
Error("カードにある商品数が多すぎます。")
限界値を含むことが明確。
3.4 範囲を指定するときは first と last を使う
包含的範囲であれば、first/last を使用すると良い
// これは'a'から'c'までの包含的範囲
alphabet = ['a', 'b', 'c', 'd'];
printChar(alphabet, first=0, last=2);
出力:abc
3.5 包含/排他的範囲には begin と end を使う
10月16日に開催されたイベントを全て出力する場合、以下のように書く方が
PrintEnventsInRange(begin='OCT 16 12:00am', end='OCT 17 12:00am')
以下のように書くよりも簡単。
PrintEnventsInRange(first='OCT 16 12:00am', last='OCT 16 11:59:59.9999pm')
4章 美しさ
4.4 縦の線をまっすぐにする
列の要素や引数を複数行並べる場合、縦の線をまっすぐにすればコードが読みやすくなる。
以下、空白を使用して引数を整列させた例
ChechFullName('Doug Adams' , 'Mr. Douglas Adams' , '');
ChechFullName(' Jake Brown ', 'Mr. Jake Brown III', '');
ChechFullName('No Such Guy' , '' , 'no match found');
ChechFullName('John' , '' , 'more than one result');
5章 コメントすべきことを知る
コメントの目的は、書き手の意図を読み手に知らせることである。
コードからすぐにわかることをコメントに書かない。
自分の考えを記録する。(監督のコメンタリー)
// このデータだとハッシュテーブルよりもバイナリツリーの方が 40% 速かった。
// 左右の比較よりもハッシュの計算コストの方が高いようだ。
6章 コメントは正確で簡潔に
6.5 入出力のコーナーケースに実例を使う
言葉で説明するよりも実例を提示した方が理解しやすい場合もある。
// 'src'の先頭や末尾にある'chars'を除去する。
// 実例:Strip("abba/a/abab", "ab")は"ba/a/"を返す。
String Strip(String src, String chars){...}
この場合、chars は除去する文字列であり、複数繰り返しのcharsについても除去されていることがわかる。
6.7 「名前付き引数」コメント
名前付き引数が使用できない言語であれば、インラインコメントを使って同じような表現ができる。
void Connect(int timeout, bool use_encryption) {...}
// 引数にコメントをつけて関数を呼びだす
Connect(/* timeout = */ 10, /* use_encryption = */ false);
7章 制御フローを読みやすくする
7.1 条件式の引数の並び順
条件式の引数の並び順は、以下の指針に従う。
条件式の左辺 | 条件式の右辺 |
---|---|
「調査対象」の式。変化する。 | 「比較対象」の式。あまり変化しない。 |
例えば、
if (length >= 10)
if (10 <= length)
の場合、前者の方が読みやすい。
7.7 ネストを浅くする
ネストの深いコードは理解しにくい。深いほど読み手は「精神的スタック」に条件をプッシュしなければならない。
ネストを浅くするには、「失敗ケース」を早めに関数から返す。
▼悪い例
if (user_result == SUCCESS) {
if (permission_result != SUCCESS) {
errorMsg = "permission error";
return;
}
errorMsg = "";
} else {
errorMsg = user_result
}
return;
▼修正後
if (user_result != SUCCESS) {
errorMsg = user_result;
return;
}
if (permission_result != SUCCESS) {
errorMsg = "permission error";
return;
}
errorMsg = "";
return;
※ループ内部のネストを削除するには、continue
を使う
8章 巨大な式を分割する
8.3 ド・モルガンの法則を使う
ド・モルガンの法則はコーディングにも使用することができる。
not (a or b or c) = (not a) and (not b) and (not c)
not (a and b and c) = (not a) or (not b) or (not c)
「notを分配してand/orを反転する」と覚える
例:
if (!(file_exists && !is_protected))
↓書き換え
if (!file_exists || is_protected)
8.5 複雑なロジックと格闘する
場合分けや条件が多すぎる場合、問題を「否定」したり、反対のことを考えてみる。
例:「2つの範囲が重なるのか」という問題の場合、その反対は「2つの範囲が重ならない」になる。
9章 変数と読みやすさ
9.1 変数を削除する
中間結果を保持するだけの変数は削除する。
9.2 変数のスコープを縮める
メモ:
ECMAScriptでは、var
ではなくlet
を推奨している。
(var
は多重に定義できてしまうが、let
ではエラーを検知する)
9.3 変数は一度だけ書き込む
値を変更する予定のない変数は定数で定義する。
イミュータブルなオブジェクトを使用するようにしたい。
所感
「リーダブルコード」はプログラミング初学者向けの技術書として有名だが、本当にこの本の価値が理解できるのはプログラミング歴2~3年目以降のエンジニアではないかと感じた。
特に、他者のコードレビュー経験などがあると、自らの経験と照らし合わせてコードの良し悪しの判断基準になると思う。
本書のサンプルコードで初めてC++に触れたが、最近の主要な言語と作法が異なる点があるためコードリーディングが辛いタイミングがあった。
競技プログラミングの世界ではC++が推奨されているため、機会があれば今後学びたい。