ブログ記事
機能を変えずに構造を変える:Martin Fowler『リファクタリング』第2版
「リファクタリング」という言葉は広く使われるが、その定義はあいまいに使われることも多い。Martin Fowler の『リファクタリング 既存のコードを安全に改善する 第2版』は、この行為を厳密に定義し直し、実践可能な技法として体系化した一冊だ。
1. リファクタリングの定義——「改善」ではなく「変換」
本書の定義は明確だ。リファクタリングとは「外部から見た振る舞いを変えずに、内部の構造を改善すること」だ。
この定義が重要なのは、外部の振る舞いが変わるなら、それはリファクタリングではなく機能変更だからだ。両者を同時に行うと、どちらの変更が原因でテストが壊れたか判別できなくなる。本書が推奨するのは「リファクタリングのステップ」と「機能追加のステップ」を意図的に分けることだ。
この区別は、コードレビューやコミット履歴の粒度にも影響する。
2. コードの匂いとリファクタリングの契機
本書の約半分は「コードの匂い(Code Smells)」と各リファクタリング手法のカタログで構成されている。
代表的な匂いとして挙げられるのは、「長い関数」「巨大なクラス」「重複したコード」「長すぎるパラメータリスト」「データの浮遊(Data Clumps)」などだ。これらは直ちに問題が起きているわけではないが、変更に弱い設計のシグナルだ。
匂いを検出したら、対応する手法(例:長い関数 → 関数の抽出)を適用する。この「匂い→手法」の対応関係が整理されているため、感覚的だったリファクタリングの判断を具体的な手順に変換できる。
flowchart LR
subgraph SMELL["コードの匂い(Code Smells)"]
S1["長い関数"]
S2["巨大なクラス"]
S3["重複したコード"]
S4["長すぎる引数リスト"]
end
subgraph RECIPE["リファクタリング手法"]
R1["関数の抽出"]
R2["クラスの分割"]
R3["重複の排除"]
R4["パラメータオブジェクトの導入"]
end
S1 --> R1
S2 --> R2
S3 --> R3
S4 --> R4
style SMELL fill:#fce8e8,stroke:#e53935
style RECIPE fill:#e8f8e8,stroke:#4caf50
3. テストなしのリファクタリングは進めない
本書が一貫して強調するのは、テストがリファクタリングの安全網であるという点だ。
外部の振る舞いが変わっていないことを確認できなければ、リファクタリングが「改善」なのか「壊した」のかが分からない。自動テストが通る状態を保ちながら、小さなステップでコードを変換していく——これが安全なリファクタリングの進め方だ。
逆に言えば、テストが書きにくいコードはリファクタリングもしにくい。テストを書くことが難しいと感じたら、それは設計の問題を示すシグナルでもある。
4. リファクタリングと設計判断
本書が示す重要な観点の一つが、リファクタリングと事前設計の関係だ。
詳細な事前設計よりも、動く小さな実装から始めてリファクタリングで洗練させる方が、実際には良い設計に到達しやすい場合がある。設計は一度決めたら変えられないものではなく、コードが成長する中で継続的に改善するものだという見方は、アジャイルな開発スタイルとも整合する。
本書の第2版はJavaScript(TypeScript)のコード例を多く使っており、フロントエンドを含む現代の開発環境で読みやすくなっている。
5. どんな場面で効くか
「この関数、長くて読みづらいから直したいけれど、下手に触ると別の場所が壊れそうで手が出せない」——本書が最も効くのはこの状況だ。§2で挙げた「長い関数」「重複したコード」といった匂いに気づいても、どこから手をつけるか分からず放置してしまう。本書は匂いごとに対応する変換手順を並べているため、「気持ち悪いのに直せない」状態が「この匂いにはこの手法」という具体的な次の一手に変わる。動いているコードを壊さず構造だけ入れ替える段取りが分かると、レビューで指摘された箇所を、機能を止めないまま小さく直していける。
6. 誰に効き、誰には早いか
向いている人
- 動いているコードに手を入れるたびにどこかが壊れないか不安で、安全に直す手順がほしい
- レガシーコードの改善を任され、闇雲な書き直しではなく段階的な進め方を持ちたい
- コードの匂いには気づけるのに、直し方が感覚頼みで人に説明できない
向いていない人
- 自動テストを書く習慣がまだない人。本書はテストを安全網の前提に置く(§3)ため、先にテストの型を身につけてから戻ると価値が出る。editorial_note も「テストの素養があると価値が一気に上がる」とする
- プログラミングを学び始めたばかりの人。読みやすいコードの形をまだ持っていないなら、先に『リーダブルコード』で「あるべき形」を掴んでから読むと、変換の目的が腑に落ちる
7. 通読するか、辞書として引くか
本書は前半(第1章〜第4章)と後半のカタログに分かれる。前半はリファクタリングとは何か・なぜテストが要るのかという原則を、最初の例を実際に動かしながら通す。ここは順に読む価値がある。特に第3章「コードの不吉な臭い」を読むと、自分のコードのどこが匂うかを言い表す語彙が手に入る。
一方、第6章以降のカタログ(カプセル化・特性の移動・データの再編成・条件記述の単純化など)は最初から通読しなくてよい。editorial_note が言うように、入門段階では辞書として拾い読みするのが現実的だ。実際に匂いに出くわしたとき、対応する手法の項を引く——この読み方だと、手を動かす場面と結びついて記憶に残る。
8. 読んだ後、次にどこへ進むか
本書の手順は「テストがある」ことを前提にする。だが現場には、そもそもテストの無いコードが多い。テストの無いレガシーコードを安全に変えたいなら、次は『レガシーコード改善ガイド』へ進む。依存を切り離す継ぎ目を見つけ、テストで覆って安全網を張ってから構造を直す、という一段難しい局面の進め方が得られる。
別の方向として、「なぜ改善するのか」を問い直す道もある。個々の変換手順が戦術なら、複雑性そのものをどう抑えるかは戦略だ。ここに関心が向いたら『A Philosophy of Software Design』が、リファクタリングの判断に「これは複雑性を減らせているか」という軸を足してくれる。
最初の一歩は、次に匂いに気づいたとき、機能追加とは切り離して変換だけの小さなコミットを一つ作ってみることだ。§1で触れた「振る舞いを変えるコミットと変えないコミットを分ける」を、自分の履歴で一度試してみる。それだけで、リファクタリングがルーティンに変わる。
筆者の体験から
前職の受託開発でtoBの業務システムの改修を任された頃、巨大な条件分岐のあるクラスに手を入れる必要がありながら、下手に触ると別の場所が壊れそうで、結局コピペで分岐を増やして逃げる場当たり対応を繰り返していた。本書のカタログに従い、意味のある処理の塊ごとに関数の抽出を繰り返し、抽出のたびにテストを流して振る舞いが変わっていないことを確認してからコミットする——このステップを守るようになってからは、数十回の抽出の末に一つの巨大な関数が名前の付いた小さな関数の集まりに変わり、レビューでも「差分が読める」と言われるようになった。
不満が残ったのは、後半のカタログを結局通読していないことで、匂いに出くわした時に該当箇所を引く辞書的な使い方に落ち着いている。事前設計より小さく作って直す方がよいという主張も、テストが薄く体制も固まっていない当時のチームでは鵜呑みにできなかった。書き直しではなく変換の積み重ねで形が変わる感覚をつかめたのは、この反復があったからだと思う。
DevBookPath のマップで確認する
この本の前後の読書順は、DevBookPath のグラフで確認できます。
本記事のリンクには Amazon アソシエイト等の広告が含まれる場合があります。リンク経由の購入で運営者に紹介料が支払われることがあります。
この記事を共有
この地図を共有