※こちらの記事は書籍の自分用まとめです
『リーダブルコード -より良いコードを書くためのシンプルで実践的なテクニック』をインターン初め当初にPRレビューを依頼するときは本書籍の内容を満たしているかを確認するよう助言を頂いたので学習のまとめとしてこちらの記事を書きます。この書籍のテーマは「読みやすいコード」です。
1. 理解しやすいコード
- コードは理解しやすくなければならない
- コードは他の人が最短時間で理解できるように書かなければならない
Part.1 表面上の改善
2. 名前に情報を埋め込む
- 名前に情報を詰め込む
- 気取った言い回しよりも明確で正確のほうがいい
advace. tmp
という名前は生存期間が短くて、一時的な保管が最も大切な変数にだけ使おう
advace. tmp, it, retval
のような汎用的な名前を使うときは、それ相応の理由を用意しよう
(i, j, k
を使うのではなく説明的な名前(club_i, members_i, users_i
やci, mi, ui
, etc.)を付ける)
☞ 基本的には意味を理解してもらわなければ困るところに属性を追加する(セキュリティ, etc.)
まとめ
- 明確な単語を選ぶ -
Get
ではなく、状況に応じてFetch, Download
, etc.を使う -
tmp, retval
, etc.の汎用的な名前は避ける - ただし明確な理由があれば別の話. - 具体的な名前を使って、物事を詳細に説明する -
ServerCanStart()
よりもCanListenOnPort()
のほうが明確だ - 変数名に大切な情報を追加する - ミリ秒を表す変数名には後ろに
_ms
をつけるこれからエスケープが必要な変数名には、前にraw_
をつける - スコープの大きな変数には長い名前を付ける - スコープが数画面に及ぶ変数には1~2文字の短い暗号めいた名前をつけてはいけない. 短い名前はスコープが数行の変数につけるべきだ
- 大文字やアンダースコアなどに意味を含める - クラスのメンバ変数にアンダースコアをつけてローカル変数と区別する
3. 誤解されない名前
- 名前が「他の意味に間違えられることはないだろうか?」と何度も自問自答する
advace. 限界値を明確にするには、名前の前にmax_
やmin_
をつけよう
まとめ
最善の名前とは誤解されない名前である. 限界値はmax, min
、包含的範囲はfirst, last
、包含/排他的範囲はbegin, end
がイディオムなのでそれを使う. boolenはis, has
を使い、否定形は避ける. 単語に対するユーザの期待にも注意する. get(), size()
には軽量なメソッドが期待されている.
4. 美しさ
- 一貫性のあるスタイルは「正しい」スタイルよりも大切だ
まとめ
- 複数のコードブロックで同じようなことをしていたら、シルエットも同じようなものにする
- コードの「列」を整理すれば、概要が把握しやすくなる
- ある場所でA* B* Cに並んでいたものを他の場所でB* C* Aにように並び替えてはいけない. 意味のある順番を選んで常にその順番を守る
- 空行を使って大きなブロックを論理的な「段落」に分ける
5. コメントすべきことを知る
- コメントの目的は、書き手の意図を読み手に知らせることである
- コードからすぐわかることをコメントに書かない
まとめ
コメントすべきでは「ない」こと:
- コードからすぐに抽出できること
- ひどいコード(ひどい名前の関数)を補う「捕捉的なコメント」. コメントを書くのではなくコードを修正する
記録すべき自分の考え:
- なぜコードが他のやり方ではなくこうなっているのか(「監督コメンタリー」)
- コードの欠陥を
TODO:
やXXX:
などの記法を使って示す - 定数の値にまつわる「背景」
読み手の立場になって考える:
- コードを読んだ人が「えっ?」と思うところを予想してコメントをつける
- 平均的な読み手が驚くような動作は文章化しておく
- ファイルやクラスには「全体像」のコメントを書く
- 読み手が細部を捕らわれないように、コードブロックにコメントをつけて概要をまとめる
6. コメントは正確で簡潔に
- コメントは領域に対する情報の比率が高くなければいけない
まとめ
- 複数のものを指す可能性がある「それ」や「これ」などの代名詞は避ける
- 関数の動作はできるだけ正確に説明する
- コメントに含める入出力の実例を慎重に選ぶ
- コードの意図は詳細レベルではなく高レベルで記述する
- よくわからない引数にはインラインコメントを使う(ex.
Function(/* arg = */ ...)
) - 多くの意味が詰め込まれた言葉や表現を使ってコメントを簡潔に保つ
Part.2 ループとロジックの単純化
7. 制御フローを読みやすくする
- 条件やループなどのフローはできるだけ「自然」にする. コードの読み手が立ち止まったり読み返したりしないように書く
- 行数を短くするよりも、他の人が理解するのにかかる時間を短くする
advace. 基本的にはきちんとif/else
を使おう. 三項演算子はそれによって簡潔になるときだけ使おう
- 変更するときにはコードを新鮮な目で見る. 一歩下がって全体を見る.
まとめ
- 比較を書くときは、 変化する値を左に、より安定した値を右 に配置する
-
if/else
文のブロックは適切に並び替える. 一般的に肯定形* 単純* 目立つものを先に処理する. こうした基準は衝突することもあるけど、衝突がなければ基準を守っておこう - 三項演算子,
do/while
ループ,goto
, etc.のプログラミング構成要素を使うとコードが読みにくくなることが多い. 代替となるものが必ずあるので、これらは使わないほうがよいだろう - ネストしているとコードを追うのに集中力が必要になる. ネストが増えるたびに「スタックにプッシュ」することが増える. 深いネストを避けるには 「直線的」なコードを選択する
- 早めに返してあげると、ネストを削除したりコードをクリーンにしたりできる. 特に 「ガード節」(関数の上部で単純な条件を先に処理するもの) が便利だ
8. 巨大な式を分割する
- 巨大な式は飲み込みやすい大きさに分割する
- 頭が良いコードに気を付ける. あとで他の人がコードを読むときにわかりにくくなる
まとめ
大きな式の値を保持する説明関数には3つの利点がある
- 巨大な式を分割できる
- 簡潔な名前で式を説明することで、コードを文書化できる
- コードの主要な「概念」を読み手が認識しやすくなる
そのほかには ドモルガンの法則を使ってロジックを操作する 方法がある. これは論理式をキレイに書き直すことにも使える.
問題を「否定」したり、反対のことを考えてみたりすることが必要になる.
複雑なロジックを見つけたら積極的に分割する.
9. 変数と読みやすさ
- 変数のことが見えるコード行数をできるだけ減らす
- 変数を操作する場所が増えると、現在値の判断が難しくなる
まとめ
変数を減らして「軽量」にすれば、コードは読みやすくなる
- 邪魔な変数を削除する - 結果をすぐに使って「中間結果」の変数を削除する
- 変数のスコープをできるだけ小さくする - 変数を数行のコードからしか見えない位置に移動する
- 一度だけ書き込む変数を使う - 変数に一度だけ値を設定すればコードが理解しやすくなる
Part.3 コードの再構成
10. 無関係の下位問題を抽出する
まとめ
プロジェクト固有のコードから汎用コードを分離する. 一般的な問題を解決するライブラリやヘルパー関数を作っていけばプログラムに固有の小さな核だけが残る
11. 一度に1つのことを
- コードは1つずつタスクを行うようにしなければいけない
まとめ
- 読みにくいタスクがあればタスクをすべて列挙する(別の関数に分割できるタスクがある. それ以外は関数の段落)
- タスクをどのように分割するよりも分割することが大切
- 一番難しいことはプログラムが行なっていることを説明すること
12. コードに思いを込める
おばあちゃんがわかるように説明できなければ、本当に理解したとは言えない
まとめ
- プログラムのことを簡単な言葉で説明する. 説明で使っている単語やフレーズをよく見れば分割する下位問題がどこにあるかわかる
ラバーダッキング
- 問題が発生した際に、ラバーダック(ゴム製のアヒルのおもちゃ)に悩みを話しかけることで、頭の中を整理し、問題の解決を図る方法
問題や設計をうまく言葉で説明できないのであれば、何かを見落としているか、詳細が明確になっていないということだ. プログラムを言葉にすることで明確な形になるのである.
13. 短いコードを書く
- 最も読みやすいコードとは何も書かれていないコードだ
まとめ
できるだけコードを書かないこと. 新しいコードはテスト, 文章, 保守が必要になる. また、コードが増えると「重く」なるし開発も難しくなる.
新しいコードを書かないようにするには、
- 不必要な機能をプロダクトから削除する. 過剰な機能は持たせない.
- 最も簡単に問題を解決できるように要求を考える.
- 定期的にすべてのAPIを読んで、標準ライブラリに慣れ親しんでおく.
Part.4 選抜テーマ
14. テストと読みやすさ
- 他のプログラマが安心してテストの追加や変更ができるように、テストコードを読みやすくする
- コードを完全にテストする最も単純な入力値の組みあわせを選択しなければならない
- テストには最もキレイで単純な値を選ぶ
まとめ
テストコードでも読みやすさが大切だ. テストが読みやすければ、テストが書きやすくなり、みんながテストを追加しやすくなる
テストを改善する点
- テストのトップレベルはできるだけ簡潔にする. 入出力のテストはコード1行で記述できるといい.
- テストが失敗したらバグの発見や修正がしやすいようにエラーメッセージを表示する.
- テストに有効な最も単純な入力値を使う.
- テスト関数に説明的な名前をつけて、何をテストしているのかを明らかにする.
Test1
ではなく、Test_<関数名>_<状況>
のような名前にする
15. 「分 / 時間カウンタ」を設計・実装する
総合問題
まとめ
素朴な解決策 - 速度とメモリの問題
ベルトコンベヤー設計 - 速度とメモリの問題は解決できたが柔軟性が乏しい.
時間バケツ設計 - 複数の下位問題に分割することでこれらの問題を解決した. ボトムアップで3つのクラスを作りそれぞれで下位問題を解決した.
付録 合わせて読みたい
- 高品質のコードを書くための書籍
- プログラミングに関する書籍
- 歴史的記録
解説
本書の内容を身につけて自然に読みやすいコードを書く3つのステップ
- 実際にやる
- 当たり前にする
- コードで伝える
最後に
読みやすいコードを書いて自分が書いたコードを忘れてしまっても見たら簡単にわかるように書いておく!