A Philosophy of Software Design ch14 Choosing names

APoSDソフトウェア設計勉強メモ

出典: 


Choosing names

  • 識別子の命名は、ソフトウェア設計において最も過小評価される側面のひとつ
  • よい命名は一種のドキュメンテーション

    • コードの可読性向上
    • 他のドキュメンテーションの必要性を減らす
    • 誤りを発見しやすくする
  • 命名がまずいと

    • 複雑性を増す
    • あいまいさ・誤解を招く
    • バグを生む
  • 複雑性は積み重ね

    • 命名一つ一つは、システムの複雑性に大して影響しないように見える
    • 何千もの変数が積み重なると複雑性・管理可能性に大きく影響する

Example: bad names cause bugs

  • 著者がむかしOSを作ったときの話

    • ディスク上の物理的なブロックと、ファイルの論理的なブロック、両方にblockという命名をして、見つけづらいバグを作り込んでしまった
    • diskBlock, fileBlockといった命名なら避けられた
  • ほとんどの開発者は命名について熟考していない

    • 最初に思いついた、「まあまあマッチしている」名前を使用してしまう
    • 「まあまあマッチしている」だけでは不十分なのである

      • blockという名前も決して悪い名前ではなかった
  • 素晴らしい名前をつけるために時間をさけ

    • 素晴らしい名前とは

      • 正確
      • あいまいでない
      • 直感的である
    • かかった時間はすぐに元を取れる
    • 繰り返す内に、すばやく良い命名をできるようになる

Create an image

  • 命名の目標は、名前が指しているものの本質について、読み手の脳内にイメージを作り出すこと
  • よい名前は多くの情報を含む

    • それが何であるか
    • 何でないか
  • 命名の際には自問せよ:

    • この名前を、宣言やドキュメント抜きで単体で見た時、名前が指すものをどれだけ正確に推測できるだろうか?
    • より明確なイメージを描ける名前はないか?
  • こめられる情報には限度がある

    • せいぜい2-3単語、それより多いと扱いづらくなる
    • 少ない単語で、表したいものの最も重要な側面をとらえる難しさ
  • 命名は一種の抽象化である

    • 重要なことを反映する
    • 重要でない詳細は省く

Names should be precise

  • 良い名前が有する特性

    • 正確性
    • 一貫性
  • 本節は正確性について述べる
  • もっともよくある問題: 名前が汎用的すぎ・あいまいすぎ

    • 読み手は、その名前が何を指しているか判断がつかない
    • 間違えて推測してしまうかもしれない

      • blockの例のように
  • 良くない命名と改善案の例

    • getCount()

      • 何の個数?
      • getActiveIndexlets()numIndexlets()等がベター
    • x, y

      • テキストエディタの、文字の位置(行内の文字のインデックス、行のインデックス)を表す変数
      • ピクセル単位と混同するので良くない
      • charIndex, lineIndex等がベター
    • blinkStatus: bool

      • boolean値に対して「status」はあいまい

        • trueのとき何なの
        • falseのとき何なの
      • blinkも意味不明

        • 何がblinkするの
      • cursorVisible等がベター

        • trueなら見える
        • falseなら見えない
        • 「blink」という単語は消えた

          • 見えているかいないかが重要なのであって、「ピカピカすること」は重要でない
    • private statis final String VOTED_FOR_SENTINEL_VALUE = "null"

      • 特別な値であることはわかる

        • 【補】sentinel(番兵)
      • どう特別なのかが伝わらない
      • NOT_VOTED_YET等がベター
    • 値を返さないメソッド内のresult

      • resultをreturnするものと期待させるので良くない
      • 何かを算出した値という以上の情報がない

        • mergedLine, totalChars等がベター
        • resultをreturnするならば問題ない

          • 汎用的すぎる名前ではあるが、メソッドのドキュメンテーションを見れば意味を汲み取れる
          • 【補】FowlerのRefactoring本でもresultという名前で統一されていた
  • 例外はある

    • ループのイテレーション変数i, j
    • ループが短く、全体像を一望できれば問題ない

      • 一望でないほど長かったり、イテレーション変数の意味を汲み取るのが難しければ、より説明的な名前をつける
      • 【補】行/列の多重ループで、i/jどちらが行でどちらが列がわかりづらい場合などか
  • 限定的すぎる名前も良くない

    • 例: void delete(Range selection) {...}
    • selectionという引数名は、UIの範囲選択を前提としている
    • UI以外からも利用できる汎用モジュールであるならば不適
    • void delete(Range range) {...}がベター
  • 良い名前が思い浮かばないのは危険信号

    • その変数が明確な定義や目的をもっていない
    • 一つの変数で複数のものを表現しようとしている
  • よい名前を模索することで、設計のまずいところを特定し、設計を向上させることができる

Use names consistently

  • 第二に、一貫性について
  • 3つの要件

    • 同じ意図には同じ名前を使用する
    • 異なる意図に同じ名前を使用しない
    • 同じ名前のものが同じ振る舞いをするよう、意図は十分狭いこと
  • 冒頭のblockの例は、3つめに違反している例

    • blockの指す意図は広すぎた

      • ディスクの物理的なブロック
      • ファイルの論理的なブロック
  • 同じ意図のものが同時に複数必要になったら?

    • 例: ファイルブロックのコピー

      • srcFileBlock, dstFileBlockのようにする
      • 【補】suffixにしたいこともあると思う。同グループ分けするかの思想が反映される
  • ループのイテレーション変数も、一貫性が有用な例

    • 必ず外側からi, j,…と振る

A different opinion: Go style guide

  • Goのスタイルガイドは「短い名前」を推奨している
  • Andrew Gerrrandいわく:

長い名前は、コードが何をしているか曖昧にする

  • 結局のところ、可読性を決めるのは書き手ではなく読み手

    • 短い変数名でも、読み手が読みやすいと言えばそれでよい
    • 名前が短すぎて暗号のようだと言われたら長い名前を検討すべき
    • 名前が長すぎて読みづらいと言われたら短い名前を検討すべき
  • Gerrandいわく:

名前の宣言箇所と利用箇所とが離れるほど、名前は長くあるべき

  • 著者も同意

    • 前述のループのイテレーション変数のくだりはこのルールの一例

      • 一望できるなら1文字で良い

Conclusion

  • よく考えて選ばれた名前はコードをより明瞭にする

    • 変数名から振る舞いを推し量れる

      • それは合っている
  • 良い名前を選ぶのは「投資の姿勢」(Ch.3)

    • 将来そのコードを読む人が楽できる
  • 良い命名のスキルを磨くことも投資

    • はじめは良い命名に時間がかかりフラストレーションを感じるだろう
    • じき簡単になる
    • 最終的に時間がかからなくなり、メリットだけを享受できるようになる