AI開発アンチパターン 2025年6月8日

AI生成スパゲッティコード:なぜ保守できなくなるのか

AIには、コード生成における「お気に入りのパターン」があります。 このような「モンスター関数」が、AIによって大量生産されます。 CodeRabbitの2025年調査は、AI生成コードの品質を客観的に測定しました。

川西智也

合同会社ロイヤルピース 代表

アンチパターン⑤「スパゲッティ大量生産」

AIの「お気に入り」

AIには、コード生成における「お気に入りのパターン」があります。

「AIはモノリシックな関数を書くのが大好きだ。1つの300行の関数で、APIからデータを取得し、3種類の変換を行い、エラーを処理し、データベースを更新し、メールを送信する。まさに『手続き型スパゲッティの傑作』だ」

このような「モンスター関数」が、AIによって大量生産されます。


【統計データ】AI開発の現実

CodeRabbitの2025年調査は、AI生成コードの品質を客観的に測定しました。

AI生成 vs 人間作成:

指標AI生成人間作成倍率
PR当たりの問題数10.836.451.68x
ロジックエラー--1.75x
品質・保守性問題--1.64x
可読性問題--3.0x以上
コード重複--4.0x

特に、可読性の問題は3倍以上コード重複は4倍 です。

これは、スパゲッティコードの大量生産を数字で示しています。


AI生成モンスター関数の例

AIが生成しがちなモンスター関数の例を見てみましょう。

async function processUserOrder(userId, orderData, paymentInfo, shippingDetails) {
  // APIからデータをフェッチ(20行)
  const user = await fetch(`/api/users/${userId}`);
  const userData = await user.json();
  
  // バリデーション(30行)
  if (!userData) throw new Error('User not found');
  if (!orderData.items) throw new Error('No items');
  // ... 他のバリデーション
  
  // データ変換1(50行)
  const transformedOrder = {
    ...orderData,
    userId: userData.id,
    // ... 大量のマッピング
  };
  
  // データ変換2(50行)
  const shippingData = {
    // ... また大量のマッピング
  };
  
  // 決済処理(40行)
  const paymentResult = await processPayment(paymentInfo);
  if (!paymentResult.success) {
    // エラーハンドリング
  }
  
  // データベース更新(30行)
  await db.orders.create(transformedOrder);
  await db.inventory.update(/* ... */);
  await db.users.updateLastOrder(/* ... */);
  
  // メール送信(20行)
  await sendEmail(userData.email, /* ... */);
  
  // ログ記録(20行)
  await logActivity(/* ... */);
  
  // Webhook通知(20行)
  await notifyWebhooks(/* ... */);
  
  return result;
}

この関数は 300行以上 で、10以上の責務 を持っています。


なぜモンスター関数が生まれるか

AIがモンスター関数を生成する理由があります。

理由1: トレーニングデータの影響

  • Stack Overflowの回答は「動く」ことが優先
  • チュートリアルは簡潔さを優先
  • 分割より一括の方が「答え」として分かりやすい

理由2: プロンプトの影響

  • 「〇〇機能を作って」と依頼すると、一括で作ろうとする
  • 分割を明示的に指示しないと、分割しない

理由3: コンテキストの制約

  • 複数ファイルにまたがる設計は困難
  • 1つの関数で完結させる方がAIにとって「簡単」

AI生成スパゲッティコードの問題

モンスター関数には、多くの問題があります。

問題1: 単一責任の原則違反

1つの関数が10以上の責務を持つ。変更の理由が10以上ある。

問題2: テスト困難

各責務を個別にテストできない。モック地獄に陥る。

問題3: 再利用不可

「決済処理」だけを別の場所で使いたくても使えない。

問題4: デバッグ困難

300行のどこで問題が起きたか特定困難。

問題5: 変更波及

1箇所を変更すると、他の箇所に影響する可能性。


AI生成コードでDRY原則が崩壊する理由

GitClearの2025年分析は、衝撃的な統計を示しました。

2億1100万行のコード分析:

指標傾向
コードチャーン(短期変更)増加
コードクローン(重複)約4倍増
移動/再利用コード過去最低
DRY原則の遵守崩壊中

AIは「再利用」が苦手です。似たような機能を依頼すると、既存のコードを使わず、新しく生成します。

結果として、同じようなコードがあちこちに散らばる ことになります。


スパゲッティを防ぐプロンプト

スパゲッティを防ぐためのプロンプト戦略があります。

戦略1: 責務を明示

以下の責務を持つ関数を、それぞれ別々に作成してください:
1. ユーザー情報の取得
2. 注文データのバリデーション
3. 決済処理
4. 注文の保存
5. 通知の送信

戦略2: 関数の行数を制限

各関数は30行以下にしてください。
30行を超える場合は、小さな関数に分割してください。

戦略3: 既存コードの再利用を指示

既存のvalidateUser関数を使用してください。
新しく作成しないでください。

リファクタリングの習慣

AIが生成したコードは、そのまま使わず、リファクタリング しましょう。

リファクタリングのチェックリスト:

  1. 関数の行数は30行以下か?

    • 超えていれば分割
  2. 関数の責務は1つか?

    • 複数あれば分割
  3. 重複したコードはないか?

    • あれば共通化
  4. 適切な抽象化レベルか?

    • 詳細と概要が混在していないか
  5. 命名は適切か?

    • 関数名、変数名を確認

AI開発で意識すべき「良い」コードの特徴

AI生成コードを「良い」コードにするために、目指すべき特徴があります。

良いコードの特徴:

  1. 小さな関数

    • 1つの関数は1つのことだけ
  2. 明確な命名

    • 関数名を読めば何をするか分かる
  3. 低い結合度

    • 関数間の依存を最小限に
  4. 高い凝集度

    • 関連する処理をまとめる
  5. テスト可能

    • 各関数を独立してテストできる

この事例から学ぶべき教訓

「スパゲッティ大量生産」から学ぶべきことは以下の通りです。

  1. AIはモンスター関数を生成しがち

    • 300行、10責務の関数
  2. 可読性問題は3倍、重複は4倍

    • CodeRabbit調査
  3. DRY原則が崩壊している

    • AIは再利用が苦手
  4. プロンプトで分割を指示

    • 責務を明示、行数を制限
  5. リファクタリングを習慣化

    • AIの出力をそのまま使わない

まとめ:重要ポイントの振り返り

  • AIは モンスター関数 を生成しがち(300行、10責務)
  • 可読性問題は 3倍以上 、コード重複は 4倍
  • DRY原則が崩壊 、同じコードが散らばる
  • プロンプトで 責務を明示行数を制限
  • AI出力は リファクタリング してから使う
  • 教訓:AIの出力をそのまま使うな、整形せよ

実践的なスキルを習得しませんか?

ブログで学んだ知識を、研修で実践に変えましょう。