
ハードコードされた値の洗い出し|設定へ外出しする安全な手順
「お問い合わせフォームの送信先を、新しいアドレスに変えてもらえますか」
1行直せば終わる、と思って検索をかけると、同じメールアドレスが画面いっぱいに出てきます。フォームの処理、完了メールのテンプレート、管理画面、夜間バッチ、なぜか古いテスト用のファイルにまで。数えてみたら十数か所。しかも、どれが今も使われているのか分からない。
ここで手が止まるのは、慎重だからです。雑に全部置き換えれば一瞬ですが、どこかで何かが壊れそうな気配がする。その感覚は正しいです。
ハードコード(設定で変えるべき値を、プログラムの中に直接書き込んである状態)は、書いた人の怠慢というより、「急ぎの改修」と「当時は変わらないと思っていた」が積み重なった跡です。責める相手はいません。この記事では、それを少しずつ外へ出していく順番を、一緒に整理していきます。
結論:やることは4つです。①まず探して一覧にする(直すのは後。数と場所を先に知る)、②値の「行き先」を仕分ける(設定へ/秘密なら金庫へ/コードに残してよいもの)、③振る舞いを変えずに、1種類ずつ外へ出す(まず1か所の定数に集め、動作を確かめてから設定へ)、④移したあと、古い値が残っていないかもう一度探す。一度に全部やる必要はありません。今日の依頼で触る1種類からで十分です。
なお、言語やフレームワーク、サーバーの構成によって、設定の置き場所や読み込み方は変わります。ここで挙げるのは「進め方の型」です。コード例はPHPで書いていますが、自分の現場の書き方に置き換えながら読んでみてください。
ハードコードされた値は、なぜ増えるのか
まず、何が起きているのかを落ち着いて見ておきます。ハードコードは、たいていこんな経緯で増えます。
- 急ぎの改修:「今日中にこのアドレスへ届くように」と言われたら、いちばん速いのは直接書くことです。その判断は、その日は正しかった。
- コピペで広がる:似た画面を作るとき、既存のファイルを複製して直す。すると、埋め込まれた値も一緒に複製されます。
- 「変わらない」と思っていた:税率、送料の無料ライン、1ページの表示件数、取引先のURL。書いた時点では、変わる予定がなかった値です。
- 環境ごとの値が混ざる:開発用のサーバー名、検証用のAPIのURLが、本番のコードにそのまま残っている。
困るのは、値が変わる日が来たときです。直す場所が分からない、直し漏れが出る、直したつもりで一部だけ古いまま動き続ける。「一部だけ古い」がいちばんやっかいで、エラーにならないので誰も気づきません。
だからこそ、最初の一手は置き換えではありません。探して、数えることです。
ステップ1:ハードコードされた値を探して、一覧にする
いきなり直し始めず、まず全体を見ます。探すときは、「これが変わったら困る値」の形で検索するのが近道です。
Gitで管理しているなら git grep が便利です(管理されているファイルだけを探すので、ライブラリやログに埋もれにくくなります)。まだGitに載っていないなら、バージョン管理なしのソースをGitに載せる手順を先にやっておくと、この後の作業がぐっと安全になります。
# URL(外部APIや自社の別サイトなど)
git grep -n -E "https?://" -- '*.php' '*.js' '*.html'
# メールアドレス
git grep -n -E "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}"
# IPアドレス(接続先のサーバーが直書きされていないか)
git grep -n -E "\b[0-9]{1,3}(\.[0-9]{1,3}){3}\b"
# サーバー上の絶対パス
git grep -n -E "/home/|/var/www/|/usr/local/"
# 今回の依頼で変える値そのもの(まずはこれがいちばん確実)
git grep -n "info@old-example.co.jp"
Gitがない場合は、grep で同じことができます。ライブラリの置き場所は外しておくと、結果が読める量になります。
grep -rn --exclude-dir={vendor,node_modules,.git} "info@old-example.co.jp" /var/www/app/
見落としやすい場所も、ここで一緒に確かめておきます。
- テンプレート・JavaScript・CSS(画面側にも同じ値が書かれていることがあります)
- cronの設定(
crontab -lで、バッチの引数に値が直書きされていないか) - データベースの中(設定テーブルやメール文面のテーブルに入っていることもあります)
- サーバーの設定ファイル(Webサーバーのリダイレクト先など)
探した結果は、表にして1枚にまとめます。この段階ではまだ何も直しません。
| 値 | 意味 | 見つかった場所 | 変わる頻度 | 行き先 |
|---|---|---|---|---|
| info@old-example.co.jp | 問い合わせ通知の宛先 | 7か所(フォーム・バッチ・テンプレート) | 年に数回 | 設定へ |
| https://api.example-pay.jp/v1 | 決済APIの接続先 | 3か所 | 環境ごとに違う | 設定へ |
| sk_live_xxxx | 決済APIの秘密鍵 | 1か所 | 漏れたら即交換 | 金庫へ |
| 1.1 | 税込計算の係数 | 5か所 | 制度が変われば | 設定へ(要確認) |
| 20 | 一覧の表示件数 | 4か所 | ほぼ変わらない | 定数に集める |
「見つかった場所」の件数が、そのまま作業の大きさです。ここが見えるだけで、依頼者に「今日できること」と「少し時間がかかること」を分けて伝えられるようになります。
ステップ2:値の「行き先」を3つに仕分ける

