Slide 1

Slide 1 text

実践Claude Code 20の失敗から学ぶAIペアプログラミング 武⽥ 隆志 クラスメソッド株式会社 クラウド事業本部サービス開発室

Slide 2

Slide 2 text

⾃⼰紹介 2 ● 武⽥ 隆志 ● クラスメソッド株式会社 ○ クラウド事業本部サービス開発室 ● ソリューションアーキテクト ● Claude Code使⽤歴: 約4ヶ⽉(2025年6⽉〜10⽉)

Slide 3

Slide 3 text

本⽇お持ち帰りいただくもの 3 ● AIの「クセ」と現実への理解 ● 向き合い⽅を考える視点 ● 実践で活かせる気づき

Slide 4

Slide 4 text

本⽇のアジェンダ 4 ● はじめに ● 20の失敗パターン ○ 基本的な⾏動パターンの問題 ○ コード品質とデバッグ ○ テストと検証 ○ 環境‧プロジェクト管理 ○ 致命的な喪失とドキュメント ● まとめ

Slide 5

Slide 5 text

Claude Codeとは 5 ● AI「Claude」によるエージェント型開発CLI ● ターミナルから⾃然⾔語で対話しながら、コード⽣成‧Git操作 ‧テスト実⾏などを⾃律的に進める

Slide 6

Slide 6 text

Claude Codeとは 6 モデルの進化 時期 モデル 特徴 2024年6⽉ Claude 3.5 Sonnet ⾼速‧⾼性能化 2025年2⽉ Claude 3.7 Sonnet 推論特化 2025年5⽉ Claude Sonnet 4 性能向上 2025年9⽉ Claude Sonnet 4.5 コーディング性能⼤幅向上

Slide 7

Slide 7 text

AIペアプログラミングの現実 7 ● 使い始めて感じたこと ○ 「コード⽣成が速い!」「テストも書いてくれる!」 ● でも、実際に使い続けると…… ○ 指⽰を無視して勝⼿に効率化 ● 同じミスを何度も繰り返す ○ 「完了しました」→ エラーだらけ これらの「あるある」、どう対処します か?

Slide 8

Slide 8 text

それでもAIペアプログラミングをする理由 8 ● 失敗はあるが、適切に使えば強⼒ ○ コーディング速度の⼤幅向上 ○ 定型作業の⾃動化 ○ テストコード⽣成の効率化 ○ ドキュメント作成の⽀援 「失敗パターンを知り、適切に使う」ことが重要

Slide 9

Slide 9 text

実例から学ぶ 20の失敗パターン

Slide 10

Slide 10 text

基本的な⾏動パターンの問題 失敗1〜6

Slide 11

Slide 11 text

失敗1: 指⽰を無視した効率化 11 問題: 「1ファイルずつ精査して」→ grep⼀括検索に切り替え 影響: ユーザーの本来⽬的が未達成 # 指示: ファイルを1つずつ開いて確認してください # AI行動: $ grep -i "error\|fail\|timeout" **/*.ts # 作業偽装: 「確認しました」(実際は読んでいない)

Slide 12

Slide 12 text

失敗1: 対処法 12 対策 ● 明確な指⽰ ○ 「grepは使わず、ファイルを1つずつReadツールで開く」 ● 進捗確認 ○ 各ファイルごとに報告を求める ● 中断も辞さない ○ 指⽰違反が続く場合は即座に中断

Slide 13

Slide 13 text

失敗2: プロアクティブな⾏動 13 問題: 確認なく勝⼿にコミット‧デプロイ 影響: 未完成コードのコミット、意図しないデプロイ # ユーザー: このコードはどういう意味? # AI: 修正しました(問題は聞かれていない) # AI: 修正完了です # AI: コミットしてデプロイします(確認なし) $ cdk deploy --all # 確認なく実行

Slide 14

Slide 14 text

失敗2: 対処法 14 ● CLAUDE.mdに明記すべきルール ○ 質問には説明で答える(勝⼿に修正しない) ○ コミットは明⽰的指⽰がある場合のみ ○ 推測でなく確認

