プログラマの間ではかなり有名で、一人一冊持っておくべきということも聞いた「リーダブルコード」。
1回目さらっと読んで、2回目に要点をまとめたので、自習用のメモをブログにまとめます。
#はじめに
コードは他の人(未来の自分)が最短時間で理解できるように書かなければならない。
行数は必ずしも短ければいいわけではなく、複雑な1行より分割されて整理された2行の方がいい。理解しやすいかがポイント。
#表面上の改善
##1、名前に情報を詰め込む
1-1 明確な単語を選ぶ
get → どこからget ?
size → 何のsize ?
stop → 取り消し可能?完全消去
いずれも意味が曖昧
代替案:
例:start → launch, create, begin, open
###1-2 汎用的な名前を避ける
例:
retval(戻り値) → sum_squares
こちらの方が具体的で分かりやすい。またバグも発見しやすい。
ただ、一時的な保管だけのためであれば、retvalでも十分。
###1-3 名前に情報を追加する
・変数+単位(例:start_ms)
・危険や注意を喚起する情報など
###1-4 名前の長さを決める
名前は短い方が良いが、変数の使い方によって適切な長さは変わる。
・スコープが小さい → 短い名前でもOK(全ての情報が見えているので)
・省略形はプロジェクト内など短な人にしか分からないものは避けるべき。新しいチームメイトが加わった際に、見て分からないため。
・不要な単語は捨てる → ConvertToString( ) → ToString( ) これでもできることは一緒だから
###1-5 名前のフォーマットで情報を伝える
アンダースコアやダッシュ、大文字を使おう
##2、誤解されない名前
例:filter( )
filter( "year" <= "2011")
→ 選択するのか、除外するのか分からない
→ select( ), exclude( )を使おう
例:length
max_length
→ バイト数?文字数?単語数?
→ max_charsとかにしよう
例:limit
→ 以下か未満か分からない
→ 限界値を明確にするにはmax_, min_ を使おう
範囲の指定:firstとlast
first = 2, last = 4 → 2~4
包含/排他的範囲:beginとend
begin = 2, end = 4 → 2~3
・ブール値
read_password = true → これから読む? OR すでに読んでいる?
→ need_passwordなどにする
ブール値の変数名は頭にis, has, can, shouldなどを使って分かりやすくしよう。
##3、書くべきでないコメント、書くべきコメント
書くべきでない:
・新しい情報を提供するわけでもなく、ただコードの意味を書いているだけ。
・曖昧な言葉を使っている
書くべき:
自分の考えを記録するもの
・〜だと〜%速かった、〜だと〜なので難しい、〜よりも〜の方がコストは高いようだ
など → 無意味なテストや無駄な確認処理などをしなくて済んだり、バグだと思われなくて済む。
・コードの欠陥にコメントをつける(〜を修正中 など)
・定数の値に対する背景
・全体像を要約するコメントや実例を書くと他人が見ても分かりやすい
#ループとロジックの単純化
##1、制御フローを読みやすくする
1-1条件式の並び順
左:調査対象の式(変化する) 右:比較対象の式(あまり変化しない)
if (length >= 10 ) 良い
if (10 <= length ) あまり良くない
###1-2 if elseブロックの並び順
肯定系、単純、目立つものを先に書くべし
良い:
if ( a == b ) {
} else {
}
あまり良くない:
if ( a != b ) {
} else {
}
###1-3 三項演算子、do/whileループ、gotoなどを使うと読みにくくなることも。なるべく使わないようにする
##2、巨大な式を分割する
式を簡単に分割するには、式を表す変数を使えば良い。式を変数に代入しておくと何かと便利。また、ド・モルガンの法則を使ってロジックを操作しよう。
##3、変数と読みやすさ
変数を適当に使うと?
1、変数が多いと変数を追跡するのが難しくなる
→ コードが読みやすくならない変数を削除
2、変数のスコープが大きいとスコープを把握するのが難しくなる
→ 変数のスコープを縮める=グローバル変数を避ける
3、変数が頻繁に変更されると現在の値を把握するのが難しくなる
→ 一度だけ書き込む変数を使う
コードの再構築
1、無関係の下位問題を抽出する
エンジニアリングとは、大きな問題を小さな問題に分割してそれぞれの解決策を組み立てること。
例:
高レベルな目標「与えられた地点から最も近い店舗を見つける」
下位問題「2つの地点(緯度経度)の球面距離を算出する」
→この処理だけで自己完結しているので、新しい関数として抽出する。
思考プロセス:
1、高レベルの目標は何か
2、各行を見て、高レベルの目標に直接的に効果があるのかOR無関係の下位問題を解決しているのか
3、それらが相当量あれば、それらを抽出して別の関数にする
・汎用コードをたくさん作っておけば、複数のプロジェクトで再利用できる
##2、1度に1つのことを
・コードは1つずつタスクを行うようにしなければならない。
コードが行なっているタスクを全て列挙する
→ タスクをできるだけ異なる関数に分割する。少なくとも異なる領域に分割する。