2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

リファクタとテストのバランス:安全な変更と進化可能な構造

Posted at

概要

TDDの三原則は「Red → Green → Refactor」と表現されるが、
最も誤解されがちなのが 「Refactor」の扱い である。

本稿では、TypeScript + Vitest を使った実例を通して、
TDDにおけるリファクタリングの意義、タイミング、テストとの相互関係を設計視点から深掘りする。


1. リファクタは「書き直し」ではない

❌ 書き直し ≠ リファクタ

  • 書き直し:挙動が変わる
  • リファクタ:挙動を変えずに構造を改善する

✔️ リファクタとは「振る舞いを保ったまま、設計だけを進化させる行為」


2. 実例:TDDでFizzBuzzをリファクタする

✅ 初期状態(Green済み)

export function fizzbuzz(n: number): string {
  if (n % 15 === 0) return 'FizzBuzz'
  if (n % 3 === 0) return 'Fizz'
  if (n % 5 === 0) return 'Buzz'
  return String(n)
}

✅ テストが保証している状態

import { describe, it, expect } from 'vitest'
import { fizzbuzz } from './fizzbuzz'

describe('fizzbuzz', () => {
  it('returns "FizzBuzz" for 15', () => {
    expect(fizzbuzz(15)).toBe('FizzBuzz')
  })
  it('returns "Fizz" for 3', () => {
    expect(fizzbuzz(3)).toBe('Fizz')
  })
  it('returns "Buzz" for 5', () => {
    expect(fizzbuzz(5)).toBe('Buzz')
  })
  it('returns number string otherwise', () => {
    expect(fizzbuzz(2)).toBe('2')
  })
})

3. Refactor:構造改善をテストに守られながら行う

const rules: [number, string][] = [
  [15, 'FizzBuzz'],
  [3, 'Fizz'],
  [5, 'Buzz'],
]

export function fizzbuzz(n: number): string {
  for (const [divisor, word] of rules) {
    if (n % divisor === 0) return word
  }
  return String(n)
}

✅ テストが全て通っている → 振る舞いは保たれている

  • 可読性・保守性が向上
  • テストが「不変性の保証」として機能

4. TDDにおける「安全な進化」の戦略

項目 説明
リファクタの開始条件 Green状態。全テストが通っていること
リファクタの目的 重複の除去、関心の分離、責務の明確化
リファクタの限界 振る舞いを変えない範囲でのみ行う(変えるならRedから)

5. テストによって保証される「設計の自由」

TDDのテストは、仕様を保証するためだけではない。
それは**「安全な変更を可能にする境界線」**でもある。

✅ テストが存在すると…

  • 構造を壊す不安がない
  • 改善の自由度が高まる
  • 進化できる設計が実現する

設計判断フロー

① この変更は振る舞いに影響を与えるか? → YES → Redから設計変更

② テストはすべて通っているか? → YES → Refactorに入れる

③ 重複・密結合・肥大化があるか? → YES → 分離・抽象化・責務の再配置

④ 実装の都合でテストが壊れやすくなっていないか? → YES → テスト構造も整理

よくあるミスと対策

❌ テストを書かずに構造を変えてしまう

→ ✅ Green状態 + テスト網 がないリファクタは「賭け」


❌ 「振る舞いは同じ」の確認ができない

→ ✅ テストが網羅していなければ、それはRefactorではない


❌ テストが脆く、構造変更で頻繁に壊れる

→ ✅ テストも「設計の一部」。リファクタしやすい構造に保つこと


結語

TDDの最終工程である「Refactor」は、設計を進化させるための権利である。
そして、その権利はテストによって保証されている。

  • RedとGreenで振る舞いを定義し
  • Refactorで構造を洗練する
  • テストによってリスクなき進化が可能になる

TDDとは、
“コードの正しさを守りながら、設計を攻められる構造を作るための進化戦略である。”

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?