- はじめに — なぜ名前付けはそんなに難しいのか
- 名前は実装ではなく意図を表すべき
- 名前の長さはスコープに比例する
- エンコーディングとハンガリアン記法を避ける
- 検索可能な名前を使う
- 真偽値・関数・コレクションの慣習
- リネームは一つのリファクタリングである
- よくある落とし穴
- おわりに
- 参考資料
はじめに — なぜ名前付けはそんなに難しいのか
フィル・カールトン(Phil Karlton)の有名な一言があります。「コンピュータサイエンスで難しいことは二つだけだ。キャッシュの無効化と、名前付けである」。初めて聞くと、気の利いた言葉遊びに思えます。名前付けがキャッシュの無効化と同じくらい難しい? 変数に単語を一つ付けるだけなのに?
ところが何年かコードを書いていると、この冗談が身にしみてきます。名前付けが難しいのはタイピングが難しいからではなく、名前を付けた瞬間に、その概念を本当に理解しているかどうかが露わになるからです。ある関数に良い名前が浮かばないなら、それはたいてい、その関数が一つのことをしていないか、役割をまだ明確に定義できていないというサインです。名前付けは思考の道具であって、飾りではありません。
この記事では、良い名前を付けるためのいくつかの原則を、実務の視点から整理します。ルールを丸暗記するためではありません。それぞれの原則がなぜ存在するのかを理解すれば、見慣れない状況でも自分で判断できるようになります。
名前は実装ではなく意図を表すべき
一つだけ原則を残せと言われたら、これです。良い名前は「何をするか」ではなく「なぜ存在するか」を語ります。 読む人が実装を覗き込まなくても、その値や関数の意味を掴めるべきです。
悪い例を見ましょう。
# d とは何か? 実装を読まないと分からない
d = 30
# リストを走査し、ある条件を満たすものだけ選んで新しいリストに詰める
list1 = []
for x in list2:
if x[3] == 1:
list1.append(x)
d、list1、list2、x[3] == 1 のどれも自分では語りません。このコードを理解するには周囲の文脈をすべて読む必要があります。では意図を表す名前に変えてみましょう。
GRACE_PERIOD_DAYS = 30
active_users = []
for user in all_users:
if user.is_active:
active_users.append(user)
変わったのはロジックではなく名前だけです。それなのにコードが自分自身を説明します。30 という数字が何を意味するのか、なぜこのユーザーたちを選ぶのかが、名前に込められています。「これは30日の猶予期間だ」とコメントで説明する必要がなくなりました。良い名前はコメントの代わりになります。
名前の長さはスコープに比例する
初心者にありがちな二つの極端があります。一つはすべてを a、b、tmp に縮めること。もう一つは逆に、theListOfAllActiveUsersInTheCurrentOrganization のような文章級の名前を付けることです。どちらも良くありません。
良い規則は、名前の長さはそのスコープ(生存範囲)に比例すべきというものです。
# 短いスコープ:一行の内包表記の中だけで生きる変数は短くてよい
squares = [n * n for n in numbers]
# 広いスコープ:クラス全体で使うフィールドやモジュール全域は十分に説明的に
class PaymentProcessor:
def __init__(self):
self.pending_settlement_count = 0
一行の中だけに存在するループ変数 n は短くても問題ありません。目がその小さな範囲を一度に捉えられるからです。逆にクラス全体で生き続けるフィールドが n だと悲惨です。この値がどこでどう使われるかを追うには、名前が自ら文脈を背負っていなければなりません。
まとめるとこうです。ループのインデックスや短いラムダの引数は短く、関数の引数はほどほどに、広い範囲で長く生きる名前ほど説明的に。スコープが広いほど、名前が担うべき説明の重さは増します。
エンコーディングとハンガリアン記法を避ける
かつて流行したハンガリアン記法は、変数名の先頭に型情報を接頭辞として付ける方式でした。strName(文字列 name)、iCount(整数 count)、arrUsers(配列 users)のように。今ではほとんどアンチパターンと見なされます。
# ハンガリアン記法 - 避けよう
strUserName = "alice"
iRetryCount = 3
arrActiveUsers = [...]
# 型は言語とIDEが教えてくれる。名前は意味に集中しよう
user_name = "alice"
retry_count = 3
active_users = [...]
理由は二つあります。第一に、現代の言語は型システムとIDEが型を教えてくれます。名前に型を重複させるのは冗長です。第二に、そしてより危険なのは、型が変わると名前が嘘をつくようになることです。arrUsers を後で集合(set)や辞書に変えると、接頭辞 arr が誤った情報になります。名前は常に真実であるべきなのに、実装の詳細を名前にエンコードすると、その真実は簡単に壊れます。
同じ理由で、メンバ変数に m_ を付けたり、グローバルに g_ を付ける慣習も、最近はあまり使われません。本当に区別が必要なら、self.count のように言語が提供する文法で十分です。
検索可能な名前を使う
コードは書く時間より、読んで探す時間のほうがはるかに長いものです。だから 名前が検索可能か(grep しやすいか) は、思ったより重要な実務の基準です。
数値リテラル 7 をコードのあちこちに散らばせたとします。後でこの 7 が「一週間」を意味すると気づいて値を変えようとするとき、プロジェクト全体で 7 を検索すると、無関係な 7 が大量に出てきます。しかし名前を付けておけば、まさにその概念だけを見つけられます。
# 悪い:この7が何を意味するか、他にどこにあるか探しにくい
if days_since_login > 7:
send_reminder()
# 良い:名前で検索すれば、この概念が使われた場所だけが正確に出る
INACTIVE_THRESHOLD_DAYS = 7
if days_since_login > INACTIVE_THRESHOLD_DAYS:
send_reminder()
同じ文脈で、一文字の変数やありふれた単語は検索を妨げます。data、value、item のような名前がコードベースに何百個もあると、特定のその値を探すのが困難です。名前は固有で具体的なほど、後の自分を助けます。
真偽値・関数・コレクションの慣習
いくつかの定着した慣習は、覚えておくとチーム全体のコードを読みやすくします。
真偽値は「はい/いいえ」で答えられる名前に。 is、has、can、should のような接頭辞を付けると、条件文で自然に読めます。
# 名前だけで真偽の問いになる
is_active = True
has_permission = user.role == "admin"
can_retry = attempt < max_attempts
if is_active and has_permission:
...
active や permission のように名詞形にすると、if active: が「アクティブ?」なのか「アクティブにせよ」なのか曖昧です。接頭辞一つでその曖昧さが消えます。
関数名は動詞で始める。 関数は行動だからです。getUser、calculateTotal、sendEmail のように。一方、値を保持する変数は名詞です。そして何を返すかが名前から伝わると良いでしょう。読む人は getUser() がユーザーを、isValid() が真偽値を返すと自然に期待します。
コレクションは複数形で。 複数を保持するリストや集合は複数形の名前を使います。
# 単数は一つ、複数は多数 - 走査するとき自然に読める
users = fetch_all_users()
for user in users:
notify(user)
user は一人、users は多数。この単純な規則のおかげで for user in users: が文のように読めます。逆に for u in userList: のようなコードは、毎回少し立ち止まって解釈する必要があります。
リネームは一つのリファクタリングである
ここで多くの人がつまずきます。「今の名前がいまいちなのは分かるが、変えるとあちこち直す羽目になるから…」。こうして悪い名前が化石のように残ります。
しかしリネームは、現代のツールで最も安全なリファクタリングの一つです。IDEの「シンボル名の変更」機能は単なる文字列置換ではなく、言語を理解したうえで、そのシンボルが参照される場所だけを正確に変えます。同名の無関係な変数には手を触れません。
原則はこうです。より良い名前が浮かんだなら、その瞬間が変えどきです。 名前を直すコミットは、ロジックの変更と混ぜず別にするのが良いでしょう。そうすればレビュアーが「これは純粋な名前変更で、動作はそのままだ」と一目で確認できます。
良い習慣:
コミット1: rename calc() -> calculate_monthly_total() (動作変化なし)
コミット2: 実際のロジック修正 (動作変化あり)
悪い習慣:
コミット1: 名前も変えロジックも変えフィールドも移動し… (レビュー不能)
名前を直すことを恐れないでください。コードは、理解が深まるほど良い名前を得ていく、生きたドキュメントです。最初から完璧な名前を付ける必要はありません。理解が育てば、名前も一緒に育てればよいのです。
よくある落とし穴
最後に、実務でよく出会う名前関連の落とし穴を挙げます。
- 嘘をつく名前:関数名は
getUserなのに内部でユーザーを作ったり削除したりするなら、名前が嘘をついています。取得系の関数は副作用がないと期待されるので、この種の裏切りは特に危険です。 - 一貫性のない語彙:同じ概念をある所では
fetch、ある所ではget、ある所ではretrieveと呼ぶと、読む人が「この三つは別物か?」と迷います。一つのコードベースの中では、一つの概念に一つの単語を決めて貫きましょう。 - 意味のない冗語:
UserData、UserInfo、UserObjectのData、Info、Objectは何も足しません。多くの場合、ただのUserで十分です。 - 発音できない名前:
genymdhms(generation year month day hour minute second)のような名前は、同僚と話すとき声に出して呼べません。コードはチームが一緒に語る対象なので、発音可能性も大切です。
おわりに
名前付けが「最も難しい簡単なスキル」なのは、文法的には何の制約もないのに、そこに私たちの理解がそのまま露わになるからです。良い名前は実装ではなく意図を語り、スコープに比例した長さを持ち、型をエンコードせず、検索可能で、チームの慣習に従います。
なにより、名前は固定されたものではありません。より良い名前が浮かべば、リネームはいつでもできる安全なリファクタリングです。完璧な名前を最初から絞り出そうと苦労するより、「今の自分の理解ではこれが最善」という名前を付け、理解が深まるたびに磨いていくほうがずっと健全です。結局、よく付けられた名前が積み重なれば、コードは別の説明書なしに読める文章になります。
参考資料
- Robert C. Martin『Clean Code』(第2章: Meaningful Names)
- Phil Karlton の引用の背景: https://www.karlton.org/2017/12/naming-things-hard/
- Tim Ottinger, "Ottinger's Rules for Variable and Class Naming"
- Kernighan & Pike『The Practice of Programming』(明確さと名前)
현재 단락 (1/76)
フィル・カールトン(Phil Karlton)の有名な一言があります。「コンピュータサイエンスで難しいことは二つだけだ。キャッシュの無効化と、名前付けである」。初めて聞くと、気の利いた言葉遊びに思えま...