第1章 理解しやすいコード
コードを書く原則:
- コードは理解しやすくなければならない。理解しやすいコードは優れた設計やテストしやすさにつながることが多い
- コードは他人(未来の自分にも)が最短時間で理解できるように
- 短いコードより、理解するまでにかかる時間を短くするほうが大切
第2章 名前に情報を詰め込む
1.明確な単語を選ぶ
GetPageよりDownloadPage、FetchPageほうがいい
もっと「カラフル」な単語を探す
気取った言い回しよりも明確で正確な方がいい
例:
単語 | 代替案 |
---|---|
send | deliver, dispatch, announce, distribute, route |
find | search, extract, locate, recover |
start | launch, create, begin, open |
make | create, set up, build, generate, compose, add, now |
2.tmpやretvalなどの汎用的な名前を避ける(あるいは、使う状況を選ぶ)
エンティティの値や目的を表した名前を選ぼう
- retval:「これは戻り値」以外の情報がないので、変数の値を表すような名前を使おう
- tmp:生存期間が短くて、一時的な保管が最も大切な変数にだけ使おう。(他の関数に渡されたり、何度も書き換えられたりしない)
- ループイテレータ(i,j,k,iter):インデックスやループイテレータの以外で使わないで
-
汎用的な名前使うとき、それ相応の理由用意しよう
抽象的な名前よりも具体的な名前を使う
メソッドの動作をそのまま表す!
例1:DISALLOW_EVIL_CONSTRUCTORS(ClassName)
背景:C++のクラスでは、コピーコンストラクタと代入演算子を再定義しないと、デフォルトの設定が使われて、メモリリークなどの問題につながる可能性あるのため、Googleはこうした「悪の」コンストラクタを許可しない規則を作り、まくろをつかって対応してる。
説明:「EVIL(悪の)」という言葉は必要以上に強い意志を感じてしまう。このマクロが「許可していないもの」を明確にするほうが大切だ。DISALLOW_COPY_AND_ASSIGN(ClassName)に変更しました。
例2:--run_locally
背景:--run_locallyという名前のコマンドオプションがあった。このオプションをつけると、プログラムがデバッグ情報を印字するようになる。
説明:--run_locallyに環境名が入っているのが問題だ。--extra_loggingという名前のほうが直接的で明確だ。
接尾辞や接頭辞を使って情報を追加
もし絶対に知らせなきゃいけない大切な情報があれば、「単語」を変数名に追加すればいい。
値の単位
変数名に単位を入れるといい。例:
関数の仮引数 | 単位追加した仮引数 |
---|---|
Start(int delay) | delay_secs |
CreateCache(int size | size_mb |
ThrottleDownload(float limit) | limit_kbps |
Rotate(float angle) | degrees_cw |
その他の重要な属性を追加する
- 危険や注意喚起する情報を追加したほうがいい。
プログラムの受信するデータが安全ではないことには、untrustedUrlやunsafeMessageBodyなどの変数名を使って、データは暗線にする関数を呼び出したあとは、変数名をtrustedUrlやsafeMessageBodyにするといい - 変数の意味を理解してもらわなければ困るところに属性を追加。
他の例:
状況 | 変数名 | 改善後 |
---|---|---|
password はプレインテキストなので、処理する前に暗号化すべきである | password | plaintext_password |
ユーザが入力したcommentは表示する前にエスケープする必要がある | comment | unescaped_comment * |
htmlの文字コードをUTF-8に変更 | html | html _utf8 * |
入力されたdataをURLエンコードした | data | data_urlenc |
*すべての変数名にunescaped_や_utf8などの属性を追加することではない。変数の意味を間違えてしまったとき、バグになりそうなところにだけ使う。
ハンガリアン 記法/イングリッシュ記法
すべての変数名接頭辞に「型」をつける厳密で規律のあるシステムだ。
Microsoft社で広く使われていた命名規則だが、この本に提唱しているの規律のゆるくて、必要な時にだけ変数の大切な属性を見つけ出して、それを読みやすくして名前に追加するイングリッシュ記法です。
名前の長さを決める
スコープが小さければ短い名前でもいい
識別子の「スコープ」(その名前が見えるコード行数)が小さければ、すべての情報(変数の型、初期値、廃棄方法など)が見えるので、変数の名前は短くていい。
長い名前を入力するのは問題じゃない
プログラミングに使うテキストエディタには「単語補完」機能がついている。
頭文字と省略形
新しいメンバ理解できないならだめだ。Str、docなどが大丈夫だ。
不要な単語を投げ捨てる
名前に含まれる単語を削除しても情報が全く損なわれないなら、すててもいい。例:ConvertToString()→ToString()、DoServeLoop()→ServeLoop()
名前のフォーマットで情報を伝える
- アンダースコア・ダッシュ・大文字を使って、名前に情報を詰め込むこともできる
- プログラミング言語によって使えるフォーマット規約は違ってくる。
誤解されない名前
例1:filter()✖
filterは「選択する」のか、「除外する」のかわからない曖昧な言葉だ。
「選択する」=> select();
「除外する」=> exclude();
例2:Clip(text,length)✖
Clip()の2つ動作考えられる:
- 最後からlength文字を削除する(remove)
- 最大length文字まで切り詰める(truncate)
あとは length ✖ => max_length ✖ => mac_chars 〇
限界値含めるときはminとmaxを使う
「off-by-oneエラー」などのバブを避けるため、CART_TOO_BIG_LIMIT✖.
限界値を明確にするには、名前の前にmax_やmin_をつけよう。
範囲を指定するときはfirstとlastを使う
包含的な範囲(終端を範囲に含める)を表すのであれば、firstとlastを使う
例:set.PrintKeys(first="Bart",last="Maggie")
包含/排他的範囲にははbeginとendを使う
endは少し曖昧だけど、英語には「ちょうど最後の値を超えたところ」を意味する簡潔な言葉ないので最善の選択になった。
ブール値の名前
- 頭にis・has・can・shouldなどをつけてわかりやすい。
- 否定形を避ける
ユーザの期待に合わせる
例3:get*()
getで始まるメソッドはメンバ値を返すだけの軽量アクセサであるという規約に守る!
例4:list::size()
例5:複数の名前を検討する
高いトラフィックのウェブサイトではウェブサイトの変更によってビジネスがどのぐらい改善できるかを調べる「実験」をすることが多い。
実験用の設定ファイル
experiment_id:100
description:"font-size up to 14pt"
...
既存の設定ファイルを他のじっけても使えるようにしたい(「プロトタイプ継承」パターン)
ほかの実験用の設定ファイル
experiment_id:101
the_other_experiment_id_I_want_to_reuse:100
[以下、変更が必要な情報だけ書き換える]
...
「the_other_experiment_id_I_want_to_reuse」の名前候補:
1.template 誤解:「本物」の実験ではない
2.reuse 誤解:100回再利用、resue_idの誤解:再利用idは100
3.copyだけ✖ => copy_experiment
4.inheritだけ✖ => inherit_from_experiment_id
第4章 美しさ
3つの原則
- 読み手が慣れているパターンと一貫性のあるレイアウトを使う
- 似ているコードは似ているように見せる
- 関連するコードをまとめてブロックにする
一貫性のある簡潔な改行位置
似ているコードは長すぎ折返しの位置固定
メソッドを使った整列
何度も登場してる邪魔をしてる文字列などのことにはヘルパーメソッドを使う必要ある。
縦の線を真っ直ぐにする
縦の線は「視覚的な手すり」になれば、流し読み柄国で来るようになる
でももし整列やその維持に手間になるようだったら、その時止めればいい
一貫性と意味のある並び
ランダムに並べるのではなく、意味がある順でといい
例:
- 対応するHTMLフォームの
<input>
フィールドと同じ並び順 - 「最重要」なものから重要度順
- アルファベット順
宣言をブロックにまとめる
コードの概要を把握しやすいため、空行を使って、グループや階層を1つの単位としてコードを分ける。
コードを「段落」に分割する
段落ごとに要約コメントを追加する。
個人的な好みと一貫性
一貫性のあるスタイルはただしスタイルよりも大切だ。
第5章 コメントすべきことを知る
コメントの目的は、書き手の意図を読み手に知らせること
コメントするべきでは「ない」こと
- コードからすぐにわかることをコメントに書かない
- コメントのためのコメントをしない
- ひどい名前はコメントを付けず名前を変える(優れたコード>ひどいコード+優れたコメント)
自分日考えを記録する
- コードに対する大切な考えを記録しなければならない
- コードの欠陥にコメントつける(コードの品質や状態を知らせたり、更には改善策の方法を示したりできるものを書く)
- よく使う記法
記法 典型的な意味 TODO: 後で手を付ける FIXME: 既知の不具合があるコード HACK: あまりきれいじゃない解決策 XXX: 危険!大きな問題ある
- よく使う記法
- 定数にコメントをつける(コメントをつけて改善できる定数は多い、定数の値を決めたときに考えていたことを記録)
読み手の立場になって考える
- 質問されそうなことを想像する
- ハマりそうな罠を告知する(このコードをみてびっくりすること、間違えて使う可能性など)
- 全体像のコメント(ファイルやクラスの全体像。短い適切な文章でもいい、何もないよりはマシだ)
- 要約コメント(例:関数内部にある大きな「塊」につけてもいい)
- (WHATでも、WHYでも、HOWでも)コードを理解するのに役立つものなら何でも良いから書こう。
ライターズブロックを乗り越え
コメントを書く手順
- 頭にあるコメントをとにかく書き出す
- コメントを読んで完全が必要あるものを見つける
- 改善する
コメントは正確で簡潔に
コメントを簡潔しておく
コメントは領域に対する情報の比率が高くなければいけない
曖昧な代名詞を避ける
「それ」「その」などの代名詞は紛らわしいようであれば、「名詞」を「代名詞」に「代入」してみるといい
歯切れの悪い文章を磨く
関数の動作をできるだけ正確に記述する
入出力のコーナーケースに実例を使う
視覚化しやすいため、実例を使ってより詳しく説明
コードの意図を書く
「名前付き引数」コメント
よくわからない引数を説明するときインラインコメント(java,
C++)使って書く(このようなコメント必要ないことも多いい)
例:
void Connet(int timeout, bool use_encryption){...}
//引数をコメントをつけて関数を呼び出す
Connect(/*timeout_ms = */ 10, /*use_encryption = */ false);
情報密度の高い言葉を使う
多くの意味が詰め込まれた言葉や表現を使って、コメントを簡潔に保つ