リファクタリングとは?
イントロダクション:リファクタリングを一言で言うと? 🔧
リファクタリングとは、 「コードの外から見た動作は変えずに、内部の構造だけを良くすること」 です。
バグ修正や新機能追加とは違い、「機能を増やす・直す」のではなく、 同じ振る舞いを、より読みやすく・変更しやすい形で書き直す作業 だとイメージしてください。
「ちょっと読みにくい」「この辺がモヤっとする」と感じたコードを、 少しずつキレイに整えていく、 日常的な“お掃除と片付け”のような活動 がリファクタリングです。
1. なぜリファクタリングを学ぶ必要があるの?(現場ですぐ役立つ理由)
実務のコードは、一度書いて終わりではなく、 何度も仕様変更や機能追加が入るのが普通 です。
そのたびに場当たり的に書き足していると、コードが次のような状態になっていきます。
-
同じような処理のコピペが増える
ちょっとした仕様変更でも、あちこちのコピペを全部直さないといけない。 -
1つの関数・クラスがなんでも屋になる
条件分岐だらけで、「どこを直せばいいのか」が分かりづらくなる。 -
変更が怖くなる
動いてはいるけど、触ると壊れそうで誰も手を入れたがらない“ブラックボックス”が生まれる。
リファクタリングは、こうした 「技術的負債」 を少しずつ返済し、 「変更しやすい状態」を保ち続けるための基本テクニック です。 長く生きるシステムほど、リファクタリングの有無で差がつきます。
2. 「書き直し」「作り直し」とどう違うの?
似た言葉として「リライト」「全面改修」「作り直し」などがありますが、 リファクタリングはそこから目的が少し違う ことを押さえておきましょう。
-
リファクタリング
外から見た動作・仕様は変えずに、コードの構造・名前・分割の仕方を改善する。 テストが通っていれば成功、とみなせる種類の変更。 -
仕様変更・機能追加
ユーザーから見た動きや画面が変わる。 要件定義の変更に対応するための、新しい振る舞いを足す・変える変更。 -
全面的な作り直し
アーキテクチャや技術選定ごと変えるような大きな変更。 動作も構造も大きく変わることが多い。
リファクタリングを 「仕様変更のついで」 ではなく、 それ自体が独立した作業(振る舞いは変えない、構造だけ改善する) として扱えると、 変更の影響範囲を考えやすくなり、失敗もしにくくなります。
3. どんなとき・どう進める?(安全に小さく進めるコツ) 🧪
リファクタリングは、 いきなり大規模にやろうとしない のがポイントです。 現場では次のような流れで、小さく安全に進めることが多いです。
-
1. テスト(動作確認手段)を用意する
自動テストが理想ですが、最低限「この操作をするとこう動く」といったチェック手順を決めておく。 リファクタリング後も同じ動作になるかを確かめるための「物差し」です。 -
2. 気になる“におい”を見つける
長すぎる関数・重複したコード・意味の分かりにくい名前など、 違和感のある箇所をピンポイントで選ぶ(コードの「悪いにおい」を嗅ぎ分けるイメージ)。 -
3. 小さなステップで書き換える
関数を1つに分割する、名前を変える、重複を1か所にまとめる…など、 一歩ごとにテストを回せるサイズ で変更する。 -
4. こまめにコミットする
テストが通った小さな変更ごとにコミットしておくことで、 いつでも戻せる安全ネットを確保する。
このサイクルを 機能追加やバグ修正の前後に少しずつ挟んでいく習慣 ができると、 時間をかけずに、でも着実にコードベースが整っていきます。
図解:プログラミングにおける「リファクタリング」
リファクタリングは、外から見た振る舞いを変えずに、 コードの内部構造を改善することです。読みやすさ・変更しやすさを高め、 バグを埋め込まないよう小さなステップで行います。
リファクタリングを理解する 3 つの視点
1. ゴール:振る舞いはそのまま、構造だけをきれいに
ユーザーから見た動きは変えずに、 「変更に弱いコード」から「変更に強いコード」へと作り替えるのが目的です。
2. サイクル:小さなステップ+テストの繰り返し
リファクタリングはいきなり大改造しないのが鉄則です。 テスト(自動テスト or 手動確認)を安全網にして、細かい変更を積み重ねます。
現状の振る舞いを固定
1〜2 手の変更に限定
通ったらコミット
この 3 ステップを何度もぐるぐる回しながら、少しずつ構造を整えていきます。
3. 対象:どこをどう整えるか
リファクタリングは「きれいにする」ではなく、 狙いを決めてコードの形を変える作業です。代表的な的(まと)は次の 3 つです。
- 関数・変数・クラス名を意図が伝わる言葉に
- 意味の重複やあいまいな略語をなくす
- 長い関数を分割(メソッド抽出など)
- 重複ロジックを共通化
- UI とドメインの処理を分ける
- クラス・モジュールの責務を 1 つに寄せる
JavaScriptで見る「リファクタリング」の例
ここでは、同じ「データ取得 → 計算 → 表示の整形」を題材に、 リファクタリング前(Before)と リファクタリング後(After)を見比べます。 外から見た挙動は変えずに、コードの内部構造だけを整えるイメージです。
Before:1つのイベントハンドラに「取得・計算・表示」がベタ書きされたコード
クリックイベントの中に、データ取得・合計計算・ フォーマット・描画がすべて押し込まれています。 動きは分かりやすい反面、仕様変更やテストには弱い形です。
// 今日の売上合計を表示するボタン
document.getElementById('show-today-sales').addEventListener('click', function () {
const resultEl = document.getElementById('today-sales-result');
resultEl.textContent = '読み込み中...';
// API から全売上一覧を取得
fetch('/api/sales')
.then(function (res) {
if (!res.ok) {
throw new Error('API error');
}
return res.json();
})
.then(function (data) {
// 今日の日付文字列を作成(YYYY-MM-DD)
const now = new Date();
const yyyy = now.getFullYear();
const mm = ('0' + (now.getMonth() + 1)).slice(-2);
const dd = ('0' + now.getDate()).slice(-2);
const todayStr = yyyy + '-' + mm + '-' + dd;
// 今日の売上だけに絞って合計
let total = 0;
for (let i = 0; i < data.length; i++) {
const row = data[i];
if (row.date === todayStr) {
total += row.amount;
}
}
// 金額フォーマットをその場で実装
const formatted = total
.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
// 結果の HTML をここで直接組み立て
if (total === 0) {
resultEl.innerHTML = '<p>本日の売上はありません。</p>';
} else {
resultEl.innerHTML =
'<p>本日の売上合計:<strong>' +
formatted +
'</strong> 円</p>';
}
})
.catch(function (err) {
console.error(err);
resultEl.innerHTML =
'<p class="error">売上の取得に失敗しました。</p>';
});
});
イベントハンドラの中にすべての処理が詰め込まれているため、 「対象期間を変える」「表示形式を変える」といった変更のたびに この長い関数を直接いじる必要があります。
After:振る舞いはそのまま、中身を分割したコード
同じ「今日の売上合計を表示する」機能ですが、 日付計算・集計ロジック・描画処理を それぞれ独立した関数に切り出しています。 結果として、テスト・再利用・仕様変更がしやすい形になります。
// ---- ドメイン寄りの小さな関数群 --------------------------
function formatDateYYYYMMDD(date) {
const yyyy = date.getFullYear();
const mm = ('0' + (date.getMonth() + 1)).slice(-2);
const dd = ('0' + date.getDate()).slice(-2);
return `${yyyy}-${mm}-${dd}`;
}
function formatCurrencyJPY(amount) {
return amount
.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
/**
* 売上配列から、指定した日付の合計金額を計算する
* @param {Array<{date: string, amount: number}>} sales
* @param {string} targetDate YYYY-MM-DD
*/
function calculateTotalSalesForDate(sales, targetDate) {
return sales
.filter((row) => row.date === targetDate)
.reduce((sum, row) => sum + row.amount, 0);
}
/**
* API から全売上一覧を取得する
* @returns {Promise<Array<{date: string, amount: number}>>}
*/
function fetchAllSales() {
return fetch('/api/sales').then((res) => {
if (!res.ok) {
throw new Error('API error');
}
return res.json();
});
}
/**
* 計算結果を DOM に描画する
* @param {HTMLElement} container
* @param {number} total
*/
function renderTodaySales(container, total) {
if (total === 0) {
container.innerHTML = '<p>本日の売上はありません。</p>';
return;
}
const formatted = formatCurrencyJPY(total);
container.innerHTML =
'<p>本日の売上合計:<strong>' +
formatted +
'</strong> 円</p>';
}
// ---- UI 側:イベントハンドラは「流れ」を組み立てるだけ --------
document.getElementById('show-today-sales').addEventListener('click', function () {
const resultEl = document.getElementById('today-sales-result');
resultEl.textContent = '読み込み中...';
const todayStr = formatDateYYYYMMDD(new Date());
fetchAllSales()
.then((sales) => {
const total = calculateTotalSalesForDate(sales, todayStr);
renderTodaySales(resultEl, total);
})
.catch((err) => {
console.error(err);
resultEl.innerHTML =
'<p class="error">売上の取得に失敗しました。</p>';
});
});
イベントハンドラは「読み込み中表示 → データ取得 → 集計 → 描画」という 処理の流れだけを表現し、 個々のロジックは専用の関数に追い出されています。 「対象日付を変える」「期間合計にする」「グラフ表示にする」といった変更も、 関数単位で見通しよく修正できます。
まとめ:リファクタリング習慣のポイント
- リファクタリングは、 「動作を変えずに、コードの構造だけを良くする」 ための作業です。
- 放置すると増えていく 技術的負債(読みづらさ・変更しづらさ) を、少しずつ返していくための基本テクニックです。
- 仕様変更や作り直しと違い、 振る舞いは変えない ことが前提なので、 テスト(動作確認の物差し)と「小さなステップ」が重要になります。
- 日々の開発の中で「モヤっとしたら、まず小さく整える」という リファクタリング習慣を身につけることで、 長く変化し続けるシステムを支えやすくなります。
まずは、 「動作は変えずに、ちょっとだけ読みやすく・直しやすくする」 ところから始めてみると、 リファクタリングの感覚がつかみやすくなります。
関連原則 🔗
このページの著者
経験:Webアプリ/業務システム
得意:PHP・JavaScript・MySQL・CSS
個人実績:フォーム生成基盤/クイズ学習プラットフォーム 等
詳しいプロフィールはこちら! もちもちみかんのプロフィール