🔖

【AI駆動開発】Cursor@ファイル指定で404 Not Found未実装バグ修正

はじめに

こんにちは。エンジニア 兼 講師のShotaです。

普段はエンジニアとしてAIツールを実案件に適用しながら開発を行い、同時に講師として得られた知見を体系化して受講生の方にお伝えする活動をしています。

AIツールを実案件に適用する際に事前に知っておくべき実践的なTipsのシリーズ第4回。今回のテーマは「【AI駆動開発】Cursor@ファイル指定で404 Not Found未実装バグ修正」です。

※本記事の内容は「AI駆動開発実践コース」での知見をもとにしています

前回の振り返りと課題

前回は、AIツールを使ったリファクタリングにおいて、以下の2つのポイントが効果的であることを確認しました:

  • タスクを細分化すること
  • ファイル名を指定して明確な指示を出すこと

今回は、これらの手法がバグ修正においても有効なのかを実際のコード例とともに検証します。

補足: 本記事で紹介するプロンプトとコードは、実案件で実際に適用したタスクと同一の内容ですが、機密保持の観点から実際のプロンプトやコードを模した形で再構成しています。ただし、AIツールへの指示方法や修正アプローチの本質的な部分は実案件での実体験に基づいています。

実際に発生したバグ事例

実案件のテスト中に以下のようなバグが発見されました。

バグの概要

  • 発生事象: 存在しないリソースの削除処理時、エラーメッセージを表示すべきところ、成功メッセージが表示される
  • 期待する動作: エラーメッセージが表示される
  • 実際の動作: 成功メッセージが表示される

AI駆動バグ修正の基本フロー

AIを活用した開発においても、基本的なバグ修正の流れは通常の開発と同様です:

  1. 事象整理 - 期待する動作と実際の動作とのギャップを整理
  2. 原因特定 - バグの直接原因と根本原因を特定
  3. 修正実施 - 原因に応じた修正を実装

通常の開発とAI駆動開発との違いは、各ステップでAIに原因の提案や実際の修正を依頼できる点です。

ステップ1:事象整理

1. 事象整理
  存在しないリソースの削除処理時、エラーメッセージを表示すべきところ、成功メッセージが表示される

ステップ2:原因特定

直接原因の仮説: 存在しないリソースを削除しようとしていることから、バックエンド側で削除処理前にリソースの存在チェックを実施していないことが想定される

コード確認:

修正前のコード(問題のあるコード)

// server/routes.ts - 削除処理
app.delete("/api/tasks/:id", asyncHandler(async (req, res) => {
  // ❌ 存在チェックなし
  await db.delete(tasks).where(eq(tasks.id, parseInt(req.params.id)));
  res.status(204).end();
}));

確認の結果、削除処理前に存在チェックが実装されていないことが判明しました。

根本原因の特定:
さらに調査を進めると、編集処理でも同様の問題があることが分かりました:

修正前のコード(類似問題)

// server/routes.ts - 編集処理
app.put("/api/tasks/:id", asyncHandler(async (req, res) => {
  // ❌ 存在チェックなし
  const updatedTask = await db.update(tasks)
    .set({
      title: req.body.title,
      description: req.body.description,
      status: req.body.status,
      updatedAt: new Date()
    })
    .where(eq(tasks.id, parseInt(req.params.id)))
    .returning();
  res.json(updatedTask[0]);
}));

原因のまとめ:

2. 原因特定
  直接原因:削除処理前に対象リソースの存在チェックを実施していない
  根本原因:各処理前に対象リソースの存在チェックを実施していない

ステップ3:修正実施

実施すべき修正:

3. 修正実施
  削除処理前に対象リソースの存在チェックを実施する
  編集処理前に対象リソースの存在チェックを実施する

AIツールを使った効率的なバグ修正

前回の手法(タスクの細分化 + ファイル名指定)をバグ修正に適用してみます。

①タスクの細分化

大きなタスクを以下のように分割:

  • 大きなタスク: 存在チェックの追加
  • サブタスク1: 削除処理前の存在チェック追加
  • サブタスク2: 編集処理前の存在チェック追加

②ファイル名を指定した明確な指示

サブタスク1:削除処理前の存在チェック追加

指示内容:

@server/routes.ts

このコードに削除処理前の存在チェックを追加してください。

