0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

本「リーダブルコード」の要約

Posted at

命名規則

明確な単語を選ぶ

「GetPage」だと何も分からない

  • このメソッドはページをどこから取ってくる?
  • ローカルキャッシュから?データベースから?
  • インターネットから取ってくるなら、FetchPage()やDownloadPage()のほうが明確

Size()メソッドは何を返すか分からない

  • ツリーの高さ?ノードの数?メモリ消費量?
  • それぞれ、Height(), NumNodes(), MemoryBytes()になる

Stop()でもいいけど、もっと明確な名前をつけれる

  • 取り消しができない重い操作ならKill()
  • あとからResume()できるなら、Pause()

tmp や retvalなどの汎用的な名前を避ける

  • 2乗の合計を返すなら、sum_squaresなど
  • 一時的に保管する目的であればtempを使ってもいい

ループイテレータも明確な単語に

  • i・j・k・iterなどの名前は、イテレータが複数ある時に複雑になる
  • club_i, members_i, users_i または ci, mi, uiなどする

名前に情報を追加する

  • string id: // af84ef845cd8 → IDのフォーマットが大事なら、hex_idが適切

値の単位

  • 変数名に単位を入れる
  • start → start_ms
  • delay → delay_secs
  • limit → max_kbps
  • angle → degrees_cw

その他の重要な属性を追加する

  • セキュリティ問題の多くは、プログラムの受診するデータが安全でないことが原因で発生している
    • untrustedUrl や unsafeMessageBody などの命名をする
    • データを安全にしたら、 trustedUrl や safeMessageBodyにするといい
  • 具体
    • password → plaintext_password
    • comment → unescaped_comment
    • html → html_utf8
    • data → data_urlenc

名前の長さの決め方

  • スコープが小さければ短い名前でもいい
  • 単語保管機能を使えば、長い命名でも大丈夫
  • プロジェクト固有の省略形の名前にしない
  • 後から入った人が理解できる省略形なら大丈夫
  • 不要な単語を投げ捨てる
    • ConvertToString → ToString
    • DoServerLoop → ServerLoop

曖昧な名前をつけない

fileter()はどんな値が返ってくるか曖昧すぎる
- 選択する → select()
- 除外する → filter()

Clip(text,length) も最後からlength文字を削除するのか、最大length文字まで切り詰めるのかわからない
- Truncate(text,length)に変えるほうがいい
- そしてlengthもmax_length、さらに言えば、単位をつけてmax_charsにするといい

限界値を含めるときはminとmaxを使う

  • 未満なのか以下なのかわからないため、max_、min_を使う

範囲を指定するときはfirstとlastを使う

  • stopは複数の意味に解釈できる
    • lastをつかあえば、抱合していることが明確になる

包含/排他的範囲にはbeginとendを使う

  • endは包括的を意味する

ブール値の名前

  • read_passwordだと二つの意味がありえる
    • パスワードをこれから読み取る必要がある
    • パスワードをすでに読み取っている
    • → need_password, user_is_autheticatedを使う
  • 頭にis・has・can・shouldをつける
    • 名前を否定的にするのは避ける
      • disabled_ssl = false → use_ssl = true
      • 肯定形にしたほうが声にだして読みやすい

説明変数を使う

  • 式を表す変数を使う
username = line.split(":")[0].strip();

コードを「段落」に分割する

def suggest new_friends(user, email_password);
 # ユーザーの友達のメールアドレスを取得
 friends = user.friend();
 friend_emails = set(c.email for in friends);

 # ユーザーのメールアカウントからすべてのメールアドレスをインポートする
 contacts - import_contacts(user.email, email_password)
 contact_emails

コメント

自分の考えを記録する

// このデータだとハッシュテーブルよりもバイナリツリーのほうが40%早かった
  • コメントから情報を得ることができるので、下手に最適化しようとして無駄に時間を使う必要がなくなる

コードの欠陥にコメントをいれる

  • 改善が必要なときは以下のように書いておく
// TODO: もっと高速なアルゴリズムをつかう
  • コードが未完成のときは以下のように書いておこう
TODO(グラ): JPEG以外のフォーマットに対応する
  • よく使う記法
    • TODO : あとで手を付ける
    • FIXME : 既知の不具合があるコード
    • HACK : あまりキレイじゃない解決策
    • XXX : 危険!大きな問題がある

定数にコメントをつける

  • その定数が何をするのか、なぜその値を持っているのか「背景」が存在する場合が多い
// 合理的な限界値。人間はこんなに読めない
const int MAX_RSS_SUBSCRIPTIONS = 1000;

image_quality = 0,72; // 0.72ならユーザーはファイルサイズと品質の面で妥協できる

ハマりそうな罠を告知する

// 実行時間は0(タグの数 * タグの深さの平均)なので、ネストの深さに気を付ける

要約コメントをつける

def GenerateUserReport():
  #  このユーザのロックを獲得する
  ...
  # ユーザの情報をDBから読み込む
  ...