Slide 15

Slide 15 text

失敗3: 作業完了前のチェック不⾜ 15 問題: 「完了しました」→ その後エラー発⾒ 影響: 不正なコードのまま作業継続 # AI: 修正が完了しました! # ユーザー: 本当?確認して $ npm run lint # エラー... $ npm run test # エラー...

Slide 16

Slide 16 text

失敗3: 対処法 16 ● CLAUDE.mdに必須チェックを明記 ● Hooks機能で強制実⾏ // .claude/settings.json { "hooks": { "PostToolUse": [{ "matcher": "Write|Edit", "hooks": [{ "type": "command", "command": "cd \"$CLAUDE_PROJECT_DIR\" && npm run lint" }] }] } }

Slide 17

Slide 17 text

失敗4: 既存実装の確認不⾜ 17 問題: 既存機能があるのに重複実装 ● よくある流れ: ○ ユーザー: 「その実装もうありませんでしたっけ?」 ○ AI: 「確認しますね」(ここで初めて検索) // 既存実装(src/cli/index.ts:72) .option('--verbose', 'detailed output') // AI実装(新規) .option('-v, --verbose', 'verbose mode') // → 重複!

Slide 18

Slide 18 text

失敗4: 対処法 18 ● AIに実装前の確認を徹底させる ○ 「実装前に既存の類似機能を確認する」と指⽰ ○ CLAUDE.mdに「新規作成より既存ファイルへの追加を優 先」と明記 ● 重複実装してしまった後の対処 ○ 既存実装の場所を明⽰: 「src/cli/index.ts:72に同じ機能があ ります」 ○ 統合を指⽰: 「既存実装を拡張する形で実装して」 ○ 重複コードの削除を確認

Slide 19

Slide 19 text

失敗5: 指摘事項の繰り返し 19 問題: ⼀度修正しても次で同じミス 影響: 同じレビューの繰り返し、チームの疲弊 # 1回目: 指摘前 sys.path.append('./src') # ❌ # 指摘後: 修正 def test_func(monkeypatch): monkeypatch.syspath_prepend('./src') # ✅ # 2回目: また同じミス sys.path.insert(0, './src') # ❌ 過去の指摘が反映されていない

Slide 20

Slide 20 text

失敗5: 対処法 20 ● CLAUDE.mdにルールを明記 ○ 既存コードのパターンを踏襲する ○ プロジェクト規約を必ず確認してから実装 ● ⼈間側の対処 ○ 繰り返しがちなミスと対処をCLAUDE.mdに明記 ○ AIが同じミスを繰り返したら「確認して」 ○ 既存コードの該当箇所を明⽰的に⽰す

Slide 21

Slide 21 text

失敗6: 対処法の不安定 21 問題: 同じ問題への対処が毎回違う 影響: コードの⼀貫性が失われる、レビュー混乱 # 1回目: アンダースコア def handler(event, _context): # 2回目: ignoreコメント def handler(event, context): # noqa: ARG001 # 3回目: またアンダースコアに戻る def handler(event, _context):

Slide 22

Slide 22 text

失敗6: 対処法 22 ● CLAUDE.mdにルールを明記 ○ プロジェクト規約を確認 ○ 既存コードのパターンを踏襲 ○ 対処法を統⼀する

Slide 23

Slide 23 text

コード品質とデバッグ 失敗7〜11

Slide 24

Slide 24 text

失敗7: シンプル作業の複雑化 24 問題: ファイル分割など単純なリファクタリング指⽰で機能追加 影響: PR複雑化、レビュー困難、コード肥⼤化 // feature/new-api ブランチで初実装 function processData() { } // 同じブランチでリファクタリング function processDataV2() { } // V2? /** @deprecated 後方互換のため */ function processData() { } // なぜ残す?

Slide 25

Slide 25 text

失敗7: 対処法 25 ● CLAUDE.mdに原則を明記 ○ 同⼀ブランチ内では古いコードは削除 ○ まだマージされていない = 後⽅互換不要 ● 作業完了時の追加指⽰ 実装完了後、以下を確認して不要なものを削除 - V2/Enhanced/New などのプレフィックスやサフィックス - @deprecated マークを付けた実装 - 後方互換のための古いコード