修正結果(削除処理):

// 修正前
app.delete("/api/tasks/:id", asyncHandler(async (req, res) => {
  // ❌ 存在チェックなし
  await db.delete(tasks).where(eq(tasks.id, parseInt(req.params.id)));
  res.status(204).end();
}));

// 修正後
app.delete("/api/tasks/:id", asyncHandler(async (req, res) => {
  const taskId = parseInt(req.params.id);
  const task = await db.select().from(tasks).where(eq(tasks.id, taskId)).limit(1);
    
  // ✅ 存在チェック追加
  if (!task.length) {
    return res.status(404).json({ message: "リソースが見つかりません" });
  }
  await db.delete(tasks).where(eq(tasks.id, taskId));
  res.status(204).end();
}));

サブタスク2:編集処理前の存在チェック追加

指示内容:

@server/routes.ts

このコードに編集処理前の存在チェックを追加してください。

修正結果(編集処理):

// 修正前
app.put("/api/tasks/:id", asyncHandler(async (req, res) => {
  // ❌ 存在チェックなし
  const updatedTask = await db.update(tasks)
    .set({
      title: req.body.title,
      description: req.body.description,
      status: req.body.status,
      updatedAt: new Date()
    })
    .where(eq(tasks.id, parseInt(req.params.id)))
    .returning();
  res.json(updatedTask[0]);
}));

// 修正後
app.put("/api/tasks/:id", asyncHandler(async (req, res) => {
  const taskId = parseInt(req.params.id);
  const task = await db.select().from(tasks).where(eq(tasks.id, taskId)).limit(1);
    
  // ✅ 存在チェック追加
  if (!task.length) {
    return res.status(404).json({ message: "リソースが見つかりません" });
  }
  const updatedTask = await db.update(tasks)
    .set({
      title: req.body.title,
      description: req.body.description,
      status: req.body.status,
      updatedAt: new Date(),
    })
    .where(eq(tasks.id, taskId))
    .returning();
  res.json(updatedTask[0]);
}));

検証結果:手法の汎用性

今回のバグ修正において、前回のリファクタリングで使用した手法が非常に効果的であることが確認できました:

✅ タスクの細分化の効果

  • 削除と編集を別々のサブタスクに分割することで、AIが各修正を正確に理解
  • 修正内容を段階的に確認でき、手戻りを最小限に抑制
  • 各修正の影響範囲が明確で、レビューが容易

✅ ファイル名指定の効果

  • @server/routes.tsの指定により、AIが修正対象ファイルを正確に認識
  • 修正箇所が明確で、意図した通りの実装が実現

まとめ

今回の検証を通して、前回のリファクタリング編、今回のバグ修正編を通して、以下の手法が様々な場面で高い効果を発揮することが実証されました:

  • タスクの細分化 - 複雑な修正を小さな単位に分割
  • ファイル名指定 - @マークを活用した明確な修正対象の指定

これらの手法は確実に使える実践的なテクニックであることが分かりました。

手法の汎用性について

リファクタリングとバグ修正という異なる用途で同じアプローチが効果的だったことから、以下の知見が得られました:

効果的なAIツール活用の共通パターン

  • 作業の細分化により、AIの理解精度と実装品質が向上
  • 具体的な対象指定により、意図した修正が実現
  • 段階的な確認により、手戻りを最小限に抑制

適用可能な開発場面

  • リファクタリング(エラー処理の共通化など)
  • バグ修正(存在チェック追加など)
  • その他の修正作業全般

AIツールを効果的に活用するには、技術的な理解だけでなく、適切な指示方法を身につけることが重要です。今回紹介した手法は、実案件で実証済みの実践的なアプローチとして、様々な開発場面で活用できるでしょう。

次回予告

次回はリファクタリング編、バグ修正編で学んだメソッドを振り返りつつ、AI駆動開発を加速するメソッドを大解剖していきます。

リファクタリング編・バグ修正編で学んだ手法の正体を明らかにしつつ、その他の効果的なメソッドの概要、そして各メソッドがAIツール活用のための実践メソッドとしてどのように体系化されているのかを確認していきます

この記事が参考になりましたら、ぜひいいねをお願いします。このシリーズは不定期更新のため、最新情報をすぐに受け取りたい方はフォローしていただけると幸いです。

AI駆動開発実践コース

Discussion