ツヨシのブログ

技術的な事とか日常の事とか徒然なるままに

スポンサーリンク

【読書】リーダブルコードを読んで行く(2章:名前に情報を詰め込む)

スポンサーリンク

こんにちは、ツヨシです。 前回に続きリーダブルコードの2章についてのまとめになります。

ginga0118.hatenablog.com

ginga0118.hatenablog.com

2章 名前に情報を詰め込む

  • 名前は短いコメントである。
    • 明確な名前を選ぶ
    • 汎用的な名前を避ける
    • 抽象的な名前よりも具体的な名前を選ぶ
    • 接尾語や接頭語を使って情報を追加する
    • 名前の長さを決める
    • 名前のフォーマットで情報を伝える

2.1. 明確な単語を選ぶ

  • getPage()という関数の場合、getが明確な単語ではない。ページをダウンロードするのであればdownloadPage()の方が良い。
  • size()といったサイズを返す関数の場合、なんのサイズかは不明確である。height?, number?
  • stop()などは何をどうしたいのかわからない。タスクを消すならkill、リジュームできるならpauseなど
単語 代替案
send deliver, dispatch, announce, distribute, route
find search, extract, locate, recover
start launch, create, begin, open
make create, set up, build, generate, compose, add, new

point:気取った言い回しよりも、明確で正確な方が良い

2.2. tmやretvalなどの汎用的な名前を避ける

tmp, retvalなど汎用的な名前があるが、これは名前について何も考えていない。つまり、エンティの値や目的を表した名前を選ぶ。

retval

2乗の合計を出力する以下のコードの場合はretvalよりも、sum_squaresの方がよい。明確に2乗を出力したいことがわかり、バグが見つけやすい。

var euclidean_norm = function(v){
   var retval 0 0.0;
   for ( var i = 0; i<v.length; i++)
      retval += v[i] * v[i];
   return Math.sqrt(retval);
};

point:retvalという名前には情報がない。

tmp

「一時的な情報の保管」としてtmpが使わるが、以下の場合は一時的な側面よりもuser_infoに変えるなど情報のある物として扱うべきである。

String tmp = user.name();
tmp += " " + user.phone_number();
tmp += " " + user.email();

ループイテレータ

i、j、kなどの名前はループイテレータとしてよく使われるが、バグを防ぐためには説明的な名前にする方が良い。 以下の場合イテレータの位置が適切でない。membersとusersのインデックスが反対になっている。この場合はclub_i, members_i, users_iなどにしてイテレータの対象を明確にするのが良い。

for(int i=0; i<clubs.size(); i++)
   for(int j=0; j<clubs[i].members.size(); j++)
      for(int k=0; k<users.size(); k++)
         if(club[i].members[k] == users[j])
         cout << "user["<<j<<"] is in club["<<i<<"]" << end];

2.3. 抽象的な名前よりも具体的な名前を使う

ServerCanStart()はTCP/IPのポートがリスンできるかを調べるものとしてつけているが、対象が不明だったり動作が不明だったりする。この場合はCanListenOnPort()の方がよい。

プログラムのデバック文をプリントする"--run-locally"といったオプションがあった。これには以下の問題がある。

  • ローカルで動作するときに使うオプションなのか?
  • リモートではどうすればいいのか?
  • 新しいメンバがこのオプションについてどういう意味か理解できない

この場合はログを出力するオプションなので、"--extra_logging"などが良い

2.4. 名前に情報を追加する

  • 名前は短いコメントである
  • 名前に型を含める
    • id -> hex_idとして16進であると明確にする
  • 値の単位をつける
    • start -> start_msとしてmsだと明確にする
  • 重要な属性を追加する
    • password -> plaintxt_password
    • comment -> unescaped_comment
    • html -> html_utf8
    • data -> data_urlenc

point:変数の意味を間違うと困るところには属性を追加する

2.5. 名前の長さを決める

  • 長い名前を避けるべきだが、用途に応じて使用する。
  • スコープが小さければ短い名前で良い。
  • 長い名前を入力するのは問題ではない
    • エディタにより補完ができる
  • 頭文字と省略形はプロジェクト固有はダメ
    • 新しいメンバーが理解できることが必要
  • 不要な単語を捨てる
    • 名前に含まれる単語を消しても意味が分かる場合は消しても良い
    • ConvertToString() -> ToString()でよい
    • DoServeLoop() -> ServeLoop()

2.6. 名前のフォーマットで情報を伝える

  • 変数名、定数、マクロなどでフォーマットを整える(例 Googleオープンソースプロジェクト)
    • 変数名は小文字でアンダースコアで区切る -> lower_separated
    • 定数はkをの後に大文字で始まる名前にする -> kConstantName
    • マクロは大文字にする -> MACRO_NAME

2.7. まとめ

  • 明確な単語を選ぶ
  • tmpやretvalなどの汎用的な名前を避ける
  • 具体的な名前を使って、物事を詳細に説明する
  • 変数名に大切な情報を追加する
  • スコープの大きな変数には長い名前をつける
  • 大文字やアンダースコアに意味を含める

追記

私は名前に型を定義することはしていましたが、あまり考えずに名前は付けていますね。その場限りやイマイチ名前が思いつかない場合にはtmp、イテレータはiとしてました。それらの説明は定義時にちょろっとコメントで書くくらいです。たしかに、名前をきちんとつけることでその変数がどのように使われるかもわかってきます。

実際に少し時間が経って自分のコードを見直す時にtmpってなに?とかなって、結局コメントを探しもしくはアルゴリズムを読み取り確認していました。気をつけないといけないですね。