Skip to content
jssrshun edited this page Aug 25, 2020 · 4 revisions

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

本章でのポイント

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

2.1 明確な単語を選ぶ

 名前に情報を詰め込むには、対象の動作や目的に合わせて明確な名前を付ける必要がある

class BinaryTree {   
       int Size();
       ... 
} 

 上の Size() が表しうるものと適切な名前の例
 ・ ノードの数 ⇒ Height()
 ・ ツリーの高さ ⇒ NumNodes()
 ・ メモリ使用量 ⇒ MemoryBytes()

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

 retvalから得られる情報は「戻り値用の変数である」という情報だけ。目的や値の情報を伝えるためには汎用的だと難しい。
 例えば、平均値を保持する変数ならaverageやmeanと明示した方がわかりやすい。
 ただし、汎用的な名前でも問題ない場合がある。

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

 具体的な名前 ⇒ 名前がメソッドの動作や格納するデータをそのまま表している
 ServerCanPort() ⇒ CanListenOnPort()

2.4 名前に情報を追加する

 以下は名前に情報を追加することで意図が伝わりやすくなる場合の例。

  • 代入値が16進数(hexadecimal)や8進数(octal)である ⇒ string hex_id , string oct_id
  • 時間やバイト数などの計測できる数値の単位が存在する ⇒ MB単位のサイズ:size_mb , ms単位の遅延時間:delay_ms
  • 危険や注意を喚起する必要がある ⇒ 安全ではない受信データ:untrustedUrl , htmlの文字コードを指定:html_uft8

2.5 名前の長さを決める

 長すぎる名前は冗長で可読性が低いが、短すぎるコードには情報を含むことができない。
 よって以下の工夫を取り入れる。

  • スコープの大きさに基づいて名前の長さを決める
    if(debug){  
        map<string, int> m;  
        LookUpNamesNumbrs(&m);  
        Print(m);  
    }

 上記の変数mが有効であるスコープは3行しかないため、前後を見返せば用途が簡単に理解できる。短い名前でも問題はない。

  • 単語補完のコマンドを用いて長い名前の作成を簡単に
  • 誰でも理解できる単語は省略形に
    document ⇒ doc
     string ⇒ str

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

 大文字やアンダースコアなどに意味を含めることで、ほかの名前と区別することができる。

    static const int kMaxOpenFiles = 100;   //定数の先頭に小文字のkを置いて判別しやすくする ...なぜk?(数学的に?)

    class LogReader{   //クラス名は大文字で区切る、という意味?
       public:
           void OpenFile(string local_file);    //メソッド名も大文字で区切る、という意味?

       private:
           int offset_;     //メンバ変数の末尾にはアンダースコアを入れる(他の変数と見分けやすくなる)
           DISALLOW_COPY_AND_ASSIGN(LogReader);
    };

 疑問『ファイル名(クラス名)の長さの基準は?』
 - ファイル名を管理することもソースコードの可読性を上げるためには必要なのではないか?

3章 誤解されない名前

3.1 例:filter()

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

 上記の名前では2011年以下を「選択する」のか「除外する」のか区別がつかない ⇒ 誤解が生じる
 「選択する」なら select() に、「除外する」なら exclude() にした方がわかりやすい

3.2 例:Clip(text, length)

    def Clip(text, length):
      ...

 上記の名前では「最大 length 文字まで切り詰める」のか、「最後尾から length 文字削除するのか」区別がつかない
 length も抽象的な単語であり max_length の方が具体的である
 ただし max_length にもバイト数、文字数、単語数などのパターンがあり、誤解を生じさせる可能性があるため、 単位 を入れて( max_chars )判別しやすくする

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

    CART_TOO_BIG_LIMIT = 10;
    ...
    if( shopping_cart.num_items() > CART_TOO_BIG_LIMIT){
       Console.Error.WriteLine("カートにある商品数が多すぎます");   
    }

 LIMIT(限界)が非常に抽象的な単語であるとわかる
 「10」を含む限界なのか、含まない限界なのかが一目ではわからない(前後のソースコードを見れば...)  MAX_ITEMS_IN_CART のように max(最大)や min を使うと違いがわかりやすい

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

    print integer_range(start = 2, stop = 4)

 上記のような範囲を指定する必要がある場合、開始点と終点を表す単語を用いるのが適切である

    print integer_range(first = 2, last = 4)

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

 (C++に begin() と end() のイテレータを扱う関数があったが、C++を使ったことがないのでよくわからない)

3.6 ブール値の名前

 ブール型の変数名の先頭には is・has・can・shouldなどをつけると、真偽の状態が理解しやすい
 加えて名前は肯定形にするのが望ましい

    bool disable_ssl = false;        //二重否定みたいでわかりにくい

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

  • 例1 get()
     getから始まるメソッドは「簡単に」利用できると思われがちである。その期待を裏切るような膨大な処理を get**() メソッドに含めるのは親切ではない。
  • 例2 list::size()  他のコンテナに合わせた簡潔な名前のメソッドを用意すると、ユーザは他のコンテナと同様の処理速度を期待する。よってその期待を裏切ってしまう。

3.8 複数の名前を検討する

 名前を決めるのに複数の候補を出し、適切な名前を選考しましょう。

3.9 まとめ

 最善の名前とは誤解されない名前である。コードの読み手が誤解し得る可能性を想像し、曖昧さを除いた最適な名前を導き出さなければならない。