勉強日記

チラ裏

A Philosophy of Software Design ch14 Choosing names

www.goodreads.com


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)
    • 将来そのコードを読む人が楽できる
  • 良い命名のスキルを磨くことも投資
    • はじめは良い命名に時間がかかりフラストレーションを感じるだろう
    • じき簡単になる
    • 最終的に時間がかからなくなり、メリットだけを享受できるようになる