TL;DR

  • 良い名前はドキュメントの一部となってコードの理解を助け、悪い名前は複雑さとバグを生む。
  • 良い名前は、正確さと一貫性を併せ持つ。

内容

名前の重要性

良い名前はドキュメントの一部になり、コードの理解を助ける。他のドキュメントの必要性を減らし、誤りも見つけやすくする。逆に、悪い名前はコードの複雑さを増やし、バグの原因になる曖昧さや誤解を生む。悪い名前は、複雑さが少しずつ積み重なる例の 1 つである(第2章 The Nature of Complexity)。

著者は、block という変数を、ディスク上の物理ブロック番号とファイルの論理ブロック番号の 2 つの意味で使っていた。物理ブロック番号が必要な場所で論理ブロック番号を使うバグが起きた。block を見ると反射的に物理ブロック番号だと思い込んでしまったので、原因の特定に半年ほどかかった。fileBlock と diskBlock のように別々の名前を付けていれば防げた。

開発者の多くは、名前を付けることにあまり時間をかけず、思いついた名前をそのまま使いがちである。しかし、より正確で一貫性のある名前を選ぶのに時間をかけるべきである。その時間はすぐに取り戻せるし、繰り返すうちに良い名前を選べるようになる。

名前は抽象化の一形態

名前を付ける目標は、名付けたものの本質を読み手の頭に思い描かせることである。良い名前は、それが何であり、何でないかについて多くの情報を伝える。名前を付けるときは、「宣言やコメント、使っているコードを見ずに名前だけを見た人が、それが何を指すかをどれだけ推測できるか」を自問するとよい。1 つの単語では限界があるので、最も重要な側面を捉える数語を見つけられるかが鍵になる。名前は、背後にある複雑な実体を隠してシンプルに表すものなので、抽象化の一形態といえる。

正確さ

曖昧な名前は正確さに欠け、読み手は何を指すのか分からない。曖昧な名前はレッドフラグの 1 つである。たとえば、管理している indexlet の総数を返すメソッドの名前が getCount では、何の数か分からない。getActiveIndexlets や numIndexlets のほうが正確である。

カーソルが見えているかを表す真偽値の blinkStatus も曖昧である。status は真偽値の名前としては曖昧で、blink も何が点滅するのかを示していない。真偽値の名前は常に述語にするべきで、cursorVisible とすれば true の意味を推測しやすい。

// Controls cursor blinking: true means the cursor is visible,
// false means the cursor is not displayed.
private boolean cursorVisible = true;

まだ誰にも投票していないことを表す定数に VOTED_FOR_SENTINEL_VALUE と付けると、特別な値(センチネル値)であることは分かるが、何が特別なのかは分からない。NOT_YET_VOTED のほうが具体的である。result はメソッドの戻り値を想起させるが、どんな値かは分からない。ただし、実際に戻り値として使う変数なら、どんな値かはメソッド名から分かるので問題ない。

一方で、曖昧な名前でもよい場合がある。短いループの反復子 i や j は、変数の使われる箇所をすべて見渡せるので、冗長な名前は必要ない。ループが長かったり、意味がコードから分かりにくかったりするなら、正確な名前を付ける。また、具体的すぎる名前もよくない。テキストの範囲を削除するメソッドの引数を selection にすると、UI で選択した範囲だけを削除するように読める。どんな範囲でも削除できるなら、range のような汎用的な名前にする。

正確な名前を思いつかないことは、その変数に明確な定義や目的がないことを示している。1 つの変数で複数のことを表している場合などで、宣言そのものを見直す必要がある。名前を付けるのが難しいことも、レッドフラグの 1 つである。

一貫性

ある文脈で見た名前の意味を別の文脈でも推測できるので、一貫性のある名前は認知的負荷を減らす。たとえば、外側のループの反復子には i、内側には j を使う。一貫性のある名前にするには、同じ目的には常に同じ名前を使い、その名前を他の目的には使わず、同じ名前の変数が同じように使われるよう目的を十分に絞る。同じ種類のものを指す変数が複数必要な場合は、接頭辞で区別する。たとえば、ファイルをコピーするメソッドでは srcFileBlock と dstFileBlock のようにする。

Go の短い名前

Go には、名前はとても短くするべきだという考え方が根付いている。Andrew Gerrand は What's in a name? で、長い名前はコードが何をするのかを分かりにくくすると述べている。

long names obscure what the code does.

一方で、次のようにも述べている。

The greater the distance between a name’s declaration and its uses, the longer the name should be.

キーワード

自分の理解

Go で context.Context のインスタンスを ctx と名付けるのも、一貫性のある名前の例だと思う。Go の短い名前は、一貫性を持たせれば認知的負荷を下げられる。一方で、短くすると必然的に曖昧になるので、正確さは失われる(block の例)。結局、可読性は書き手ではなく読み手が決めるものだ。短い名前でも、読み手が理解しやすいと感じればそれでよい。ループの反復子の話で、変数の使われる箇所をすべて把握できるなら冗長な名前はいらないというのも、Go の基本的な考え方と同じだ。

cursorVisible には blink という単語が含まれないので、カーソルが常に表示されない理由を知りたければコメントを読む必要がある。本ではこの情報はさほど重要でないとされているが、重要でないかどうかは他の実装を見るまで分からないと思う。ただ、cursorVisible のほうが汎用的ではある。