🐠

わいの生成AIがカスコードばっか出してくるんやが

に公開

こんにちは!
satto workspaceでエンジニアをしている伊藤(@ryo_ito)です。

TL;DR


はじめに

日々業務する中で生成AIツールはなくてはならないものになりました。
わからなかった分野の実装も自然言語で指示するだけで勝手に実装してくれる魔法のツール!
強靭!無敵!最強!
足りない知識を補ってくれる最高のツールだ!

そんなふうに考えてた時期が自分にもありました。

出力されたコードは確かに動いてはいる。
確かに動いてはいるけどなんで動いているのかよくわからない。

そんなこんなで出てきたコードを"まぁええか"でレビューを出すと生成AIを使っているのに、なぜかコードレビューで大量の指摘が入る

十中八九そうなると思います。
頭のいい生成AIが出力したコードなのにどうして?
できるエンジニアも使ってるじゃん、同じツールなのに、動いてるのにどうして?

実は、生成AIによるコーディングの品質は、プロンプト(指示)の出し方で劇的に変わります。
本記事では、悪い例と良い例を対比しながら、生成AI時代におけるコーディング品質の本質について考えます。


あの人の生成AIなんか自分のより頭良くない?

生成AIツールは同じでも、エンジニアによってアウトプットの質に大きな差が出ています。

  • Aさん: 生成AIでサクサクとコードを書き、レビューもスムーズに通過。開発速度が2倍に。
  • Bさん: 生成AIで書いたコードが「動くけど読みにくい」「バグが多い」と指摘され、結局書き直しに。

この差はどこから生まれるのでしょうか?
同じツールを同じプランで使ってるのになんやこの差は。
働いている中でできる人を観察しているとプロンプト(指示)の具体性自分自身の理解度が重要なことに気づきます。


悪い例:抽象的な指示

プロンプト例

ユーザー一覧を取得するAPIを作って

生成されたコード

// ❌ 悪い例
app.get('/users', async (req, res) => {
  const users = await db.query('SELECT * FROM users');
  res.json(users);
});

何が問題か?

  • エラーハンドリングがない
  • ページネーションの考慮なし
  • 認証・認可のチェックがない
  • レスポンスの型定義がない
  • 全カラムを返している(機密情報の漏洩リスク)
  • SQLインジェクションのリスクがある(この例では直接的ではないが、拡張時に危険)

動くけど、本番環境では使えないコードになっています。


良い例:具体的な指示

プロンプト例

【要件】
- ユーザー一覧を取得するAPIエンドポイントを実装
- Honoフレームワークを使用
- 認証トークンをヘッダーで検証
- ページネーション対応(limit/offset)
- レスポンスはid, name, emailのみ(passwordは除外)
- エラーハンドリング(DB接続エラー、認証エラーなど)
- TypeScriptの型安全性を確保
- Zodでバリデーション

生成されたコード

// ✅ 良い例
import { Hono } from 'hono';
import { z } from 'zod';
import { zValidator } from '@hono/zod-validator';
import { verifyToken } from './auth';
import { db } from './db';

const app = new Hono();

const querySchema = z.object({
  limit: z.string().transform(Number).pipe(z.number().min(1).max(100)).default('20'),
  offset: z.string().transform(Number).pipe(z.number().min(0)).default('0'),
});

app.get(
  '/users',
  zValidator('query', querySchema),
  async (c) => {
    try {
      // 認証チェック
      const token = c.req.header('Authorization')?.replace('Bearer ', '');
      if (!token) {
        return c.json({ error: 'Unauthorized' }, 401);
      }

      const user = await verifyToken(token);
      if (!user) {
        return c.json({ error: 'Invalid token' }, 401);
      }

      // クエリパラメータ取得
      const { limit, offset } = c.req.valid('query');

      // ユーザー一覧取得(安全なカラム指定)
      const users = await db.query(
        'SELECT id, name, email FROM users LIMIT $1 OFFSET $2',
        [limit, offset]
      );

      const total = await db.query('SELECT COUNT(*) as count FROM users');

      return c.json({
        data: users.rows,
        pagination: {
          limit,
          offset,
          total: total.rows[0].count,
        },
      });
    } catch (error) {
      console.error('Error fetching users:', error);
      return c.json({ error: 'Internal server error' }, 500);
    }
  }
);

export default app;

何が改善されたか?

  • ✅ 認証・認可のチェックがある
  • ✅ ページネーション対応
  • ✅ エラーハンドリングが適切
  • ✅ 型安全性が確保されている
  • ✅ 必要なカラムのみ返却(セキュリティ向上)
  • ✅ SQLインジェクション対策(パラメータ化クエリ)
  • ✅ レスポンス構造が明確

