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