はじめに
- 読もう読もうと思って読んでなかった。
- 「他人が理解できるコードが読みやすいコード」が理解しやすいコードである。とは?具体的に?
- 現在の社内システムをリファクタリング・チューニングするにあたってリファクタリングのイディオムから段々と抽象化していき最終的にruby(rails)システムで使われているデザインパターンを学習予定。
- 「おっ」と思ったものだけまとめ
第二章 名前に情報を詰め込む
2.1 明確な単語を選ばなければならない
(例)「get」は明確な単語ではない
def GetPage(url)
...
ページをどこから取ってくるのだろうか?データベースなのか?ローカルキャッシュから?
def FetchPage(url)
...
or
def DownloadPage(ur)
...
2.2 tmpやretvalなどの汎用的な単語は避ける
(例)戻り値にretvalを使っている
var euclidean_norm = function(v){
var retval = 0.0;
for (var i = 0; i < v.length; i += 1)
retval += v[i] * v[i];
return Math.sqrt(retval);
};
いい名前が思いつかない場合に、戻り値にretvalとつけたくなる。しかし
sum_squares += v[i];
//この場合、2乘がないバグだ!と気付きやすくなる
(例)tmp
if (right < left){
tmp = right;
right = left;
left = tmp;
}
この場合tmpという名前で全く問題ない。この変数の目的は、情報の一時保存である。しかも生存期間は数行なので問題ない。
2.4名前に情報を追加する
値の単位
var start = (new Date()).getTime();
...
var elapsed = (new Date()).getTime() - start;
document.writeln("読み込み時間:" + elapsed + "秒");
これはうまく動かない。getTime()が秒ではなく、ミリ秒を返すから。変数名に_msを追加すれば明確になる。
var start_ms = (new Date()).getTime();
...
var elapsed_ms = (new Date()).getTime() - start_ms;
document.writeln("読み込み時間:" + elapsed_ms / 1000 + "秒");
使い所は、変数の意味を間違えてしまった時にバグになりそうなところだけに使うことが大切。
2.5名前の長さを決める
識別子の「スコープ」(その名前が「見える」コードの行数)が小さければ、多くの情報を詰め込む必要はない。
if (debug) {
map < string,int > m;
LookUpNamesNumbers(8m);
Print(m);
}
mという変数にはあまり情報が含まれていないが、コードを理解するのに必要な情報がすぐそばにあるからだ。
第三章 誤解されない名前
鍵となる考え
名前が「他の意味と間違えられることはないだろうか?」と何度も自問自答する。
(例)
lengthという名前はNG。
max_lengthにした方が明確になる。
- 上下の限界値を決めるときは、max_,min_を前につけるとok。
- 包含的範囲であれば、first,lastを使うとok。
- 包含、排他的範囲であればbegin.endがイディオムなのでそれを使う。
- ブール値に名前をつけるときは、それがブール値だとわかるように
- is,hasなどの単語を使う。
- disable_sslのような否定形は避ける。
第四章 美しさ
4.1 なぜ美しさが大切なのか?
プログラミングの時間のほとんどがコードを読む時間だから。
第五章 コメントすべきすることを知る
鍵となる考え
コメントの目的は、書き手の意図を読み手に知らせること
通常は補助的なコメントが必要になることはない
「優れたコード > ひどいコード + 優れたコメント」
5.3 読み手の立場になって考える
- 「他の人」というのは、プロジェクトのことを熟知していない人のことである。
- 「このコードを見てびっくりすることはなんだろう?」「どんな風に間違えて使う可能性があるだろう?」と自分に問いかけること
- コメントの目的とは、コードの意図を読み手に理解してもらうことである。
第六章 コメントは正確で簡潔に
6.2 曖昧な代名詞を避ける
//データをキャッシュに入れる。ただし、先にそのサイズをチェックする。
「その」が指しているのは、「データ」かもしれないし「キャッシュ」かもしれない。その場で理解できるようにする。
6.5 入出力のコーナーケースに実例を使う。
//'src'の先頭や末尾にある'chars'を除去する。
String Strip(String src, String chars){...}
//...
//実例:String Strip("abba/a/ba", "ab")は"/a/"を返す
String Strip(String src, String chars){...}
第七章 制御フローを読みやすくする
鍵となる考え
条件やループなどの制御フローはできるだけ「自然」にする。コードの読み手が立ち止まったり読み返したりしないように書く。
7.1 条件式の引数の並び順
左側 | 右側 |
---|---|
「調査対象」の式。変化する | 「比較対象」の式。あまり変化しない |
7.3 三項演算子
鍵となる考え
行数を短くするよりも、他の人が理解するのにかかる時間を短くする。
7.7 ネストを浅くする
鍵となる考え
変更する時にはコードを新鮮な目で見る。一歩下がって全体を見る。
早めに返してヌストを削除する
「失敗ケース」をできるだけ早く返す。
第八章
8.2 要約変数
式を説明する必要がない場合でも、式を変数に代入しておくと便利。
if (request.user.id == document.owner_id){
// ユーザはこの文章を編集できる
}
final boolean user_owns_document = (request.user.id == document.owner_id)
if (user_owns_document) {
// ユーザはこの文章を編集できる
}
user_owns_documentを最上部に定義したことで、「この関数で参照する概念」を事前に伝えることができるようになった。
第十章 無関係の下位問題を抽出する
10.3 その他の汎用コード
ajax_post({
url: 'http://exmaple.com/submit',
data: data,
on_success: function (response_data){
var str = "{\n";
for (var key in response_data){
str += " " + key + " = " + response_data[key] + "\n";
}
alert(str + "}");
});
このコードの高レベルの目標は「サーバをAjaxで呼び出してレスポンスを処理する」である。しかしこのコードの大部分は「ディクショナリを綺麗に印字する。」という「無関係の下位問題」を解決しようとしている。
このコードを抽出して、format_pretty(obj)のような関数にする。
var format_pretty = function(obj){
var str = "{\n";
for (var key in obj){
str += " " + key + " = " + obj[key] + "\n";
}
return str + "}";
};
下位問題を抽出し関数化すると、「コードが独立していれば、format_pretty()の改善が楽になる」という恩恵もある。
所感
・rubyやrailsで使うActiveRecordは用意してくれるメソッドが優秀なので、「他人が見てもわかりやすい」をはじめに、変数名や一つのメソッドで複数のことをしないように意識しないとすぐにFatになる。
・条件式の左辺に変化する値を置くというのは、なんとなく流行っていたけど、言語化してコードに一貫性を持たせる。
・「短いコードより、一貫性のあるコード」