リファクタリングとは?24の観点とタイミング・進め方
リファクタリングとは、ソフトウェアの外から見た振る舞いを変えずに、内部の構造だけを改善する作業です。動作を変えないという一点が、機能追加やバグ修正と決定的に違います。ただ現場で問題になるのは定義そのものではなく、「どのコードを対象に選ぶか」「いつ着手し、いつ見送るか」の判断でしょう。この記事では Martin Fowler と Kent Beck が挙げたコードの不吉な臭い24項目をレビュー観点として整理し、着手基準と見送り基準、安全な進め方までを扱います。
まとめ
リファクタリングの判断は、次の4点に集約できます。
- 定義の核は「外部から見た振る舞いを変えない」こと。振る舞いが変わる改修はリファクタリングではなく、書き直しか機能変更として別に扱います。
- 観点は感覚に頼らず、コードの不吉な臭い24項目をレビューのチェック基準に落とします。実務でまず効くのは Mysterious Name、Duplicated Code、Long Function、Shotgun Surgery、Primitive Obsession の5項目です。
- 着手のタイミングは「その箇所をこれから触るとき」。触る予定がないコード、期日直前、丸ごと作り直す判断が既に立っている箇所は見送ります。
- 「意味ない」という評価の多くは、コード品質と開発速度を切り離して考えていることに由来します。39の商用コードベースを調べた研究では、低品質コードは Jira に登録された欠陥が15倍、課題解決に要する時間は平均124%多いという結果でした。
以下、各項目の根拠と具体的な進め方を順に見ていきます。
リファクタリングの定義と、書き直しとの線引き
Fowlerによる名詞と動詞、2つの定義と目的
Fowler は refactoring.com で、リファクタリングを名詞と動詞の2通りで定義しています。名詞としては「a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior」、動詞としては「to restructure software by applying a series of refactorings without changing its observable behavior」です。
ここで効いてくるのが observable behavior、つまり外から観測できる振る舞いという限定でしょう。内部構造を触った結果、戻り値やAPIの応答、画面表示、ログの意味が変われば、それはリファクタリングの定義から外れます。振る舞いが変わらない限り、変数名を1つ変えるだけでも立派なリファクタリングです。
目的も、この定義文の中に書き込まれています。easier to understand(理解しやすくする)と cheaper to modify(修正を安く済ませる)の2つ。つまりリファクタリングの目的は将来の改修コストを下げることであって、コードを美しくすることではありません。この違いは実務上の判断に直結します。改修予定のないコードをどれだけ整えても、下げるべきコストが発生しないため目的を果たしません。
用語としての初出は、Opdyke と Johnson が1990年9月に発表した論文です。実務の手法として体系化されたのは Opdyke の1992年の博士論文で、その後 Fowler の書籍によって一般に広まりました。日本語版はオーム社『リファクタリング(第2版)既存のコードを安全に改善する』(2019年12月発売、ISBN 978-4-274-22454-6、456頁、訳=児玉公信・友野晶夫・平澤章・梅澤真史)が現行版になります。第2版のサンプルコードは初版の Java から JavaScript に置き換わりましたが、Fowler 自身が「the refactorings are applicable in any language」と述べているとおり、手法そのものは言語に依存しません。
「リファクタ」「リファクト」「refactor」の表記と言い換え
英語表記は refactoring、動詞形が refactor です。日本語の現場では「リファクタ」「リファクト」と縮めて呼ぶことが多く、Git のコミットメッセージやブランチ名では refactor という接頭辞がそのまま使われます。いずれも指しているものは同じで、意味の違いはありません。
日本語に言い換えるなら「内部構造の改善」が最も近い表現でしょう。「コードの整理」「コードのお掃除」といった言い方も通じますが、社外向けの見積書や設計書では避けたほうが無難です。作業内容が軽微に見え、工数として認めてもらいにくくなります。「保守性改善」「内部品質改善」のように、成果物の性質を指す語を使うと説明が通りやすくなります。
書き直し・リアーキテクチャとの判断分岐
混同されやすい作業は、変える対象と振る舞いの扱いで区別できます。
| 作業 | 変える対象 | 外部の振る舞い | 既存テストの扱い |
|---|---|---|---|
| リファクタリング | 内部構造のみ | 変えない | そのまま通す |
| 書き直し(リライト) | 実装全体 | 原則維持だが差異が出る | 作り直しが前提 |
| リアーキテクチャ | 構成要素の境界 | API境界ごと変わる | 結合テストから再設計 |
この区別が効いてくるのは、見積もりとリスクの根拠が変わるからです。リファクタリングは既存テストが通ることを合格条件にできるため、リスクを小さく保てます。書き直しは合格条件そのものを作るところから始まるので、工数もリスクも桁が変わるわけです。「リファクタリングします」と言いながら実態が書き直しになっている提案は、テストをどう扱うかを聞けば見分けがつきます。
リファクタリングの観点:24の不吉な臭いをレビュー基準へ
24項目の一覧と対処手法の対応
「どこを直すべきか」を個人の感覚で決めると、レビューが好みの議論になります。Fowler と Kent Beck が Refactoring 第2版の第3章 Bad Smells in Code(日本語版の章題は「コードの不吉な臭い」)で挙げた24項目は、この判断を共有可能な語彙に変えるためのものです。以下が24項目の全リストと、代表的な対処手法の対応になります。
| 不吉な臭い | 症状 | 代表的な対処手法 |
|---|---|---|
| Mysterious Name | 名前から役割が読めない | Rename Variable |
| Duplicated Code | 同じ処理が複数箇所にある | Extract Function |
| Long Function | 関数が長く分岐が深い | Extract Function |
| Long Parameter List | 引数が多く順序を間違える | Introduce Parameter Object |
| Global Data | どこからでも書き換わる | Encapsulate Variable |
| Mutable Data | 更新箇所を追跡できない | Encapsulate Variable |
| Divergent Change | 1つのクラスが別々の理由で変わる | Extract Class |
| Shotgun Surgery | 1つの変更が多数のファイルに波及 | Move Function |
| Feature Envy | 他クラスのデータばかり参照する | Move Function |
| Data Clumps | 同じ組のデータが常に一緒に現れる | Extract Class |
| Primitive Obsession | 意味のある値を文字列や数値で持つ | Replace Primitive with Object |
| Repeated Switches | 同じ分岐条件が各所に散る | Replace Conditional with Polymorphism |
| Loops | ループの意図が読み取れない | Replace Loop with Pipeline |
| Lazy Element | 実体のない層やクラスが残る | Inline Function |
| Speculative Generality | 使われない拡張点が作り込まれている | Collapse Hierarchy |
| Temporary Field | 特定の場面だけ値が入る属性 | Extract Class |
| Message Chains | オブジェクトを数珠つなぎに辿る | Hide Delegate |
| Middle Man | 委譲するだけのクラスが挟まる | Remove Middle Man |
| Insider Trading | クラス間で内部情報をやり取りする | Move Function |
| Large Class | クラスが担う責務が多すぎる | Extract Class |
| Alternative Classes with Different Interfaces | 同種の役割で呼び出し方が揃わない | Change Function Declaration |
| Data Class | データだけを持ち振る舞いがない | Encapsulate Record |
| Refused Bequest | 継承した機能の大半を使わない | Push Down Method |
| Comments | コメントが分かりにくさを補っている | Extract Function |
原著の英語名で並べたのは、refactoring.com のオンラインカタログや静的解析ツールの表示と突き合わせやすくするためです。日本語版では各項目にも訳語が当てられているので、書籍と照らす際はそちらを参照してください。カタログには2026年8月6日時点で66件の手法が掲載されており、66件すべてが第2版の収録手法にあたります。ただしカタログの個別ページに載るのは Before / After のコードスケッチだけで、適用手順は掲載されていません。手順まで確認したい場合は書籍かWeb版を参照する必要があります。
実務で優先度が高い5項目
24項目を等しく扱う必要はありません。改修コストへの跳ね返りが大きい順に、Mysterious Name、Duplicated Code、Long Function、Shotgun Surgery、Primitive Obsession の5つを先に潰すのが効率的です。
名前と重複は、レビューで指摘しやすく修正も局所的で、リスクがほぼありません。コードの重複は、片方だけ修正して片方が残る不具合の温床になるため、発見したその場で潰す価値があります。Long Function は主観になりがちですが、サイクロマティック複雑度のような数値指標を使えばレビューの合意を取りやすくなるでしょう。
Shotgun Surgery、つまり1つの仕様変更が多数のファイルに波及する状態は、上の4つと性質が異なります。修正範囲がモジュール境界をまたぐため、影響が大きい代わりに効果も大きい項目です。RailsのFat Model対策のように、肥大化したクラスの分割手法を先に決めてから着手すると事故を防げます。
見つけても手を出さない項目
一方で、見つけても後回しでよい項目もあります。代表が Speculative Generality、将来に備えて作り込まれた拡張点です。
これは判断を誤りやすい領域になります。使われていない抽象化に見えても、外部連携やバッチ処理から呼ばれている場合があるためです。利用箇所を静的解析で洗い出せていないうちは削除しないでください。PHPStanのような静的解析ツールで参照を機械的に確認できる状態を作るのが先になります。
Comments も単独では急ぎません。コメントが分かりにくさを補っている状態は確かに臭いですが、コメントを消して関数を切り出す作業は、その関数を次に触るときにまとめて行えば十分です。
「リファクタリングは意味ない」への回答
意味がないと感じる原因
「リファクタリングは意味ない」という評価には、それが出てくる典型的な状況があります。
1つ目は、触る予定のないコードを整えてしまった場合です。改善の効果は「次にそのコードを変更するとき」に初めて回収されるので、二度と触らない箇所を整えても、投じた工数はそのまま失われます。この場合は意味がないという評価が正しく、リファクタリングの選び方の問題になります。詳しい判断基準は後述のタイミングの章で扱います。
2つ目は、テストが無い状態で構造を変え、デグレードを起こした場合です。振る舞いが変わっていないことを確認する手段が無ければ、それは構造改善ではなく無保証の改造でしょう。
3つ目は、成果が数字で示されていない場合になります。「読みやすくなりました」だけでは、工数を承認する側にとって判断材料になりません。修正1件あたりの所要時間や、変更が波及したファイル数といった、改修コストの指標に紐づけて報告する必要があります。
低品質コードの代償を示す実測値
コード品質と開発速度の関係については、公開された定量データがあります。Adam Tornhill と Markus Borg による “Code Red: The Business Impact of Code Quality”(arXiv:2203.04374、2022年3月8日公開、TechDebt 2022 発表)は、39の商用コードベース、30,737ファイルを対象に、ソースコード解析とバージョン管理の履歴、そして Jira の課題情報を突き合わせた研究です。
結果は明確でした。低品質と判定されたコードは Jira に登録された欠陥が15倍、課題の解決に要した時間は平均で124%多く、最大サイクルタイムは9倍に達しています。同論文は冒頭で、技術的負債が開発者の時間の最大42%を浪費しているという先行研究の推計にも触れています。
Fowler も “Is High Quality Software Worth the Cost?”(2019年5月29日)で、熟練開発者への聞き取りをもとに「Developers find poor quality code significantly slows them down within a few weeks」と述べ、品質を犠牲にして速度を得られる期間は数週間しかないと結論づけました。品質と速度はトレードオフではなく、数週間を超える期間で見れば同じ方向を向く。これがこの2つの資料に共通する主張です。
意味がないという主張への回答はこうなります。次に触る予定のあるコードを、テストで保護したうえで直す限り、リファクタリングには効果があります。この2つの条件のどちらかが欠けているとき、その指摘は正しいのです。
リファクタリングのタイミング
着手すべき場面:これから触る直前
判断基準は1つです。そのコードをこれから触るかどうか。触る予定があるなら、触る直前が最良のタイミングになります。
具体的には次の場面が該当します。
- 新しい機能を追加する直前に、追加しやすい形へ構造を整えるとき
- バグ調査でコードを読み解き、理解した内容をコードの形に反映するとき
- 同じような処理を3度目に見かけ、共通化に踏み切るとき
- コードレビューで指摘を受け、その場で直すとき
Fowler は “Opportunistic Refactoring”(2011年11月1日)で、これを計画された作業ではなく日常の一部として扱うべきだと述べ、「But a team that’s using refactoring well should hardly ever need to plan refactoring, instead seeing refactoring as a constant stream of small adjustments that keep the project on the happy curve of the DesignStaminaHypothesis」と書いています。リファクタリング専用のスプリントを確保しなければ回らない状態は、日常の改善が不足しているサインだという指摘です。
見送るべき場面:期日直前と廃止予定
着手しない判断のほうが、投じた工数を無駄にしない効果は大きくなります。次の場面では手を出しません。
触る予定のないコードは対象外になります。動いていて、改修の予定も無く、外部から呼ばれるだけの箇所は、内部がどれだけ汚くてもブラックボックスとして扱う判断が正解です。中身を読めない状態のままでも、外部インタフェースが安定していれば実害はありません。
作り直しの判断が既に立っている箇所も同様です。廃止予定のモジュールや、リプレースが決まっているサブシステムを整えても、成果は破棄されます。この場合に投じるべきなのは、移行先の設計でしょう。
リリース期日の直前も避けます。改善の効果が出るのは期日の後であり、期日前に得られるのはデグレードのリスクだけだからです。ただしこれは「期日直前に見つかった臭いを無視しろ」という意味ではありません。課題として記録し、次に同じ箇所を触るときの着手対象に回します。
安全に進める手順とテストの前提
振る舞いを固定するテストの用意
手順の起点は、コードを触ることではなく、現在の振る舞いを固定することです。対象コードを覆うテストが無い状態で構造を変えれば、変わっていないことを確認する手段がありません。
既存テストが無ければ、まず現在の入出力をそのまま記録するテストを書きます。この段階では、仕様として正しいかどうかを問いません。現状の振る舞いを再現できれば十分です。テスト駆動開発(TDD)のサイクルを既に回しているチームであれば、リファクタリングはそのサイクルの第3ステップとして自然に組み込めます。修正範囲が広い場合は、リグレッションテストの範囲選定をあわせて設計する必要があるでしょう。
テストを整えたら、変更は小さく刻みます。1つの手法を適用するたびにテストを実行し、通ったところでコミットします。この粒度を守れば、問題が起きても直前のコミットへ戻すだけで復旧できるわけです。コード品質管理の自動化ツールをCIに組み込み、テストと静的解析を各コミットで走らせておけば、この刻みを機械的に強制できます。
ガード節への置き換えで見る「振る舞い不変」
振る舞いを変えないという条件が具体的に何を指すのか、Replace Nested Conditional with Guard Clauses を例に確認します。ネストした条件分岐を、早期リターンに置き換える手法です。
// Before: ネストした条件分岐
function payAmount(employee) {
let result;
if (employee.isSeparated) {
result = { amount: 0, reasonCode: "SEP" };
} else {
if (employee.isRetired) {
result = { amount: 0, reasonCode: "RET" };
} else {
result = { amount: employee.baseSalary, reasonCode: "OK" };
}
}
return result;
}
// After: ガード節へ置き換え
function payAmount(employee) {
if (employee.isSeparated) return { amount: 0, reasonCode: "SEP" };
if (employee.isRetired) return { amount: 0, reasonCode: "RET" };
return { amount: employee.baseSalary, reasonCode: "OK" };
}
両者に isSeparated と isRetired の真偽2通りずつ、baseSalary を0・1・300000の3通り、あわせて12通りの入力を与えて戻り値を突き合わせると、差分は0件です(Node.js v26.5.0、2026年8月6日実行)。行数が減ったこと自体は目的ではありません。前段の条件で処理が終わることが読み取れるようになり、後続の条件を読むときに前提を覚えておく必要がなくなります。これが「理解しやすくする」の中身です。
ツールとAIエージェントの使いどころ
IDEの自動リファクタリングで確実に使える手法
Rename や Extract Function のような機械的な手法は、IDE の自動リファクタリング機能に任せるのが安全です。IntelliJ IDEA と Eclipse は参照箇所を構文解析で追跡するため、文字列置換で起きる取りこぼしや誤爆がありません。Visual Studio Code の Rename Symbol は言語サーバが対応している言語であれば同様に追跡できますが、対応する拡張が無い言語ではテキストベースの置換に落ちるので、実行前に対応状況を確認してください。
手作業の一括置換は、コメント内の同名文字列まで巻き込む典型的な事故につながります。名前の変更こそ、ツールに任せる価値が最も高い領域です。
AIエージェントに任せてよい範囲
AIコーディングエージェントは、対象箇所の抽出と手法の提案に向いています。Claude Code の /simplify コマンドのように変更範囲を絞って冗長さを圧縮する用途であれば、レビュー可能な粒度の差分が出てきます。Copilot CLI の Rubber Duckのように、別のモデルへレビューさせて指摘の偏りを減らす使い方も選択肢になるでしょう。
ただし、生成された差分をそのまま受け入れるのは避けます。AIエージェントは振る舞いが変わったかどうかを自力で保証できないからです。テストが緑であることを人間が確認するまで、それはリファクタリングではなく単なる書き換えにすぎません。判断の順序は変わりません。テストで保護し、小さく刻み、1手法ずつ確認します。ツールが速くするのはこの手順の実行であって、手順そのものを省略できるわけではないのです。
よくある質問
リファクタリングとは何ですか?
ソフトウェアの外から見た振る舞いを変えずに、内部構造だけを改善する作業です。Fowler の定義では「理解しやすく、修正コストを下げるために、観測可能な振る舞いを変えずに内部構造へ加える変更」とされています。機能追加やバグ修正と違い、利用者から見た動作は前後で同一です。この性質があるため、既存テストがそのまま通ることを合格条件にでき、リスクを小さく保った状態で改善を進められます。
リファクタリングの観点はどう決めればよいですか?
個人の感覚ではなく、Refactoring 第2版 第3章の「不吉な臭い」24項目をレビューのチェック基準に使ってください。全項目を等しく扱う必要はなく、改修コストへの跳ね返りが大きい Mysterious Name、Duplicated Code、Long Function、Shotgun Surgery、Primitive Obsession の5項目から着手すると効果が出やすくなります。Long Function のように主観が入りやすい項目は、サイクロマティック複雑度などの数値指標を併用するとレビューでの合意を取りやすくなります。
リファクタリングは英語でどう書きますか?「リファクタ」との違いは何ですか?
英語表記は refactoring、動詞形は refactor です。読み方は「リファクタリング」で、現場では「リファクタ」「リファクト」と略されます。Git のコミットメッセージやブランチ名では refactor がそのまま接頭辞として使われることが多く、いずれも指す作業内容は同じです。日本語に言い換える場合は「内部構造の改善」「保守性改善」が近く、見積書や設計書ではこちらを使うと工数の妥当性を説明しやすくなります。
リファクタリングは意味ないと言われるのはなぜですか?
対象の選び方とテストの有無が原因です。今後触る予定のないコードを整えても、改善の効果を回収する機会が来ないため、投じた工数は戻りません。またテストが無い状態で構造を変えると、振る舞いが変わっていない保証が得られず、デグレードとして表面化します。逆に、次に触る予定のあるコードをテストで保護して直す限り、効果は測定可能です。Tornhill と Borg による39コードベースの調査では、低品質コードは Jira に登録された欠陥が15倍、課題解決に平均124%多い時間を要するという結果が出ています。
リファクタリングはいつやるべきですか?
そのコードをこれから触る直前です。新機能を追加する前、バグ調査でコードを読み解いたとき、同じ処理を3度目に見かけたとき、レビューで指摘を受けたときが代表的な場面になります。Fowler も、リファクタリングをうまく使えているチームなら計画を立てる必要はほとんど無く、小さな調整の連続として扱うべきだと述べています。一方、リリース期日の直前、作り直しが決まっている箇所、今後触る予定のない箇所では見送ります。効果を回収する機会が無いか、リスクだけが残るためです。
リファクタリングとリライト(作り直し)はどう違いますか?
外部の振る舞いを維持するかどうか、そして既存テストを流用できるかどうかで分かれます。リファクタリングは内部構造だけを変えるため、既存テストが通ることを合格条件にできる点が特徴です。リライトは実装を作り直すので、テストの再作成が前提になり、工数もリスクも大きくなります。構成要素の境界ごと変えるリアーキテクチャはさらに範囲が広く、API境界の再設計と結合テストの作り直しを伴うでしょう。提案の実態を見分けたいときは、テストをどう扱うかを確認してください。