ツヨシのブログ

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

スポンサーリンク

【読書】リーダブルコードを読んで行く(3章:誤解されない名前)

スポンサーリンク

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

ginga0118.hatenablog.com

ginga0118.hatenablog.com

3. 誤解されない名前

  • 3.1. 例:filter()
  • 3.2. 例:Clip(text, length)
  • 3.3. 限界値を含めるときはminとmaxを使う
  • 3.4. 範囲を指定するときはfirstとlastを使う
  • 3.5. 包含/排他的に範囲にはbeginとendを使う
  • 3.6. プール値の名前
  • 3.7. ユーザの期待に合わせる
    • 例:get()
    • 例:list::size()
  • 3.8. 例:複数の名前を検討する
  • 3.9. まとめ

3.1. 例:filter()

results = Database.all_objects.filter("year<=2011")

上記の場合に"year<=2011"であるものを選ぶのか、それとも"year<=2011"でないもの、つまり"year>2011"であるものを選ぶのかがfilterという名前ではわからない。

選択をするなら"select"、除外するなら"exclude"を使用すべきである。

3.2. 例:clip(text, length)

clitp(text, length)

上記の場合に最後がlength文字を削除する(remove)の意味か、最大でlength文字まで切り詰める(trancate)なのかわからない。 また、lengthという単語も、文字数、バイト数、単語数など複数の意味を持つ。もし文字数を表すのであれば、max_charsがよい。

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

限界値を指定する時にoff-by-oneエラーを考えなければならない。これは、for文などのループ処理で、処理回数が正しい回数よりも1回多い、もしくは少ない事をいう。

例えば、カートに10点までしか入らない場合

CART_TOO_BIF_LIMIT = 10

if shopping_caart.num_items()>=CART_TOO_BIF_LIMIT:
   Error("カートにある商品が多すぎます")

この場合、CART_TOO_BIF_LIMITは9であるか、">="を">"にしなければいけない。

この場合、定数名にmax(min)などを加えて最大(最小)数を明確にするのが良い。

MAX_ITEMS_IN_CART = 10

こうする事で、最大で10個までカートにはいるというのがわかる。

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

startは適切な名前だがstopは複数の意味に解釈できるので別の言葉を使う。

stopでなくlastを使えば、保管していることが明確になる。意味的に正しくするのであればfirstとlast以外にも見にmaxを使って包含的範囲を表すようにする。

  • stop -> last

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

10月16日に開催されたイベントの印字の例では包含を含めた方がいい。

  • (NG)含めない場合*
PrintEventsInRange(' OCT 16 12:00am', 'OCT 17 12:00am')
  • (OK)含めた場合*
PrintEventsInRange(' OCT 16 12:00am', 'OCT 17 12:00am')

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

3.6. プール値の名前

ブール値の名前にはtrueとfalseの意味を明確にしなければいけない。

bool read_password = true;

この「read」が読み終わったを指すのか、読む必要があるのかこのままだとわからない。

なので、「need_password」や「user_is_authenticated」などが良い。

bool値の名前には「is」「has」「can」「should」などが良い。

3.7. ユーザの期待に合わせる

例:get()

get()のメソッドはメンバの値を返すだけの「軽量アクセサ」であるという認識がある。 このためget()内でのイテレートをすることはやめた方が良い。

その他list.size()など内部で計算を行う関数を判定に使うとそれだけ時間を取ることになる。

vold ShrinkList(list<Node>& list, int max_size){
   while(list.size() > max_size){
      FreeNode(list.back());
      list.pop_back();
   }
}

この場合は動作するという意味でcountSize()などにするとよい。

3.8. 複数の名前を検討する

名前を決めるときには複数の名前を検討する。どういった名前にするかはその機能を知らない人が見たときに理解できる名前にする。

たとえば次のような設定があり、定義されていない場合は別の設定に置き換えたい場合がある。

experiment_id 100: description "test for tsuyopon": minutes 20: the_other_experiment_id_I_want_to_resue 101: ...

「変更が必要な情報だけを置き換える」ために再利用したいidをどうするか? この場合次のような候補が挙げられる。

  • templete
  • reuse
  • copy
  • inherit

templete

この場合、これはテンプレートなのか、このテンプレートを使っているのかがわからない。テンプレートというと抽象的なモニ何かを埋め込んで使うものなので、変更が必要な情報を置き換える場合に適切ではない。

reuse

reuseだとこの実験は100回再利用できると間違えそうだ。

copy

copyだとその設定数だけコピーすると間違えそうだ。

inherit

継承という意味で、しっくりくる。inherit_fromやinherit_from_experiment_idとするとなお良い。

3.9. まとめ

最善の名前は誤解されない名前である。英語の単語はfilter、length、limitのように曖昧なものがおおい。名前を決める前に反対意見を考え誤解されない名前か想像してみる。