制御フローを読みやすくする

条件式の引数の並び順

  • 左側
    • 調査対象の式。変化する
  • 右側
    • 比較対象の式。あまり変化しない
if(age >= 10){}
while(bytes_expected < bytes_expected) {}
  • 「もし君が18歳以上ならば」という順番が自然
    • 「もし君の年齢が年齢以下ならば」というのは不自然

if / elseブロックの並び順

  • 条件は否定形よりも肯定形を使う。例えばif(!debug)ではなく、if(debug)を使う。
  • 単純な条件を先に書く。ifとelseが同じ画面に表示されるので見やすい
  • 関心を引く条件や目立つ条件を先に書く
if(a == b) {
	// 第一のケース
} else {
	// 第二のケース
}

以下のように書くのは同じ

if(a != b) {
	// 第二のケース
} else {
	// 第一のケース
}

関数から早く返す

  • 関数で複数のreturn文を使ってもいい

ネストを浅くする

  • ネストの深いコードは理解しにくい

早めに返してネストを削除する

  • ネストを削除にするには「失敗ケース」をできるだけ早めに関数から返せばいい

ループ内部のネストを削除する

  • 早めに返す技法はいつでも使えるわけではない。
  • 早めに返すのと同じようなことをループ内部で行うには、continueを使う
for (int i = 0; i < result.size(); i++) {
	if(result[i] == NULL) continue;
	non_null_count++;
	if(result[i]->name == "") continue;
	count << : "Text" << endl;
}

変数の取り扱い

不要な変数の切り出しを削除する

  • 変数が多いと変数を追跡するのが難しくなる
  • 変数のスコープが大きいとスコープを把握する時間が長くなる
  • 変数が頻繁に変更されると現在の値を把握するのが難しくなる

役に立たない一時変数

now = datetime.datetime.now()
root_message.last_view_time = now
  • 複雑な式を分割していない
  • より明確になっていない。datetime.datetime.now()のままでも十分に明確
  • 一度しか使っていないので、重複コードの削除になっていない

中間結果を削除する

  • 変数 index_to_remove は、中間結果を保持するためだけに使っている
var remove_one = function(array, value_to_remove) {
	var index_to_remove = null;
	for (var i = 0; i < array.length; i += 1) {
		if(array[i] === value_to_remove) {
			index_to_remove = i;
			break;
		}
	}
	if(index_to_remove !== null) {
		array.splice(index_to_remove, 1);
	}
}
  • 結果をそのまま使えば、このような変数は削除できる
var remove_one = function(array, value_to_remove) {
	for (var i = 0; i < array.length; i += 1) {
		if(array[i] === value_to_remove) {
			array.splice(i,1);
			return;
		}
	}
}
  • 関数から早く返すことで、index_to_removeをすべて削除できた。
  • タスクはできるだけ早く完了するほうがいい

制御フロー変数を削除する

boolean **done** = false;
while(/* 条件 */ && !**done**) {
	...
	if(...) {
		done = true;
		continue;
	}
}
  • 制御フロー変数は削除できる
while(/* 条件 */) {
	...
	if(...) {
		break;
	}
}

変数のスコープを縮める

  • クラスのメンバ変数を減らす
    • メソッドをできるだけ static にするといい
    • staticを使えば、メンバ変数とは関係ないことがよくわかる

変数は一度だけ書き込む

  • const使うべき
  • 変数が絶えず変更されると、値を追跡する難易度が高い

汎用コードをたくさんつくる

  • ReadFileToString() や format_pretty()など、広く適用可能な関数を、複数のプロジェクトで再利用する
  • 特別なディレクトリ(例: util)を用意する

一度に複数のタスクを行わない

var vote_changed = function (old_vote, new_vote) {
	var score = get_score();
	
	if(new_vote !== old_vote) {
		...
	}

	if(new_vote === "Up") {
		score += (old_vote === "Down" ? 2 : 1);
	} else if (new_vote === "Down") {
		score -= (old_vote === "Up" ? 2 : 1);
	} else if (new_vote === "") {
		score -= (old_vote === "Up" ? -1 : 1);
	}
	set_score(score);
}
  • たった1つのこと(スコアを更新すること)をしているように見えて、実際には一度に2つのタスクを行っている
  1. old_vote と new_voteを数値に「パース」する
  2. score を更新する

2つのタスクを別々に解決すれば、読みやすいコードになる

// 最初のタスク(投票を数値にパースする)を解決したもの
var vote_changed = function (old_vote, new_vote) {
	if(vote === "Up") {
		return +1;
	}

	if(vote === "Down") {
		return -1;
	}

	return 0;
}

// 2つめのタスク(スコアの更新)を解決している
var vote_changed = function (old_vote, new_vote) {
	var score = get_score();
	score -= vote_value(old_vote); // 古い値を削除する
	score += vote_value(new_vote); // 新しい値を追加する
}
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?