リファクタリング

外部の振る舞いを変えずにコードの内部構造を改善し、保守性と可読性を向上させる手法

品質設計

リファクタリングとは

リファクタリングは、外部の振る舞い (入出力) を変えずにコードの内部構造を改善し、保守性と可読性を向上させる手法である。Martin Fowler が『リファクタリング』(1999 年) で体系化。

リファクタリング vs 機能追加

観点 リファクタリング 機能追加
外部の振る舞い 変わらない 変わる
テスト 全テストが通る 新しいテストを追加
目的 内部構造の改善 新機能の実装

代表的なリファクタリング

長いメソッドを小さな関数に分割するメソッドの抽出、意図が伝わる名前への変数名の変更、早期リターンでネストを浅くする条件分岐の簡略化、共通関数への重複の除去、引数をオブジェクトにまとめるパラメータオブジェクトなどがある。

メソッドの抽出

// ❌ 長いメソッド
async function processOrder(event: any) {
  const body = JSON.parse(event.body);
  if (!body.productId) throw new Error('Missing productId');
  if (!body.quantity || body.quantity < 1) throw new Error('Invalid quantity');
  const product = await db.get({ TableName: 'products', Key: { id: body.productId } });
  const total = product.price * body.quantity;
  await db.put({ TableName: 'orders', Item: { id: uuid(), total, ...body } });
  return { statusCode: 201, body: JSON.stringify({ total }) };
}

// ✅ 抽出後
async function processOrder(event: any) {
  const input = parseInput(event);
  const validated = validateOrder(input);
  const total = await calculateTotal(validated);
  const order = await saveOrder(validated, total);
  return formatResponse(201, order);
}

早期リターン

// ❌ ネストが深い
function process(user: User | null) {
  if (user) {
    if (user.active) {
      if (user.verified) {
        return doSomething(user);
      }
    }
  }
  return null;
}

// ✅ 早期リターン
function process(user: User | null) {
  if (!user) return null;
  if (!user.active) return null;
  if (!user.verified) return null;
  return doSomething(user);
}

リファクタリングの安全網

安全網 説明
テスト リファクタリング前にテストを書く
型チェック TypeScript が変更の影響を検出
小さなステップ 1 つずつ変更してテスト
Git いつでも元に戻せる

いつリファクタリングするか

タイミング 説明
機能追加の前 コードを理解しやすくしてから追加
バグ修正の前 原因を見つけやすくする
コードレビューで指摘 レビューの指摘を反映
ボーイスカウトルール 触ったコードを少し綺麗にする

リファクタリングについては関連書籍でも詳しく扱われている。

関連用語