Slide 26

Slide 26 text

失敗8: 型安全性の軽視 26 問題: ⾯倒を避けてanyで逃げる 影響: 型システムの利点を無効化 // 要件: "eliminate 'any' types" // AI実装: const data = response as any // 型定義は後で...(放置) // または古い記法(Python 3.9+なのに) from typing import List, Dict # ❌ def process(items: List[str]) -> Dict[str, int]: # ❌

Slide 27

Slide 27 text

失敗8: 対処法 27 ● CLAUDE.mdにルールを明記 ○ TypeScript ■ 型ガード‧型アサーションを適切に使⽤ ■ unknown → 型述語を活⽤した型チェック ● Linter設定で⾃動検出 // tsconfig.json { "compilerOptions": { "noImplicitAny": true, "strict": true } } // pyproject.toml [tool.pyright] typeCheckingMode = "strict"

Slide 28

Slide 28 text

失敗9: ショットガンデバッグ 28 問題: 複数の変更を⼀度に実⾏、何が効いたか不明 影響: 不要な変更の蓄積、再現不可能 // エラー発生 // → 推測1: タイムアウト → timeout延長 // → 推測2: メモリ不足 → NODE_OPTIONS追加 // → 推測3: 非同期 → await追加 // 全部一度にコミット(原因不明)

Slide 29

Slide 29 text

失敗9: 対処法 29 ● CLAUDE.mdに原則を明記 ○ 1回の変更で試すのは1つの仮説のみ ○ 変更内容を事前に説明 ○ テスト → 効果確認 → 報告 ○ 効果なければ戻してから次へ ● 実際には都度の明確な指⽰が重要 ○ 「まず○○だけ試して」 ○ 「他は触らないで」 ○ 「結果を⾒てから次を判断」

Slide 30

Slide 30 text

失敗10: エラーメッセージ無視 30 問題: エラーを読まずに推測で解決 影響: 的外れな修正、時間の浪費 // エラー: "Cannot read property 'name' of undefined" // AI: タイムアウトを延長(的外れ) // エラー: "Module not found: 'axios'" // AI: ネットワーク設定を変更(見当違い) // 正解: npm install axios

Slide 31

Slide 31 text

失敗10: 対処法 31 ● CLAUDE.mdに原則を明記 ○ エラーメッセージから原因を特定 ○ 推測での対処を避ける ● 実際には事後の軌道修正が重要 ○ AIの対処が的外れだと感じたら即座に中断 ○ エラーメッセージを引⽤して再調査させる ○ 「このエラーをもう⼀度読んで」

Slide 32

Slide 32 text

失敗11: コメント品質の問題 32 問題: WHATではなくWHYを書くべき 影響: コードの意図が不明、保守性低下 # ❌ 悪い例(WHAT) # ユーザーリストを取得する users = get_users() # ✅ 良い例(WHY) # MFA未設定ユーザーのセキュリティリスク検証のため users = get_users()

Slide 33

Slide 33 text

失敗11: 対処法 33 ● CLAUDE.mdにルールを明記 ○ WHATでなくWHYを書く ○ コードを読めば分かることは書かない ○ 「なぜ必要か」を明確に ● 明⽰的に修正を指⽰ ○ 「コメントを⾒直してWHY重視に修正して」

Slide 34

Slide 34 text

テストと検証 失敗12〜14

Slide 35

Slide 35 text

失敗12: カバレッジ妥協 35 問題: 低カバレッジで「完了」判断 影響: 未テストコードの本番投⼊ // カバレッジ: 37.5% // AI: テスト完了しました! it.skip('flaky test', () => { // TODO: 後で修正 }); coverageThreshold: { branches: 90 → 50, // 一時的な変更が恒久化するリスク functions: 90 → 70 }

Slide 36

Slide 36 text

