コードの基本定理
- コードは他人が読んで短時間で理解できなければならない
- コードは短い方がもちろん良いが、一番は理解するまでの時間を短くすること
命名規則
名前に意味を持たせる。
-
明確な単語を選び、汎用的な名前を避け、より具体的な名前を使う
-
接尾辞や接頭語を使用して情報を追加する
-
類語辞典でより明確な単語を選択する
例) send
・代替案:deliver, dispatch, announce, distributes, routeなど
- メソッド内で計算するためだけに登場する変数は簡単な名前でもOK
例)tmp
if (right > left){
tmp = right;
right = left;
left = tmp;
}
上記のtmpはこのメソッド内で一時的に情報を保管するだけなので、具体的な命名にしなくてもOK
- ただ、以下の例はNG
String tmp = user.name();
tmp += " " + user.phone_number();
tmp += " " + user.email();
template.set("user_info", tmp);
上記の例では最後の行で引数としてtmpを使用しており、この引数の中身が何を意味しているのか分からないのでtmpを使用するのは好ましくない。
-
ループイテレータはi,k,j,iterなどでOK
-
値の単位や状態を表す言葉を変数名に入れる
-
省略形は使わない
BackEndManager → BEManager
FormatString → FormatStr
-
スコープの大きな変数には長い名前をつける
-
大文字やアンダースコアには意味を含める
誤解されない命名をする
- 曖昧な言葉は使用しない
例)length
・どんな長さなのかが分からない
最大文字数 → max_length
・何がmax_length
なのか?
バイト数、文字数、単語数
→ 文字数なのであれば、max_char
が好ましい
-
限界値を格納する変数にはmaxやminを使用する
-
範囲を指定する時はfirstとlastを使用する
-
ブール値のtrue,falseの意味を明確にする
・is, has, can, shouldなどをつけると分かりやすい -
複数の名前を検討する
・誤解を招きにくい命名をする
コードの美しさ
・コードは目に優しくなければならない
- インデントを整える
・改行に一貫性を持たせる
・縦の列を揃える
・ブロックにまとめる
・適切なところで段落を改行する
コメント
・コメントの目的:書き手の意図を読み手に知らせること
コメントするべきでないこと
-
コードを見たらすぐに分かること
-
コメントのためのコメントをしない
-
分かりづらい名前はコメントで注意書きするのではなく、そもそも名前を変更する
コメントした方が良いこと
-
コードを書いた背景(なぜこのコードになったのか、他のロジックもあるがなぜこの書き方なのか)
-
コードの欠陥(改善すべき場合、これからどうするかを書く)
-
定数にはコメントをつける
読み手の立場に立って考える
-
質問されそうなことを考える
-
全体像・要約をコメントとして残す
-
ライターズブロックを乗り越える
・まずは頭の中のことをコメントとして残す
コメントを簡潔に書くために
-
曖昧な代名詞を避ける
-
動作は正確に表現する
-
文章が長くなってしまったら情報密度の高い言葉を使う
制御フロー
-
条件式は左側は調査対象の式、右側は比較対象の式
・左側:調査対象の式、変化する
・右側:比較対象の式、あまり変化しない -
if / else
・条件文は肯定形を使用する
・単純な条件を先に書く
・三項演算子は簡潔に分かりやすくなるケースにのみ使用する -
do ~ whileループはwhileのみのループに書き直せる場合が多い
-
複数のreturnを使用するのはOK
-
ネストは浅くする
・入れ子が深いと読みづらい
巨大な式は分割する
- 説明変数を使う
if line.split(',')[0].strip() == "root" {}
↓
username = line.split(':')[0].strip();
if username == "root" {}
- 要約変数
if (request.user_id == document.owner_id){
// ユーザはこの文書を編集できる
}
if (request.user_id != document.owner_id){
// ユーザはこの文書を編集できない
}
- 短絡評価の悪用
assert((!(bucket = FindBucket(key))) || !bucket->IsOccupied());
↓
bucket = FindBucket(key)
if (bucket != NULL) assert(!bucket->IsOccupied());
- 巨大な分は要約変数を関数の上部に抽出する
変数と読みやすさ
- 一時変数が役に立たない場合
now = datetime.datetime.now()
root_message.last_view_time = now
このnowを他の所で使用していない場合、
root_message.last_view_time = datetime.datetime.now()
でも伝わるからOK
- 変数のスコープを縮める
・大きなクラスを小さなクラスに分割する
無関係な下位問題を抽出する
-
関数やコードブロックを見て「このコードの高レベルの目標は何か?」と自問する
-
コードの各行に対して「高レベルの目標に直接的に効果があるのか?あるいは無関係の下位問題を解決しているのか」を自問する
-
無関係の下位問題を解決しているコードが相当量あれば、それらを抽出して別の関数にする
-
コードが独立していれば後から機能追加や修正する場合も楽になる
-
汎用的なコードは基本的で幅広く応用可能なので複数の場面で再利用できる
一度に一つのことを
- コードは一つずつタスクを行うようにしなければならない
一度に一つのタスクをするための手順
①コードをが行なっているタスクを全て列挙する
②タスクをできるだけ異なる関数に分割する
- タスクは分割したメソッドとして使用する
コードに思いを込める
- コードは簡単な言葉で書くべき
コードをより明確にする手段
1. コードの動作を簡単な言葉で同僚にもわかるように説明する
2. その説明の中で使っているキーワードやフレーズにも注目する
3. その説明に合わせてコードを書く
-
否定形が少ないロジックの方が分かりやすい
-
解決策を言葉で説明する
短いコードを書く
-
最も読みやすいコードは何も書かれていないコードである
-
プロジェクトに欠かせない機能を過剰に見積もってしまうと多くの機能が完成しないか全く使われないかアプリケーション自体を複雑にしてしまう
-
プロジェクトが成長して規模が大きくなったとしても、コードをできるだけ小さく軽量に維持するしかない
意識すること
・汎用的なユーティリティコードを作って重複コードを削除する
・未使用のコードや無用の機能を削除する
・プロジェクトをサブプロジェクトに分割する
・コードの「重量」を意識する
-
ライブラリの機能を熟知して実際に活用する
-
不必要な機能をプロダクトから排除する
-
最も簡単に問題を解決できるような要求を考える
-
定期的に全てのAPIを読んで標準ライブラリに慣れ親しんでおく
テストと読みやすさ
- 他のプログラマが安心してテストの追加や変更ができるようにテストコードを読みやすくする
テストコードが恐ろしく大きい場合起こること
-
本物のコードを修正するのを恐れる
-
新しいコードを書いたときにテストを追加しなくなる
-
大切ではない詳細はユーザから隠し、大切な詳細は目立つようにする
-
エラーメッセージはできるだけ役立つようにする
-
テストには最も簡潔で単純な値を選ぶ
-
テストをしやすいようにコードを設計する
やりすぎに注意
・テストのために本物のコードの読みやすさを犠牲にしてしまう
・テストのカバレッジを100%にしないと気が済まない
・テストがプロダクト開発の邪魔になる
→こういうのはよくない