31章 リファクタリング
リファクタリングとは“ふるまいを変えずに、設計を少しだけ良くする行為の連続”である
TDDは「書く→通す→整える」だけではない。
設計を“進化”させ続ける作業がリファクタリングである。
- RED:仕様を定義する
- GREEN:とにかく動かす
- REFACTOR:設計を育てる
リファクタリングとは
振る舞いを変えず、設計だけを改善する作業
実例:Template Method パターンが生まれる瞬間
リファクタ前
class FeeCalculator
{
public function calculate($type, $amount)
{
if ($type === 'A') {
return $amount * 1.1 + 100;
}
if ($type === 'B') {
return $amount * 1.05 + 200;
}
if ($type === 'C') {
return $amount * 1.2 + 50;
}
}
}
起きている問題
- if 文が雪だるま式に増殖
- テストも type ごとに増加
- 共通処理/差分処理が絡み合う
リファクタリング指針
「同じアルゴリズム構造が複数出てきたなら、“枠組み”を抜き出せ」
税率を取得
手数料を足す
合計を返す
リファクタ後(Template Method)
abstract class FeeCalculator
{
final public function calculate($amount)
{
$rate = $this->rate();
$fee = $this->fee();
return $amount * $rate + $fee;
}
abstract protected function rate();
abstract protected function fee();
}
class TypeAFee extends FeeCalculator
{
protected function rate() { return 1.1; }
protected function fee() { return 100; }
}
class TypeBFee extends FeeCalculator
{
protected function rate() { return 1.05; }
protected function fee() { return 200; }
}
- 処理手順=共通化
- 差分=安全に分離
- if地獄 から脱出
どうやって TDD から生まれるのか?
Step1
test_type_a_fee();
Step2
test_type_b_fee();
→ if 分岐化
Step3
条件・計算式の重複増大
→ テスト準備も複雑化
Step4
- REFACTOR
共通構造を抽出
差分をメソッド化
クラス分離
リファクタリングのチェックポイント
| サイン | 行うべき改善 |
|---|---|
| if,elseif の増加が止まらない | Strategy / Template |
| テスト準備が巨大 | Fixture抽出 |
| 計算コード重複 | メソッド抽出 |
| new が増えすぎ | Factory導入 |
| Nullチェック連発 | Null Object |
アンチパターン
-
GREENになった勢いで設計変更
テスト未実行
ビルド通ってない -
「綺麗にしたい欲」で改変
目的不在のクラス分割・抽象化 -
大リファクター一気実行
差分が追えない
REDの原因不明
最後に
「このコード、テスト書きにくいな」
その違和感を“今すぐ小さく直す”