失敗12: 対処法 36 ● CLAUDE.mdにルールを明記 ○ 主要なロジックは必ずカバー ○ 安易なテストスキップを避ける ○ 勝⼿にカバレッジ⽬標を変更しない ● 繰り返しカバレッジ向上を指⽰ ○ 「カバレッジが低いファイルを洗い出し、カバレッジを向 上させて」

Slide 37

Slide 37 text

失敗13: 実在しないメソッド使⽤ 37 問題: 存在しないAPIメソッドを使⽤ 影響: 本番で初めてエラー発覚 # コード実装 client.describe_invalid_method() # 存在しない # ユニットテスト(モック) mock_client.describe_invalid_method = Mock() # → テストは通る # 本番環境 # → AttributeError

Slide 38

Slide 38 text

失敗13: 対処法 38 ● ファクトチェックで対処 ○ コードレビュー時に「このメソッド実在する?」 ○ 怪しいと思ったら公式ドキュメントのURLを⽰して確認させ る ○ 必要に応じて統合テストを追加指⽰

Slide 39

Slide 39 text

失敗14: テスト駆動の逆⾏ 39 問題: 正常なコードをテストに合わせて壊す 影響: 実装がロールバックするあるいは不正な状態になる ● コード修正完了 → 動作確認OK ● テストコード修正 → テスト失敗 ● 誤判断: 「コードをテストに合わせる」 ● 結果: 正常だったコードが壊れる

Slide 40

Slide 40 text

失敗14: 対処法 40 ● CLAUDE.mdにルールを明記 ○ 実装→テストの順序を守る ○ テスト失敗の原因を安易に推測しない ● ⼈間が判断する ○ テスト失敗時、AIの対応を鵜呑みにしない ○ コードとテストのどちらが正しいか⼈間が判断 ○ 「コードは正しいので、テストを修正して」と明確に指⽰

Slide 41

Slide 41 text

環境‧プロジェクト管理 失敗15〜17

Slide 42

Slide 42 text

失敗15: 環境差異の考慮不⾜ 42 問題: ローカルでは動くが本番で動かない 影響: デプロイ後に本番環境で障害 # ローカル用の修正 sys.path.append('./src') # ローカルテストは通る # Lambda環境 # → 相対パスが存在せず ImportError

Slide 43

Slide 43 text

失敗15: 対処法 43 ● CLAUDE.mdに確認事項を明記 ○ ローカル vs CI/CD vs 本番環境の違い ○ 相対パス‧絶対パスの扱い ○ パッケージ配布後の実⾏環境 ○ 環境変数の有無 ● 環境を指定して動作確認を指⽰ ○ 「Lambda関数の環境で動作するか検証して」

Slide 44

Slide 44 text

失敗16: プロジェクト固有ルール無視 44 問題: 明記されたルールを忘れる 影響: ワークフロー破壊、作業失敗 # RELEASE.md: "CIの自動バージョン管理 " # AI: package.json を手動で v1.2.0 に変更 # 結果: CI が誤って v1.3.0 に # メモリ: "awsumeを使用してAWSアクセス" # AI: awsume なしでアクセス → 失敗

Slide 45

Slide 45 text

失敗16: 対処法 45 ● CLAUDE.mdに書いても忘れる ○ 重要なルールは作業開始時に改めて明⽰的に指⽰ ○ 「RELEASE.md読んで、バージョン管理⽅法を確認して」 ○ 「awsumeでAWSアクセスしてる?」 ● おかしいと感じたら即座に確認 ○ 「本当にその⽅法で合ってる?ドキュメント確認して」 ○ プロジェクト固有の慣習を都度リマインド

Slide 46

Slide 46 text

失敗17: 技術仕様の誤認 46 問題: 試⾏錯誤だけで仕様を確認しない 影響: 実現可能な機能を諦める # タスク: JSONPath → JSONata 変換 # AI: 修正 → エラー → 修正 → エラー # AI: 「JSONataはサポートされていません」(誤判断) # 実際: サポートされている(公式ドキュメント確認不足)

Slide 47

Slide 47 text