あの人の生成AIなんか自分のより頭良くない?の正体

生成AIは魔法ではありません。あなたの頭の中にある実装イメージを、素早く具体化するツールです。

生成AIが得意なこと

  • 既知のパターンを素早くコード化
  • ボイラープレートの自動生成
  • 文法やAPIの正確な記述
  • リファクタリングの提案

生成AIが苦手なこと

  • 要件の曖昧さを補完する
  • ビジネスロジックの最適な設計判断
  • セキュリティリスクの完全な検出
  • プロジェクト固有の文脈理解

つまり、「何を作りたいか」「どう作るべきか」が明確でないと、良いコードは生成されないのです。
上記の例みたく、動くものは作れても認証・認可のチェックを行うとか、
エラーハンドリングをどう行うとか、
型安全にするとか、
そういう細かい部分は自分で指示しないと要件を満たしてくれません。


そのやり方がレビュー地獄を生む

生成AIが出力したコードを、理解せずにそのままコピペしていませんか?
とりあえず動くからええやろ
any使っとるけど良いやろ
なんか可読性にかける実装やけどええやろ
命名規則バラバラやし良いやろ
変数名、関数名分かりづらいし良いやろ
...など。

起こりうる問題

  • セキュリティ脆弱性に気づけない
    • SQLインジェクション、XSS、認証バイパスなど
  • パフォーマンス問題を見逃す
    • N+1クエリ、無駄なループ処理など
  • 保守性の低いコードを量産
    • 命名規則の不統一、責務の不明確さなど
  • ロジックのバグに気づけない
    • エッジケースの考慮漏れ、境界値の処理ミスなど

自分が理解していないコードは、品質が悪くてもロジックが悪くても気づけません。

レビュー者、実装者ともに悲しい結末を迎えます。

実例:気づきにくいバグ

// 生成AIが出力したコード
function calculateDiscount(price: number, discountRate: number) {
  return price - (price * discountRate / 100);
}

// ❌ 問題点:
// - 負の値チェックがない
// - 割引率が100%を超える場合の考慮がない
// - 小数点の丸め処理がない(金額計算では重要)

このコードを理解せずに使うと、割引率が101%のときに価格がマイナスになるといったバグを見逃します。


勉強することの重要性

生成AI時代だからこそ、基礎を学ぶことの重要性が増しています

なぜ勉強が必要か?

  1. 良いプロンプトを書くため

    • 良いプロンプトには、技術的な知識が必要
    • 「どう実装すべきか」を知らなければ、具体的な指示ができない
  2. コードの品質を判断するため

    • 生成されたコードが「良いコード」か「悪いコード」かを見極める
    • セキュリティや性能の問題を検出する
  3. 適切な修正・改善をするため

    • 生成されたコードを、自分のプロジェクトに合わせて調整
    • バグを見つけたときに、正しく修正できる
  4. 新しい技術を組み合わせるため

    • 生成AIは既知のパターンは得意だが、新しい組み合わせは苦手
    • 技術を理解していれば、生成AIを「補助ツール」として活用できる

自然言語だけで、AIだけで作れるのは動くだけの細部に魂のないゴミです。
もちろんプロトタイプで素早く作成もしてくれますが指示を出す人の知識と経験を混ぜることで初めて良いものができると思います。


まとめ

生成AIは、エンジニアの強力なパートナーです。
しかし、ツールは使う人の能力を増幅するだけで、能力を生み出してはくれません

生成AI時代のエンジニアに必要なこと

  1. 具体的な指示を出せる力(要件定義・設計スキル)
  2. 生成されたコードを評価する力(レビュー・品質判断)
  3. 適切に修正・改善する力(実装力・デバッグ力)
  4. 基礎を理解する力(継続的な学習)

生成AIによって「書く時間」は短縮されますが、「考える時間」「学ぶ時間」は変わりません。
むしろ、考える時間と学ぶ時間にこそ、エンジニアの価値が集中する時代になっています。

”わいの生成AIがカスコードばっか出してくるんやが”
そんなことありません。

生成AIは使う人次第で
”あなたの生成AIなんか頭良くない?”
って言われるようになります。

最後まで読んでいただきありがとうございます!
生成AIを「便利な道具」として使いこなし、一緒に成長していきましょう。


参考リンク

ソフトバンク株式会社_satto開発チーム

Discussion