目次
- はじめに:この記事で目指すゴール
- ハードコーディングって何?なぜ問題なの?
- 現場で遭遇する典型的なハードコーディング3パターン
- 解消の優先順位:どこから手をつけるべきか
- すぐ実践できる3つの解消テクニック
- チームで取り組むための具体的アプローチ
- よくある失敗パターンと回避策
- 予防と習慣化:二度と増やさないために
- まとめ:最初の一歩を踏み出そう
はじめに:この記事で目指すゴール
「ハードコーディングは良くない」という話は何度も聞いたことがあるでしょう。でも、実際の現場で「じゃあ明日から何をすればいいの?」と聞かれたら、答えに詰まってしまう人も多いはずです。
この記事は、技術書やQiitaの記事を読んで「理屈はわかった、でも現場でどう始めればいいかわからない」と感じている方に向けて書きました。特にWEB系ベンチャーやスタートアップのLaravel開発現場を想定し、実践的で今日から使える内容に絞っています。
この記事を読み終えた5分後には、あなたのプロジェクトで最初の一歩を踏み出せる状態になります。
私自身、技術力が突出して高いわけではありません。でも、だからこそチームで無理なく続けられる現実的な方法を大切にしています。この記事では、難しい理論ではなく「明日から使える実践知」をお伝えします。
ハードコーディングって何?なぜ問題なの?
ハードコーディングの定義
ハードコーディングとは、本来は設定ファイルや定数として管理すべき値を、プログラムコードの中に直接書き込んでしまうことです。
例えば、こんなコードです。
// ハードコーディングの例
if ($user->age >= 20) {
// 成人向けコンテンツを表示
}
if ($order->total >= 10000) {
// 送料無料
}
$apiUrl = 'https://api.example.com/v1/users';
一見すると問題なさそうですが、実はこれが後々大きな問題を引き起こします。
なぜ問題なのか?現場目線で考える
技術的な理由を並べても実感が湧きにくいので、現場で実際に起こる困りごとで説明します。
ケース1:仕様変更で阿鼻叫喚
「成人判定の年齢を18歳に変更してください」と言われたとき、20という数字がコード全体に散らばっていたら、grep検索で全部洗い出して修正する羽目になります。しかも「20」という数字は他の意味でも使われているので、一つひとつ確認が必要です。時間がかかる上に、修正漏れのリスクも高まります。
ケース2:環境ごとの設定変更が地獄
開発環境、ステージング環境、本番環境でAPIのURLが違う場合、コードに直接書いていると環境ごとにコードを書き換える必要が出てきます。これはデプロイミスの温床です。
ケース3:新メンバーが混乱
コードレビューで新しいメンバーから「なぜこの値が10000なんですか?」と聞かれたとき、説明できますか?ハードコーディングされた値は「なぜその値なのか」が不明瞭で、理解とメンテナンスを困難にします。
このように、ハードコーディングはチームの生産性を下げ、バグのリスクを高める原因になります。
##現場で遭遇する典型的なハードコーディング3パターン
まずは敵を知ることから始めましょう。Laravel現場で頻出するハードコーディングのパターンを3つ紹介します。
パターン1:マジックナンバー(意味不明な数値)
// よく見るハードコーディング
if ($user->status === 1) {
// アクティブユーザーの処理
}
if ($product->category_id === 3) {
// 食品カテゴリの処理
}
1や3が何を意味するのか、コードを書いた本人以外には分かりません。数ヶ月後、書いた本人すら忘れます。
パターン2:ビジネスロジックの閾値
// 送料無料の判定
if ($cart->total >= 5000) {
$shipping = 0;
}
// ポイント付与率
$points = $purchaseAmount * 0.05;
// 在庫アラート
if ($product->stock <= 10) {
$this->sendAlert();
}
これらの数値はビジネスルールそのものです。キャンペーンで変更したり、ABテストで調整したりする可能性が高いのに、コードに埋め込まれていると変更のたびにデプロイが必要になります。
パターン3:環境依存の設定値
// API接続先
$client = new Client([
'base_uri' => 'https://api.production.example.com'
]);
// メール送信元
Mail::to($user)->send(new WelcomeMail('support@example.com'));
// ファイル保存先
$path = '/var/www/html/storage/uploads/';
開発環境と本番環境で値が変わるものがコードに直書きされていると、環境切り替えのたびに修正が必要になり、非常に危険です。
##解消の優先順位:どこから手をつけるべきか
「全部のハードコーディングを今すぐ直そう!」と意気込むのは危険です。焦って進めると、かえって混乱を招きます。
ここでは現実的に進められる優先順位を提案します。
【最優先】環境依存の設定値(パターン3)
まず最初に手をつけるべきは、環境によって値が変わる設定です。理由は明確で、デプロイ事故のリスクが最も高いからです。
- APIエンドポイント
- データベース接続情報
- 外部サービスのキー・トークン
- メール送信元アドレス
- ファイル保存パス
これらは.envファイルとconfigディレクトリで管理するだけで、すぐに効果が出ます。
【次点】頻繁に変更されるビジネスロジックの閾値(パターン2の一部)
次に狙うべきは、変更頻度が高い値です。
- キャンペーンで変わる送料無料の金額
- ポイント付与率
- 会員ランクの境界値
これらを設定ファイルや定数に移すだけで、デプロイなしで変更できる可能性が広がります。
【段階的に】マジックナンバー(パターン1、パターン2の一部)
最後に取り組むのが、マジックナンバーです。これは影響範囲が広く、一気に変更すると混乱するため、新しく書くコードから徐々に改善していくのが現実的です。
- ステータスコード
- カテゴリID
- その他の固定値
すぐ実践できる3つの解消テクニック
それでは、具体的な解消方法を見ていきましょう。難しいことは一切ありません。
テクニック1:環境設定は.envとconfigに集約
Before(ハードコーディング)
$client = new GuzzleHttp\Client([
'base_uri' => 'https://api.production.example.com',
'timeout' => 30,
]);
After(改善版)
まず.envファイルに追加します。
API_BASE_URL=https://api.production.example.com
API_TIMEOUT=30
次にconfig/services.php(または新規作成)に設定を定義します。
// config/services.php
return [
'external_api' => [
'base_url' => env('API_BASE_URL'),
'timeout' => env('API_TIMEOUT', 30),
],
];
コード内ではconfig()ヘルパーで取得します。
$client = new GuzzleHttp\Client([
'base_uri' => config('services.external_api.base_url'),
'timeout' => config('services.external_api.timeout'),
]);
なぜこれで解決するのか?
.envファイルは環境ごとに内容を変えられるので、コードを一切変更せずに開発・本番で異なる設定を使えます。さらに、.env.exampleにサンプルを残しておけば、新メンバーも設定を理解しやすくなります。
テクニック2:定数クラスでマジックナンバーを撲滅
Before(ハードコーディング)
if ($user->status === 1) {
// アクティブユーザー
}
if ($order->payment_status === 2) {
// 支払い完了
}
After(改善版)
app/Constantsディレクトリを作成し、定数クラスを配置します。
// app/Constants/UserStatus.php
namespace App\Constants;
class UserStatus
{
public const INACTIVE = 0;
public const ACTIVE = 1;
public const SUSPENDED = 2;
public const DELETED = 3;
}
// app/Constants/PaymentStatus.php
namespace App\Constants;
class PaymentStatus
{
public const PENDING = 1;
public const COMPLETED = 2;
public const FAILED = 3;
public const REFUNDED = 4;
}
コードでは定数を使います。
use App\Constants\UserStatus;
use App\Constants\PaymentStatus;
if ($user->status === UserStatus::ACTIVE) {
// アクティブユーザー
}
if ($order->payment_status === PaymentStatus::COMPLETED) {
// 支払い完了
}
なぜこれで解決するのか?
数値の意味が一目瞭然になり、typoも防げます。IDEの補完も効くので、開発効率も上がります。さらに、定数を変更するときは一箇所を修正するだけで済みます。
テクニック3:ビジネスルールは設定ファイルに切り出す
Before(ハードコーディング)
// 送料無料判定
if ($cart->total >= 5000) {
$shipping = 0;
}
// ポイント付与
$points = $purchaseAmount * 0.05;
After(改善版)
config/business.phpを作成します。
// config/business.php
return [
'shipping' => [
'free_threshold' => env('SHIPPING_FREE_THRESHOLD', 5000),
],
'points' => [
'rate' => env('POINTS_RATE', 0.05),
],
];
コードでは設定を参照します。
// 送料無料判定
if ($cart->total >= config('business.shipping.free_threshold')) {
$shipping = 0;
}
// ポイント付与
$points = $purchaseAmount * config('business.points.rate');
なぜこれで解決するのか?
ビジネスルールの変更が設定ファイルの編集だけで済むようになります。将来的にはデータベースや管理画面から変更できるようにも拡張できます。また、値の意味がキー名で明示されるため、可読性も向上します。
チームで取り組むための具体的アプローチ
一人で黙々と改善するだけでは、チーム全体の習慣は変わりません。ここでは、チームで無理なく進めるための現実的なアプローチを紹介します。
ステップ1:小さく始めて成功体験を作る
いきなり大規模リファクタリングに着手するのは危険です。まずは影響範囲の小さい部分で成功体験を積むことが大切です。
おすすめの最初の一歩
- 自分が今開発中の機能で、新しく書くコードから実践する
- 一つのファイルだけ、一つの機能だけで試してみる
- 動作確認をしっかり行い、問題がないことを確認する
例えば、今まさに実装している新機能があるなら、そこで.envとconfigを使ってみる。たったこれだけです。
ステップ2:ドキュメント化して共有する
自分が実践したアプローチをチームに共有しましょう。ただし、いきなり「全員これに従ってください」と押し付けるのは逆効果です。
効果的な共有方法
- プロジェクトのREADMEやWikiに「コーディングガイドライン」として軽く記載する
- 実際に改善したコードのBefore/AfterをSlackで共有し、「こうすると便利でした」と伝える
- チームミーティングで5分だけ時間をもらい、簡単に説明する
重要なのは、「これが正解だから従え」ではなく「こうしたら楽だったので共有します」というスタンスです。
ステップ3:コードレビューで優しく指摘する
PRレビューの際、ハードコーディングを見つけたら優しく指摘しましょう。
NGな指摘の仕方
❌「ハードコーディングしないでください」
❌「これは設定ファイルに書くべきです」
OKな指摘の仕方
✅「この値、将来変更する可能性ありますよね?configに移しておくと後で楽かもしれません」
✅「例えばconfig/business.phpにこんな感じで書いておくと、他の人も理解しやすそうです(サンプルコード添付)」
指摘するときは、理由と具体的な代替案をセットで伝えると、相手も納得しやすくなります。
ステップ4:定期的にリファクタリングの時間を確保する
新機能開発ばかりに追われていると、既存コードの改善は後回しになります。理想を言えば、スプリントごとに「リファクタリングタスク」を少しずつ入れることです。
現実的な時間確保の方法
- 新機能を実装する際、関連する既存コードのハードコーディングを一緒に直す
- バグ修正のついでに、その周辺のコードも改善する
- 月に1回「クリーンアップデー」を設けて、チーム全員で小規模リファクタリングをする
無理のない範囲で、少しずつ積み重ねていくことが大切です。
ステップ5:新メンバーのオンボーディングで伝える
新しいメンバーが入ってきたときは、最高の教育機会です。オンボーディング資料に「ハードコーディングを避ける理由とやり方」を入れておきましょう。
オンボーディング資料に含めるべき内容
- プロジェクトで使っている定数クラスの場所と命名規則
-
.envとconfigの使い分け - 実際のコード例(Good/Bad両方)
新メンバーは「このチームのやり方を早く覚えたい」と思っているので、素直に吸収してくれます。そして、新メンバーの方が最新のルールを守りやすいという好循環が生まれます。
よくある失敗パターンと回避策
ハードコーディング解消に取り組む際、よく陥りがちな失敗パターンを紹介します。これを知っておくだけで、無駄な回り道を避けられます。
失敗パターン1:過剰な抽象化で逆に複雑化する
よくある失敗例
// やりすぎた例
config('business.rules.cart.shipping.conditions.free.threshold.amount.minimum')
ハードコーディングを恐れるあまり、設定ファイルの階層を深くしすぎて、かえって分かりにくくなるパターンです。
回避策
シンプルに保つことを優先しましょう。
// これで十分
config('business.shipping.free_threshold')
判断基準:「他の人が見て3秒で理解できるか?」
設定のキー名は長すぎても短すぎてもダメです。「意味が分かる最小限の長さ」を心がけましょう。
失敗パターン2:一気に全部変えようとして破綻する
よくある失敗例
「来週までに全ファイルのハードコーディングを撲滅する!」と意気込んで着手したものの、影響範囲が大きすぎてテストが追いつかず、バグを大量に生み出してしまう。
回避策
段階的に進めることが鉄則です。
- まずは新規開発コードだけ適用
- 次に、触る機会の多いコアな機能から改善
- 古くて誰も触らないコードは最後(または放置)
完璧主義は禁物です。「8割改善できればOK」くらいの気持ちで進めましょう。
失敗パターン3:定数や設定の命名がバラバラ
よくある失敗例
// 命名がバラバラ
UserStatus::ACTIVE
ORDER_STATUS_COMPLETED
config('payment_method')
config('PaymentMethods')
命名規則が統一されていないと、どこに何があるのか分からなくなります。
回避策
チームで命名規則を決めておくことが重要です。
推奨の命名規則(一例)
- 定数クラス:
PascalCase(例:UserStatus、PaymentStatus) - 定数名:
UPPER_SNAKE_CASE(例:ACTIVE、COMPLETED) - 設定ファイル:
snake_case(例:business.php、payment.php) - 設定キー:
snake_case(例:free_threshold、tax_rate)
プロジェクトのドキュメントに明記しておくと、新メンバーも迷いません。
失敗パターン4:.envに値を書いてもconfigを経由しない
よくある失敗例
// 直接envを参照してしまう
if ($cart->total >= env('SHIPPING_FREE_THRESHOLD')) {
$shipping = 0;
}
これは一見問題なさそうですが、キャッシュの問題があります。本番環境でphp artisan config:cacheを実行すると、env()ヘルパーが正しく動作しなくなります。
回避策
必ずconfigファイルを経由させましょう。
// config/business.php
return [
'shipping' => [
'free_threshold' => env('SHIPPING_FREE_THRESHOLD', 5000),
],
];
// コード内
if ($cart->total >= config('business.shipping.free_threshold')) {
$shipping = 0;
}
鉄則:コード内ではenv()を使わず、必ずconfig()を使う
失敗パターン5:定数クラスが乱立して管理不能になる
よくある失敗例
app/Constants/UserStatus.php
app/Constants/UserType.php
app/Constants/UserRole.php
app/Constants/UserPermission.php
app/Enums/Status.php
app/Enums/StatusType.php
...
良かれと思って定数クラスを作りすぎて、逆にどこに何があるか分からなくなるパターンです。
回避策
関連する定数はなるべくまとめることを意識しましょう。
// app/Constants/User.php
namespace App\Constants;
class User
{
// ステータス
public const STATUS_INACTIVE = 0;
public const STATUS_ACTIVE = 1;
public const STATUS_SUSPENDED = 2;
// タイプ
public const TYPE_FREE = 1;
public const TYPE_PREMIUM = 2;
// ロール
public const ROLE_USER = 'user';
public const ROLE_ADMIN = 'admin';
}
使うときはUser::STATUS_ACTIVEのように呼び出せば、意味も明確です。
予防と習慣化:二度と増やさないために
ハードコーディングを減らすのも大事ですが、これ以上増やさない仕組みを作ることが最も重要です。
習慣1:コードを書く前に「この値、変わる可能性は?」と自問する
新しくコードを書くとき、数値や文字列を書く前に一瞬立ち止まりましょう。
自問すべき質問
- この値、将来変更される可能性はあるか?
- 環境によって値が変わる可能性はあるか?
- 他の人がこの値の意味を理解できるか?
これを習慣にするだけで、ハードコーディングは激減します。
習慣2:PRテンプレートにチェック項目を追加する
GitHubやGitLabのPRテンプレートに、チェック項目を追加しましょう。
## チェックリスト
- [ ] ハードコーディングしていない(数値、URL、固定文字列など)
- [ ] 環境依存の設定は`.env`と`config`に記載した
- [ ] マジックナンバーは定数化した
これがあるだけで、PR作成者もレビュアーも意識するようになります。
習慣3:定期的にgrepで洗い出す
月に1回、簡単なgrepコマンドでハードコーディングの兆候をチェックしましょう。
# 疑わしい数値リテラルを探す
grep -r "=== [0-9]" app/
# 疑わしいURL
grep -r "http://" app/
grep -r "https://" app/
# メールアドレスの直書き
grep -r "@" app/ | grep -v "param" | grep -v "return"
完璧なチェックはできませんが、目視で怪しい箇所を拾い上げるきっかけになります。
習慣4:静的解析ツールを導入する
余裕があれば、静的解析ツールを導入すると、自動でハードコーディングを検出できます。
Laravel向けのツール例
- PHPStan / Larastan:型チェックとコード品質チェック
- PHP_CodeSniffer:コーディング規約チェック
- Rector:自動リファクタリング
特にPHPStanは導入が簡単で、マジックナンバーや型の問題を検出してくれます。
composer require --dev phpstan/phpstan
./vendor/bin/phpstan analyse app
最初はエラーが大量に出るかもしれませんが、少しずつレベルを上げていけばOKです。
習慣5:新メンバーからのフィードバックを歓迎する
新しく入ったメンバーほど、「これ、なんでこうなってるんですか?」と素朴な疑問を持ちます。その質問こそ、ハードコーディングや分かりにくいコードの兆候です。
「その疑問、すごくいい視点ですね!一緒に改善しましょう」
このスタンスを持つことで、チーム全体の品質意識が高まります。
まとめ:最初の一歩を踏み出そう
ここまで、Laravel現場でのハードコーディング解消について、実践的な内容を解説してきました。最後に、重要なポイントをおさらいしましょう。
今日から実践できること
1. 新しく書くコードから意識する
いきなり既存コードを全部直そうとせず、まずは今日から書くコードで実践しましょう。
2. 環境設定を.envとconfigに移す
最も効果が高く、今すぐできる改善です。APIのURLや外部サービスのキーから始めましょう。
3. マジックナンバーを定数クラスに置き換える
app/Constantsディレクトリを作って、意味のある定数名で管理しましょう。
4. ビジネスルールを設定ファイルに切り出す
頻繁に変わる閾値や係数は、config/business.phpにまとめましょう。
チームで進めるときの心構え
- 小さく始めて成功体験を積む:一気にやろうとしない
- 優しく共有する:押し付けではなく、提案として伝える
- 完璧を目指さない:8割改善できればOK
- 習慣化する:PRテンプレートやレビューで自然と意識できる仕組みを作る
最後に
ハードコーディングの解消は、技術力の高さを誇示するためのものではありません。チーム全体の開発体験を向上させ、保守性を高め、バグを減らすための現実的な取り組みです。
完璧なコードを目指す必要はありません。今日より少しだけマシな状態にする。その積み重ねが、半年後、1年後に大きな差を生み出します。
あなたがこの記事を読んだ後、最初の一歩を踏み出せることを願っています。
さあ、明日から始めましょう。まずは.envファイルを開くところから。