失敗17: 対処法 47 ● AIが諦めたら疑う ○ 「本当にサポートされていない?公式ドキュメント確認し て」 ○ WebFetchやWebSearchで最新情報を調査させる ○ 試⾏錯誤だけで判断させない ● 具体例 ○ 「JSONataはサポートされていません」→ 「AWS Step Functions公式ドキュメントで確認して」

Slide 48

Slide 48 text

致命的な喪失とドキュメント 失敗18〜20

Slide 49

Slide 49 text

失敗18: git操作で作業喪失 49 問題: 知らないうちに破壊的git操作で修正内容を消失 影響: 作業が完全に失われる(最も深刻) # 知らないうちに実行されている $ git stash # コミット整理のため退避 → 復元忘れ $ git restore file.ts # 戻しすぎて修正分も消失 $ git checkout -- . # 未コミット変更を全破棄 # 結果: 復旧できず再実装

Slide 50

Slide 50 text

失敗18: 対処法 50 ● 未コミット変更を作らせない ○ 「作業ごとに都度コミットして」と指⽰ ○ 知らないうちにstash/restoreされることがあるので注意 ● コミット整理のワークフロー # 原則AIに都度コミットさせる # 整理する段階で以下を実行(ミスしても backup-before-reset から復元可能) $ git branch backup-before-reset $ git reset --soft HEAD~3 # AIに改めて適切な粒度で整理させる 「未コミットファイルを確認し、論理的な単位でコミットして」 # ※ rebase -i, add -p などの対話的操作は苦手

Slide 51

Slide 51 text

失敗19: ファイル内容喪失 51 問題: 誤った⼿順でファイル削除 → 内容忘却 影響: コード内容の完全喪失、復元不可能 # ❌ 危険な手順 $ rm old-file.ts # 削除 # → オートコンパクション発動 # → コード内容を全て忘れる # ✅ 安全な手順 $ cp old-file.ts new-file.ts # 作成 # 内容を移動・修正 $ rm old-file.ts # 削除

Slide 52

Slide 52 text

失敗19: 対処法 52 ● 未コミットファイルを作らない ○ 新規ファイル作成後はすぐ「コミットして」 ○ ファイル削除を伴う作業前に「まずコミットして」 ● ※現実的には ○ 削除挙動を事前に⽌めるのは困難(常に監視できない) ○ 起きた後の復元も未コミットなら不可能 ○ Git履歴に残すことが唯⼀の保険

Slide 53

Slide 53 text

失敗20: 実装とドキュメントの乖離 53 問題: 説明と実装が⼀致しない 影響: デバッグ困難、信頼性の低下 # 報告: "デバッグログを追加しました " # 実際: ログが全く出ていない # 報告: "完全に機能しています " # 実際: まだ完成していません # ドキュメント: "3つのオプション" # 実装: 5つのオプションが存在

Slide 54

Slide 54 text

失敗20: 対処法 54 ● 「完了」を信じない ○ AIの報告を鵜呑みにせず、⾃分で仕様書と実装を照合 ○ 「仕様書の○○項⽬、本当に実装されてる?該当コード⾒ せて」 ○ 「テストは全部パスしている?」 ● 繰り返しチェックさせる ○ 「ドキュメントと実装が⼀致しているか確認して」 ○ 各機能ごとに照合を繰り返す ○ 疑わしい箇所は動作確認

Slide 55

Slide 55 text

失敗から学んだこと 55 20のパターンを通じて⾒えてきたもの ● AIの現実を知る ○ メモリだけでは不⼗分、都度の指⽰が必要 ○ Git履歴が唯⼀の保険 ● ⼈間が主導する ○ おかしいと思ったら即座に⽌める、軌道修正 ○ ファクトチェックの習慣、盲信しない ● 明確に伝える ○ 曖昧さを排除、具体的な指⽰

Slide 56

Slide 56 text

これは私が4ヶ⽉で辿り着いた考えです あなたなら、どう向き合いますか?

Slide 57

Slide 57 text

ご清聴ありがとうございました

Slide 58

Slide 58 text

No content