「なんとなく書いた数字」が、後からあなたや他の人を困らせる。それがマジックナンバー。まずは意味をつかんで、繰り返し処理(ループ)での具体的な回避テクを身につけましょう。
マジックナンバーの基礎
- 定義: コードの中に直接書かれた、意味が読み取れない数値(や文字列)。例:
for i in range(10): ...の「10」が何の上限なのか不明だと、マジックナンバーになります。 - なぜ問題か: 可読性・保守性が落ち、変更時に影響箇所を見落としやすい。意図が伝わらないので、理解やバグ修正に余計な時間を使います。
- 避け方の基本: 意味のある定数名・変数名を使う(例:
MAX_USERS = 10)。命名により「何の10か」がコードから分かるようにします。
マジックナンバーは「コードの意図を曖昧にする代表例」。定数化・命名で意図を表現すると、可読性・保守性が大幅に向上します。
まず押さえるループの基本形
- for: 回数が決まっているときに使う(例: 配列の長さ分まわす)。
- while: 終了条件が状態で決まるときに使う(例: 入力が空でない間)。
ループの「回数・終了条件」にこそマジックナンバーが紛れ込みやすいので、そこに名前を与えるのが最優先です。
ループでマジックナンバーを避ける5つの鉄則
- 意味を名前にする(定数化)
- 例:
MAX_RETRY = 3にしてfor _ in range(MAX_RETRY): ... - 「3回」は「何の3回?」を定数名で説明する。
- 例:
- データから条件を導く(長さや境界は参照)
- 配列や文字列の長さで回すなら、
len(items)を使う。 - 固定数の
10よりlen(users)のほうが安全。
- 配列や文字列の長さで回すなら、
- ドメイン値は1箇所に集約(設定やコンフィグ)
- 税率、タイムアウト、上限値などは設定ファイルや冒頭の定数へ。
- 変更はその1箇所だけにすれば済む。
- 条件は“意味のある関数”に包む
- 例:
is_expired(now, deadline)やwithin_limit(i, LIMIT)にして、式を直書きしない。
- 例:
- 境界の意図をコメントで補足(最小限)
- 命名で足りなければ、なぜその値かの理由を短く添える。
定数やデータ参照を使うのは、可読性・保守性を高めるための王道の対策です。
具体例で学ぶ(PythonとJavaScript)
Python
# 悪い例:何の10かわからない
for i in range(10):
process(i)
# 良い例:意味を名前にする
MAX_BATCH_SIZE = 10 # 1バッチで処理する最大件数
for i in range(MAX_BATCH_SIZE):
process(i)
# データに合わせる例:固定値をなくす
users = fetch_users()
for i in range(len(users)): # または for user in users:
process(users[i])
# 期限やリトライの例
MAX_RETRY = 3
TIMEOUT_SEC = 5 # 通信の待ち時間の上限秒数(要件から決定)
for attempt in range(MAX_RETRY):
if call_api(timeout=TIMEOUT_SEC):
break
PythonJavaScript
// 悪い例
for (let i = 0; i < 60; i++) {
tick();
}
// 良い例
const TICKS_PER_MINUTE = 60; // 1分間のtick数
for (let i = 0; i < TICKS_PER_MINUTE; i++) {
tick();
}
// 配列に合わせる例
const items = getItems();
for (let i = 0; i < items.length; i++) {
process(items[i]);
}
// さらに良い:for...ofで意図が明確
for (const item of items) {
process(item);
}
JavaScriptよくあるマジックナンバーと置き換えパターン
- ループ回数の固定値
- 置き換え: 定数化(
MAX_RETRY、PAGE_SIZE)
- 置き換え: 定数化(
- 配列のインデックス上限
- 置き換え: 長さ参照(
items.length、len(items))
- 置き換え: 長さ参照(
- 時間やタイムアウト
- 置き換え: 単位付き定数(
TIMEOUT_SEC、RETRY_DELAY_MS)
- 置き換え: 単位付き定数(
- ドメイン固有の数字(税率、閾値)
- 置き換え: 設定値・定数(
TAX_RATE、ALERT_THRESHOLD)
- 置き換え: 設定値・定数(
- 境界のオフセット(+1、-1)
- 置き換え: 意味付き関数(
is_last_index(i, items))
- 置き換え: 意味付き関数(
初心者向けチェックリスト
- 数字に「意味のラベル」を付けたか?(定数・変数名)
- 固定値の代わりに「データの長さ」を使えるか?
- 同じ数字を複数箇所で繰り返していないか?(1箇所に集約)
- 単位は明示したか?(
MS、SEC、MB) - なぜその値なのか、将来変わる可能性は?(コメントや設定に)
例外的に“直書きでもよい”ことがある
- 普遍的な数学定数や慣例的な小さな値
- 例:
0(初期値)、1(インクリメント)、-1(最後の要素)などは、文脈が自明なら許容されることが多い。 - ただし「文脈が自明でない」なら、やはり名前を付けるほうが安全。
- 例:
まとめ
- マジックナンバーは「意味が分からない数字」。ループでは回数・境界・時間が特に危険地帯。定数化、データ参照、関数抽象で「意図をコードに刻む」のが最善です。
ソースコードに直接書いた謎の値は、可読性・保守性を下げます。意味のある定数・変数名を使うことで、意図が明確になり、将来の変更にも強いコードになります。


