###未経験エンジニアとして実務に入ったので、リーダブルコードを読んだのでそのメモ。
ざっくりではなく、少し細かめにメモしてます!
1章 理解しやすいコード
###Point
#####コードは理解しやすくしなければならない。
#####コードは他の人が最短時間で理解できるように書かなければいけない。
#####6ヶ月後の自分がみて、理解しやすいコードかが大事!
#####コードは短くした方がいいけど、理解するまでにかかる時間を短くすることが大事。
###このコードは理解しやすいか?
を一歩下がって自問自答することが大事!
# 2章 名前に情報を詰め込む
###Point
#####名前に情報を詰め込む
名前を見ただけで情報を読み取るようにすること
・明確な単語を選ぶ
→空虚な単語は避けるべき。「get」とかはあまり明確な単語ではない。
どこからのget?とわからなくなる。
例えば、getではなく、状況に応じてfetch/downloadなどを使う。
######汎用的な名前を避ける
→tmpやfooなどの空虚な名前は避けよう。
具体的な目的や値を表す名前をつけよう。
戻り値retval×
sum_squares○
なので、tmp/it/retvalなどの汎用的な名前を使うときはそれ相応の理由を用意しよう!
単なる怠慢でこれを使うのはナンセンス!「命名力」!
######抽象的な名前よりも具体的名前を使う
→より適切な名前を使う
######接尾辞を使って情報を追加する
→絶対に知らせないといけない大切な情報の場合「変数名」に追加すればいい。
値の単位など、delay→delay_secsなどより明確に。
セキュリティの面でもそうだ。
password→plaintext_password(passwordはプレインテキストなので、処理前に暗号化すべき)
変数の意味を理解してもらわないといけないところに属性を追加しておく。
######名前の長さを決める
→単純に覚えにくいし、画面占領してしまう、コードの量が増える。
スコープが小さければ短い名前でもいい。
識別子のスコープが大きければ、名前に十分な情報を詰め込んで明確にする必要がある。
省略も行いがちだが、プロジェクト固有の省略形はダメ。新しいメンバーは理解できない。
######名前のフォーマットで情報を伝える
→アンダースコア・ダッシュ・大文字を使って名前に情報を詰め込むこともできる。
どんな規約を使うかどうかはチームで決める。一貫性が大事。
例えば、クラスのメンバ変数にアンダースコアを付けてローカル変数と区別する。
#3章 誤解されない名前
名前が「他の意味と間違えられることはないだろうか?」と自問自答する。
積極的に誤解を探しにいく。
限界値を含めるときは、minとmaxを使う。
範囲を指定するとくはfirstとlastを使う。
包含・排他的範囲にはbeginとendを使う。
ブール値の変数やブール値を返す関数の名前を選ぶ時には、trueとfalseの意味を明確に。
危険な例
bool read_password = true;
2つの解釈がある
・パスワードをこれから読み取る必要がある
・パスワードをすでに読み取ってる。
ここでは、readの代わりにneed_passwordを使った方がいい。
###まとめ
最前の名前とは、コード読んでいる人が君の意図を正しく理解できること。
名前を決める前に、反対意見を考えるなどして誤解されない名前かどうかを確認。
単語に対するユーザーの期待にも注意。例:get()やsize()には軽量なメソッドが期待されている。
#4章 美しさ
######優れたコードは「目に優しい」物でなければならない。
3つの原則
・読み手が慣れているパターンと一貫性のあるレイアウトを使う。
・似ているコードは似ているように見せる。
・関連するコードをまとめてブロックにする。
見た目の美しいコードの方が使いやすいのは明らか。
さっと流し読みできれば、誰にとって読みやすいコードができる。
コードの見た目をよくすれば、表面上の改善だけではなくコードの構造も改善できる。
######縦の線を真っ直ぐにしておく
列を整列させれば、コードを読みやすくなることがある。
これをしておけば、タイプミスが見つけやすくなる。
######宣言をブロックにまとめる
→コードの概要を素早く把握してもらうために、グループに分け「単位」を作ればいい。理解しやすいコード。
ただし、重要なのは一貫性のあるスタイルは「正しい」スタイルよりも重要ということ。
正しく読みやすく書いていても、全体的にバラバラのスタイルで書いていれば見にくく読みにくくなる。
####まとめ
一貫性と意味のあるやり方でコードを「整形」すれば素早く簡単にコードを読むことができる。
・複数のコードブロックで同じようなことをしていたら、シルエットも同じような者にする
・コードの「列」を整列すれば、概要が把握しやすくなる
・ある場所でA/B/Cのように並んでいたものを、他の場所でB/C/Aのように並べてはいけない。意味のある順番を選んで常にその順番を守る
・空行を使って大きなブロックを論理的な「段落」に分ける。
#5章 コメントすべきことを知る
######価値のあるコメントと価値のないコメント
######コードからすぐにわかる情報は書かない。
######コメントのためのコメントを書かない。
ひどい名前は、コメントをつけずに名前を変える
→コメントはひどい名前の埋め合わせに使うものではない。それなら、より明確な名前に変える。
では、何をコメントとして書くべきか?
→優れたコメントは「考えを記録する」ためのもの。コードを書いているときの「大切な考え」を書くべき
コードが汚い理由をコメントに書いてもいい。
誰かに修正を促すようなコメント。
######コードの欠陥にコメントをつけよう。
→これからコードをどうしたいのかを自由にコメントに書くこと。
→コードの品質を知らせたり、改善の方向を示すことができる。
######定数にコメントを付ける。
→定数を定義するときには、その定数が何を意味するのか?なぜその「値」を持っているのかという背景が存在する場合が多い。
→定数の名前を決めた時に頭の中で考えていたことをコメントで記録することが大切。
######読み手の立つ場になって考える
######質問されそうなことを想像する。
そこにコメントをつけて回答を明示しておく。
######ハマりそうな罠を告知する。
→コードを使うときに直面する問題を前もって予測し、コメントで告知しておく。
######全体像のコメント
新しいチームメンバにはコードを理解してもらわないといけない。
クラスはどのように連携しているのか?など
これは、コードに書くべきコメントだ。
短い適切な文書でいい。何もないよりマシ。
######要約コメント
低レベルのコードをうまく要約したコメントも大事。
####優れたコード > ひどいコード+優れたコメント
コードを理解するのに役立つものなら何でもいいから書こう!
######ライターズブロックを乗り越える
ライターズブロック=行き詰まってしまって文章が書けないこと
これを乗り越えるためには、とにかく書き始めるしかない。
自分の考えていることを書き出してみて、そのままコメントにする。
コメントを書く作業3ステップ
1、頭の中にあるコメントをとにかく書き出す。
2、コメントを読んで、改善が必要なものを見つける。
3、改善する。
####まとめ
コメントの目的は、コードの意図を読み手に理解してもらうこと。
######コメントすべきではないこと
・コードから抽出できること
・ひどいコードを補う「補助的なコメント」→コメントを書くのではなく、コードを修正する
######コメントすべきこと
記録すべき自分の考え
・なぜコードが他のやり方ではなくこうなっているのかをかく
・コードの欠陥をTODO:、XXX:などの記法を使って示す
・定数の値にまつわる背景
読み手の立場になって考える
・コードを読んだ人が「え?」と思うところを予想してコメントを付ける
・平均的な読み手が驚くような動作は文書化しておく
・ファイルやクラスには「全体像」のコメントを書く
・読み手が細部にとらわれないように、コードブロックにコメントをつけて概要をまとめる。
6章 コメントは正確で簡潔に
どうすれば正確で簡潔に書けるか?
コメントは領域に対する情報の比率が高くなければいけない。
######コメントを簡潔にしておく
3行も使って説明すべきなのか?→1行で説明できるときは1行で。
######曖昧な代名詞を避ける
「それ」や「これ」が何を指しているのかわからない。
例えば、
//データをキャッシュに入れる。ただし先にそのサイズをチェックする。
この場合の、「その」が何を指しているのかわからない。
紛らわしいので、代名詞に名詞を入れてみるとわかりやすくなる。
//データをキャッシュに入れる。ただし先にデータサイズをチェックする。
######歯切れの悪い文章を磨く
コメントを正確にすることと簡潔にすることは両立することが多い。
例
//これまでにクロールしたURLかどうかによって優先度を変える
↓
//これまでにクロールしていないURLの優先度を高くする
下の方が、単純で短く直接的。
######コードの意図を書く
コードの動作をそのまま書いているだけのコメントは✖︎
コードの書いていたときに考えていたことをコメントに書く。
それによって、コードとコメントが矛盾している(いわゆるバグ)が起こっていることに気付きやすい。
コメントが冗長検査の役割を果たしている。
####まとめ
小さな領域にできるだけ多くの情報を詰め込んだコメントを書く
・複数のものを指す可能性がある「それ」「これ」などの代名詞を避ける
・関数の動作はできるだけ正確に説明する
・コメントに含める入出力の実例を慎重に選ぶ
・コードの意図は詳細レベルではなく高レベルで記述する
・よくわからない引数にはインラインコメントを使う。
・多くの意味が詰め込まれた言葉や表現を使ってコメントを簡潔に保つ。
#7章 制御フローを読みやすくする
######コードの制御フローを読みやすくする
条件やループなどの制御フローはできるだけ「自然」にする。コードの読み手が立ち止まったり、読み返したりしないように書く!
######条件式の引数の並び順
if (length >= 10)
または
if (10 =< length)
最初の方が読みやすいのは明らか。
これには指針がある。
左側→「調査対象」の式。変化する。
右側→「比較対象」の式。あまり変化しない。
英語の用法と同じだ。
######if/elseブロックの並び順
並び順には優劣がある
・条件否定形よりも肯定系を使う。例えば、if(!debug)ではなく、if(debug)を使う。
・単純な条件を先に書く。ifとelseが同じ画面に表示されるので見やすい。
・関心を引く条件や目立つ条件を先に書く
状況によって衝突する場合もあるので、その場合は自分の判断で。
######三項演算子
1行でまとまるメリットもあるが、反対に読みにくいしデバッガでステップ実行するのが難しい。
行数を短くするよりも他の人が理解するのにかかる時間を短くする
######基本的にはif/else文を使う!三項演算子はそれによって簡潔になるときにだけ使う!
######関数から早く返す
関数で複数のreturn文を使ってはいけないと思っている人がいるけど、それは間違い。
関数から早く返すのはいいこと。
######ネストを浅くする
ネストの深いコードは理解しにくい。
変更するときには、コードを新鮮な目で見る。一歩下がって全体を見る。
実行の流れを追えるか?
構成要素を使っていると、コードを追うのが難しくなる。
スレッド→どのコードがいつ実行されるのかよくわからない。
シグナル・割り込みハンドラ→他のコードが実行される可能性がある。
例外→いろんな関数呼び出しが終了しようとする
これらの構成要素を使うことで、コードが読みやすくなったり冗長性が低くなったりすることもある反面
うまく使わないとコードの行方を見失ってします。
# 8章巨大な式を分割する
巨大な式は飲み込みやすい大きさに分割する
「頭がいい」コードに気をつける。あとで、他の人がコードを読むときにわかりにくくなる。
巨大な式を一度に理解しようとすると難しい。
そのために行う最も簡単な方法は「説明変数」を導入すること
大きな式の値を保持する説明変数には3つの利点がある
・巨大な式を分割できる
・簡潔な名前で式を説明することでコードを文書化できる
・コードの主要な「概念」を読み手が認識しやすくなる
そのほかには、ド・モルガンの法則を使ってロジックを操作する方法もある。
複雑なロジックを見かけたら、積極的に分割する!
9章 変数と読みやすさ
変数を削除する
コードは読みやすくならない変数を削除する。→コードは簡潔で理解しやすいものになる。
変数のスコープを縮める。
グローバル変数は避けるのは、正しい。→どこでどのように使われるのか追跡するのが難しい。
グローバル変数に限らず、全ての変数の「スコープを縮める」のはいい考え。
変数のことが見えるコード行数をできるだけ減らす。
アクセスはできるだけ制限して変数のことが見えてしまうコードを減らすのがいいとされている
→なぜ?一度に考えなければいけない変数を減らせるから
変数は一度だけ書き込む
→「永続的に変更されない」変数は扱いやすい。
変数の操作する場所が増えると、現在値の判断が難しくなる
####まとめ
プログラムの変数はすぐに増えるのでいずれ追跡できなくなる
変数を減らしてできるだけ軽量にすればコードは読みやすくなる
・邪魔な変数を削除する
・変数のスコープをできるだけ小さくする→変数の数行のコードからしか見えない位置に移動する。
・一度だけ書き込む変数を使う→変数に一度だけ値を設定すれば(あるいは、const,)コードが理解しやすくなる。
#10章 無関係の下位問題を抽出する
エンジニアリングとは、大きな問題を小さな問題に分割してそれぞれの解決策を組み立てること。
この章は、無関係の下位問題を積極的に見つけて抽出することだ。
1、関数やコードブロックを見て「このコードの高レベルの目標は何か?」と自問する。
2、コードの各行に対して「高レベルの目標に直接的な効果があるのか?無関係の下位問題を解決しているのか?」と自問する。
3、無関係の下位問題を解決しているコードが相当量あれば、それらを抽出して別の関数にする。