AI駆動開発でTDDを導入したら、個人開発が想像以上に捗った話
こんにちは。
Your Timeというアプリを個人開発しているKen.Tです。
さて、今日は、個人開発でTDDを導入したら想像以上に捗ったことを記事にまとめました。
著者について
大事なことに集中できるアプリ「Your Time」を開発しています。どんなアプリを作っているか、どんな想いで開発しているかは、以下の記事も参考にしていただけると幸いです。
TDD(テスト駆動開発)とは何か?
TDD(Test Driven Development)は、実装より先にテストを書く開発手法です。
一般的には、次のサイクルで説明されます。
- まず失敗するテストを書く(Red)
- テストが通る最小限の実装を書く(Green)
- コードを改善する(Refactor)
いわゆる Red → Green → Refactorです。
本質はシンプルで、
- このコードは「何を満たすべきか」を先に定義する
- テストは仕様そのものになる
という考え方です。
ただ、個人開発の文脈では、
- 仕様が固まっていない
- とにかく早く動くものを作りたい
- テストを書くコストが重い
と感じがちで、私自身も「チーム開発向けの手法」という印象を持っていました。Claude CodeでのAI駆動開発を前提にした場合、むしろ、TDDを取り入れることで開発速度の向上とコード品質の向上を実感することができました。
AI駆動とテスト駆動を書籍で学ぶ
個人開発におけるテスト戦略
AI駆動開発を実践しているが、個人開発ではやはり一人で開発しているので、リソース配分を戦略的に行う必要があります。
そのため、個人開発では次のように割り切っています。
- すべてをテストしない
- 壊れたら困るロジックに集中する
- UIは無理に自動化しない
特に優先度が高いのは、
- ビジネスロジック(計算・進捗・状態遷移)
- Service層のデータ操作
- 課金や保存など、壊れると致命的な部分
ここにテストがあるだけで、
- 安心してリファクタできる
- 機能追加のスピードが落ちない
- 「この仕様、どうなってたっけ?」と悩まなくなる。とくにAIが。
という効果が出ます。
実際に、Your Timeのアプリでも、課金分の実装をStoreKit 2からRevenueCatに移行する際もTDDを導入したおかげで、安心して移行ができました。(ついでにリファクタリングも進みました)
Claude CodeのスキルとしてTDDを設定する
AI駆動開発でTDDを進めるにあたって、TDDをClaude Codeのスキルとして設定しています。具体的には以下の実装を行う際は、TDDを実践するように定義しています。
- 新しいロジック追加
- バグ修正
- ViewModel / Service 実装
- リファクタリング
ポイントは、
- Red → Green → Refactor の順序を崩さない
- テストには必ず日本語コメントを書く
- テストの主戦場をビジネスロジックに絞る
ことです。
TDDは、AIで正しく開発を進めるためのよい制約条件になりました。一部、簡略化はしていますが、実際にClaude Codeで実践しているSKILL.mdのファイルになります。
ちょっと長いですが、コピペして導入できるように以下の記載しておきます。Swiftでの導入事例です。お使いのプロジェクトに合わせて、変更してお使いください。
---
name: tdd
description: 個人開発プロジェクトのTDD(テスト駆動開発)スキル。新しいビジネスロジック追加、バグ修正、ViewModel/Service実装、リファクタリング時に使用。Red-Green-Refactorサイクルに従い、日本語コメント付きのテストコードを生成します。
---
# TDD(テスト駆動開発)スキル
個人開発プロジェクトにおけるTDD実践のためのスキルです。
## 適用条件
以下の場合にこのスキルを使用してください:
- 新しいビジネスロジックを追加する時
- バグを修正する時
- ViewModelに状態遷移ロジックを追加する時
- Serviceに新しいメソッドを追加する時
- 既存コードをリファクタリングする時
## TDDの主戦場
| 優先度 | 対象 | 具体例 | 理由 |
|--------|------|--------|------|
| **高** | ビジネスロジック | 残り時間計算、進捗率算出 | 仕様の核心 |
| **高** | Service | HighlightManager, TargetDayManager | データ操作の正確性 |
| **中** | ViewModel | 状態遷移 | UI連携の信頼性 |
| **中** | Model | バリデーション、変換ロジック | エッジケースの担保 |
| **低** | View | レイアウト、色 | UIテスト or 手動確認 |
## Red-Green-Refactorサイクル
必ず以下の順序で実装すること:
### 1. Red(失敗するテストを書く)
func test_[メソッド名]_[条件]_[期待結果]() {
// Given(前提条件)
// When(実行)
// Then(検証)
XCTAssertEqual(result, expected)
}
### 2. Green(テストを通す最小限のコードを書く)
- テストを通すだけの実装(ダサくてもOK)
- 過度な最適化は後回し
### 3. Refactor(コードを改善する)
- 重複除去、命名整理、責務分離
- テストが通ったままであることを確認
## テストの命名規則
test_[メソッド名]_[条件]_[期待結果]
例:
- `test_calculateLifeProgress_with30YearsOld_returns37Percent`
- `test_saveHighlight_withEmptyTitle_throwsValidationError`
- `test_fetchTargetDays_whenDatabaseEmpty_returnsEmptyArray`
## テストの基本構造
**重要**: 各テストケースには必ず日本語コメントでテストの目的・内容を説明すること。
import XCTest
@testable import YourTime
final class [対象]Tests: XCTestCase {
// MARK: - System Under Test
var sut: [対象クラス]!
// MARK: - Setup & Teardown
override func setUp() {
super.setUp()
sut = [対象クラス]()
}
override func tearDown() {
sut = nil
super.tearDown()
}
// MARK: - Tests
/// 正常系: [何をテストしているかの説明]
/// - 条件: [前提条件の説明]
/// - 期待結果: [期待する結果の説明]
func test_機能_条件_期待結果() {
// Given(前提条件を設定)
let input = ...
// When(テスト対象のメソッドを実行)
let result = sut.doSomething(input)
// Then(結果を検証)
XCTAssertEqual(result, expected)
}
}
### 日本語コメントの例
/// 正常系: 35歳で平均寿命80歳の場合、進捗率が約44%になることを確認
/// - 条件: 1990年1月1日生まれ、現在2025年1月1日、平均寿命80歳
/// - 期待結果: passedYears=35, remainingYears=45, progressPercent≈0.4375
func test_calculate_with35YearsOld80YearsLife_returnsCorrectProgress() {
// ...
}
/// 異常系: 生年月日が未来の場合、進捗率0%を返すことを確認
/// - 条件: 生年月日が現在より未来
/// - 期待結果: passedYears=0, progressPercent=0
func test_calculate_withFutureBirthDate_returnsZeroProgress() {
// ...
}
/// 境界値: 平均寿命を超えた場合、進捗率が100%で止まることを確認
/// - 条件: 1920年生まれ(105歳)、平均寿命80歳
/// - 期待結果: progressPercent=1.0, remainingDays=0
func test_calculate_withAgeExceedingLifeExpectancy_returns100Percent() {
// ...
}
## バグ修正時のフロー
1. **バグを再現するテストを書く(Red)**
2. **テストが失敗することを確認**(バグの存在を証明)
3. **修正を実装(Green)**
4. **リグレッションテストとして残る**
## チェックリスト
### 新機能開発時
- [ ] テストを先に書いたか(Red)
- [ ] テストが失敗することを確認したか
- [ ] 最小限の実装でテストを通したか(Green)
- [ ] リファクタリングしたか(Refactor)
- [ ] エッジケースのテストを追加したか
### バグ修正時
- [ ] バグを再現するテストを書いたか
- [ ] テストが失敗することを確認したか
- [ ] 修正後、テストが通ることを確認したか
まとめ
「AI駆動開発でTDDを導入したら、個人開発が想像以上に捗った話」のまとめです
- AI駆動開発にTDDを導入することで、開発のスピード、コード品質の向上が見込める
- 個人開発でもとても有効
- TDDをスキルとしてまとめておくと便利
Xフォローしてくれると嬉しいです
Xでも情報発信しているので、フォローしていただけると励みになります!
アプリをダウンロードしてくるともっと嬉しいです
人生の残り時間を可視化し、大事なことに集中できるアプリ「Your Time」を開発しています!ダウンロードお願いします
Discussion