一覧ができたら、それぞれの値をどこへ動かすかを決めます。全部を設定ファイルに出せばいい、というわけではありません。
- 設定へ:環境ごとに違う値(接続先のURL・サーバー名)、運用中に変わる値(宛先のメールアドレス・送料の無料ライン)。コードを直さずに変えられるようにしておきたいものです。
- 金庫へ:パスワード、APIキー、秘密鍵。これは設定ファイルに書くのではなく、Gitに入らない場所・権限を絞った場所に置きます。見つけたら、この作業とは別に、優先して対処してください(手順はパスワードとAPIキーの平文放置をなくすにまとめてあります)。
- コードに残す:変わる理由がない値、変わるときはどうせコードも直す値。ただし、同じ値が何か所にも散らばっているなら、名前をつけた定数1か所に集めるだけはやっておくと、次に読む人が助かります。
迷ったら、「この値が変わるとき、誰が、どのくらいの頻度で変えたいか」を考えてみてください。依頼者から年に何度か変更依頼が来る値なら設定へ。開発者しか触らない値なら、定数で十分なことが多いです。
「環境ごとに違う値」の考え方は、環境差で事故らない設定管理でもう少し詳しく整理しています。あわせて読むと、置き場所の決め方が楽になります。
ステップ3:振る舞いを変えずに、1種類ずつ外へ出す
ここが本番です。コツは、「場所を変える」と「値を変える」を同じ日にやらないことです。
いきなり「新しいアドレスに変えつつ、設定ファイルから読むように書き換える」と、動かなかったときに原因が2つに増えます。順番を分けると、どこで壊れたかがすぐ分かります。
3-1. まず、同じ値を1か所の定数に集める
値はそのまま、置き場所だけを1か所にまとめます。この段階では、画面の動きは何も変わらないはずです。
<?php
// 変更前:7か所に同じアドレスが直書きされている
mail('info@old-example.co.jp', $subject, $body);
// 変更後:1か所に集めて、そこを参照する(値はまだ変えない)
// config/app.php
const CONTACT_NOTIFY_TO = 'info@old-example.co.jp';
// 使う側
mail(CONTACT_NOTIFY_TO, $subject, $body);
置き換えたら、フォームの送信・バッチ・管理画面など、見つかった場所の機能をひと通り動かして、これまでと同じ宛先に届くことを確かめます。触る範囲の見積もりは改修の影響範囲を調べる手順が役に立ちます。
3-2. 次に、設定ファイルから読むようにする
1か所に集まったら、その1か所だけを「設定から読む」形に変えます。
<?php
// config/app.php
$config = require __DIR__ . '/../config/settings.php'; // Gitに入れない本番用の設定ファイル
if (empty($config['contact_notify_to'])) {
// 値が入っていないときは、黙って動かずに止める
throw new RuntimeException('contact_notify_to が設定されていません');
}
define('CONTACT_NOTIFY_TO', $config['contact_notify_to']);
ここで1つ気をつけたいのが、「値がないとき、どう動くか」です。
設定が読めなかったときに、コードの中の既定値(たとえば本番のアドレス)へ黙って戻る作りにすると、検証環境から本番の宛先へメールが飛ぶ、ということが起きます。宛先や接続先のように「間違うと外に影響する値」は、値がなければ止まる形にしておくほうが安全です(メール誤送信を防ぐリリース手順でも同じ考え方を扱っています)。
設定の渡し方として環境変数を使う現場も多いと思います。ただ、PHP-FPMでは設定(clear_env)によってサーバーの環境変数がPHPまで届かないことがあります。環境変数にする場合は、php-fpm のプール設定でどう渡すかまで含めて検証環境で確かめてください。一人運用なら、権限を絞ったPHPの設定ファイル1枚のほうが、仕組みが見えやすく迷いにくいこともあります。
3-3. 値を変えるのは、そのあと
置き場所の移動が本番で問題なく動いたのを確かめてから、はじめて設定ファイルの値を新しいアドレスに変えます。ここまで来れば、変更は設定ファイルの1行です。反映の手順は設定ファイル変更を安全に反映する手順のとおり、退避・差分・反映・確認で通せば大丈夫です。
1回のリリースで外に出すのは、1種類の値までを目安にしてください。「メールアドレス」と「決済APIのURL」を同じ日にまとめると、何かあったときの切り分けが一気に難しくなります。
ステップ4:移したあと、古い値が残っていないか探し直す
外出しが終わったら、最初と同じ検索をもう一度かけます。
# 古い値が、設定ファイル以外に残っていないか
git grep -n "info@old-example.co.jp"
# データベースの中に残っていないか(テーブル名・カラム名は環境に合わせて)
# SELECT id, name FROM mail_templates WHERE body LIKE '%info@old-example.co.jp%';
ここで0件(または設定ファイルの1件だけ)になっていれば、完了です。残っていたら、それは直し漏れか、「残す」と決めた場所のどちらかです。残すなら、一覧表にその理由を1行書いておきます。
最後に、一覧表の「行き先」の列に、移した日付と設定のキー名を書き足しておきましょう。次に誰かが「この値、どこで変えるの?」と迷ったとき、この表が答えになります。
具体例:現場でよく見る4つのハードコード
- 問い合わせの宛先メールアドレス:担当者の異動や部署名の変更で、いちばんよく変わる値です。フォーム本体は直したのに、夜間の集計バッチだけ旧アドレスに送り続けていた、という直し漏れが起きやすい。
- 外部APIの接続先URL:検証用(サンドボックス)と本番で違う値です。検証用のURLがコードに残ったまま本番に出てしまい、決済が「テスト扱い」で通っていた、という事故は、直書きされた接続先から起きることがあります。
- 税込計算の係数:コードに
* 1.08が残っている古いシステムは、今も珍しくありません。ただし、軽減税率の対象(飲食料品など)では8%が正しい場面もあるので、見つけても機械的に置き換えず、どの商品に使われている計算かを確かめてから直します。税率の区分は業務の判断が入るので、経理や依頼者と一緒に確認するのが安心です。 - 表示件数や上限値:
20や100のような数字(いわゆるマジックナンバー)。変わる機会は少なくても、「なぜ100なのか」が分からないと誰も触れなくなります。定数にまとめて、名前と理由のコメントを1行つけるだけで、ぐっと読みやすくなります。
どの例にも共通するのは、危ないのは値そのものではなく、「どこにあるか分からないこと」だということです。場所が分かっていれば、変更は怖くありません。
影響:外出しを進めると、何が変わるか
- 変更依頼が「設定の1行」になる:宛先やURLの変更が、コード改修ではなく設定変更で済むようになります。見積もりも作業時間も、ぐっと小さくなります。
- 直し漏れが起きにくくなる:同じ値が1か所にしかないので、「一部だけ古い」状態が生まれません。
- 環境の取り違えが減る:本番・検証で違う値が設定側に分かれていれば、コードをそのまま出しても接続先を間違えにくくなります。
- 引き継ぎが楽になる:一覧表があれば、次の担当者は「この値はどこで変えるか」を探し回らずに済みます。技術的負債の見える化の一覧に、この表を並べておくのもおすすめです。
全部を外に出し切る必要はありません。変更依頼が来た値から1つずつ進めるだけで、半年後にはよく触る値のほとんどが1か所に集まっているはずです。
明日やること
次にハードコードの値を直す依頼が来たら、この順でどうぞ。
- その値で検索して、件数と場所を数える。コードだけでなく、テンプレート・cron・データベースも見る。
- 見つけた場所を表に書く。値・意味・場所・変わる頻度・行き先の5列で十分です。
- 行き先を決める。設定へ/金庫へ/コードに残す。秘密の情報が見つかったら、それは別件として優先して扱う。
- まず定数1か所に集める。値は変えずに、動きが変わらないことを確かめる。
- 次に設定から読む形にする。値がないときは止まるようにしておく。
- 最後に値を変えて、もう一度検索する。古い値が0件になったら完了。表に日付とキー名を書き足す。
今日やるのは、1の「検索して数える」だけでも十分です。数が分かれば、依頼者への返事も、作業の見積もりも、ずっと落ち着いて出せるようになります。
ハードコード外出しチェックリスト
- 直す前に、その値で全体を検索して件数と場所を数えたか
- コードだけでなく、テンプレート・JavaScript・cron・データベースも探したか
- 見つけた値を、意味・場所・変わる頻度つきで一覧にしたか
- 行き先(設定へ/金庫へ/コードに残す)を値ごとに決めたか
- パスワードやAPIキーを見つけたら、別件として優先して扱ったか
- 「場所を移す」と「値を変える」を別の作業に分けたか
- 1回のリリースで外に出す値を1種類にしぼったか
- 宛先や接続先は、設定がないとき黙って既定値に戻らず止まる形にしたか
- 移したあと、同じ検索をもう一度かけて古い値が残っていないか確かめたか
- 一覧表に、移した日付と設定のキー名を書き足したか
全部そろわなくても大丈夫です。最初の3つができていれば、もう「どこにあるか分からない」状態からは抜け出せています。
よければ、こちらも
- 環境差で事故らない設定管理|開発・検証・本番を一人運用で:外に出した設定を、環境ごとにどう分けて持つか。
- パスワードとAPIキーの平文放置をなくす|一人運用の保管手順:「金庫へ」に仕分けた値の、安全な移し方です。
- 触れないレガシーコードに"最初の一歩"を|壊さず改善を始める手順:大きく直さず、小さく始めるための考え方。
- テストがないコードを安全に改修する:外出しの前後で「動きが変わっていない」を確かめるために。

ハードコードの値を外に出す仕事は、終わっても画面の見た目は何も変わりません。依頼者から見れば「アドレスが変わった」だけ。でもその裏で、次の変更が1行で済む状態を、あなたが作っています。
散らばった値の一覧を前にすると気が重くなりますが、全部を一度に片づける必要はありません。今日の依頼で触る1種類を、1か所に集める。それを繰り返すだけで、システムは少しずつ、あなたが変えやすい形に近づいていきます。
まずは次の依頼のとき、直す前に一度だけ検索して、数を数えるところから始めてみてください。
ほかの実務ヒントは記事一覧からどうぞ。保守運用の小さな備えを、メールでも少しずつお届けしています。