はじめに
私は学習目的でバイブコーディングをしています。
この記事では、私がどのようにバイブコーディングと学習を結び付けているか を解説します。
以前、「まず、TODOアプリを作りまくろう ~AI時代の駆け出しWebエンジニアへ~」という記事を書きました。
この記事で紹介した学習方法は、次のステップで構成されています。
- AIに小さいTODOアプリを作ってもらう
- コードを写経する
- 自力で(またはAIを細かく使って)もう一度作る
- 振り返り+本を読んで体系化する
本記事では、ステップ1である「バイブコーディング」そのもの に焦点を当てます。
また今回の対象読者はWebエンジニアに限らず、題材もTODOアプリに限らず何でも構いません。
目的は、
ステップ2以降の学習効果を高めるために、ステップ1をどう扱うか
を整理することです。
結論:実装プロセスを GitHub 上に残す
先に結論を書くと、ポイントは次の通りです。
- 実装フェーズごとに Pull Request を切る
- 学習用のドキュメントを作る
- ターミナルで動作する AI エージェントに GitHub CLI を操作させて自動化
- main ブランチを保護し、必ず PR 経由でマージする(できれば)
- CI/CD を導入し、フェーズ単位でエラーや失敗を記録する(できれば)
なぜ PR を細かく切るのか
この学習スタイルは
『プログラマー脳 ~優れたプログラマーになるための認知科学に基づくアプローチ』
という書籍に影響を受けています。
この書籍では、
「なぜベテランプログラマーはコードをスラスラ読めるのか」
といった疑問を、認知科学の観点から解説しています。
私が理解した要点は以下です。
- 脳には短期記憶と長期記憶がある
- 短期記憶の容量はおよそ5つ前後で、人による差は大きくない
- 読解時は、長期記憶にある知識を使って情報を「チャンク化」する
- ベテランプログラマーはコードをパターンとしてチャンク化して読んでいる
- 初級プログラマーは長期記憶のパターンが少なく、すぐ短期記憶が埋まってしまう
つまり、一度に大量のコードを読むこと自体が、初学者には不利 だということです。
そこで私は、
「PR単位でコードを読む」=「認知負荷をコントロールする」
という方法を取っています。
学習用のドキュメントを作る
PRが完成したら次は理解するフェーズです。
私はバイブコーディングで生成されたコードを読みながら
学習用のドキュメントを並行して作成 しています。
このドキュメントの主な役割は次の2つです。
- 「なぜこの実装になっているのか」を言語化する
- 後述するフラッシュカードの素材を集める
フラッシュカードで「読めるコード」を増やす
『プログラマー脳』では、長期記憶にパターンを蓄積する方法としてフラッシュカード が紹介されています。
フラッシュカードとは、英単語学習で使う「表に単語、裏に意味を書くカード」のようなものです。
また、初級プログラマーが短期記憶の容量を使い切ってしまう原因はプログラミング言語の構文が身についてないことだと言及されてもいます。
TypeScript におけるフラッシュカードの例
例えばAIに
私はTypeScript初学者です。このコードを理解する前提となる知識をフラッシュカードにしてください
など指示すると以下のようなフラッシュカードを作ってくれます。
-
表:
Array.prototype.map
裏:配列の各要素を変換して新しい配列を返す。元の配列は変更しない。 -
表:
unknownとanyの違い
裏:anyは何でもできてしまうが、unknownは型チェックなしでは使えない。 -
表:
Promise<T>
裏:非同期処理の最終的な結果がT型になることを表す。 -
表:
readonly
裏:再代入はできないが、オブジェクトの中身が完全に不変になるわけではない。
これらはすべて、「コードを読んでいて一度つまずいたポイント」 です。
PRごとにコード量を抑えているため、
- どこで詰まったかが明確
- カード化する対象を選びやすい
というメリットがあります。
もちろんフラッシュカードは物理的なカードではなくマークダウンファイルで十分です。
バイブコーディングを学習に変えるための PR 運用
ここまでを踏まえて、実際の運用です。
PR の例(理想はかなり細かく切る)
PRは「機能単位」ではなく、「理解単位」 まで分解できるといいです。
以下は「GETエンドポイントを1つ追加する」場合の例です
| 順序 | PRタイトル |
|---|---|
| 1 | feat: GET /todos のルーティングを追加 |
| 2 | feat: GET /todos 用のハンドラ関数を作成 |
| 3 | feat: DBクライアントを初期化する処理を追加 |
| 4 | feat: todos を取得する repository 関数を追加 |
| 5 | feat: GET /todos で repository を呼び出す |
| 6 | feat: レスポンスDTOを定義 |
| 7 | test: GET /todos の正常系テストを追加 |
この粒度にすることで、
- 1PRあたりの差分が非常に小さい
- 「このPRでは何を理解すればいいか」が明確
- 実装意図を自分の言葉で説明しやすい
という状態を作れます。
結果として、
- 短期記憶の消費を抑えてコードを読める
- PRごとにフラッシュカードを作れる
- 「この書き方はどこで使われるのか?」を紐付けて覚えられる
という、学習に最適な単位になります。
ただPR細かく制御するにはどの粒度で実装すればいいかを知っている必要があるので、
そこは何度も実践することで身に着けていきたいところです。(AIも勝手にたくさん実装してしまう難しさもある)
ターミナル AI エージェント × GitHub CLI
個人開発でPRを毎回手動で作るのは手間ですが、GitHub CLI(gh) を使うと負担を大きく減らせます。
gh pr create
--title "feat: データベーススキーマを追加"
--body "このPRでは初期のDBスキーマを追加します"
これらのコマンドをターミナルで動作する AI エージェントに実行してもらう ことで、
- ブランチ作成
- 実装
- PR 作成
- 変更内容の要約
といった作業をまとめて任せられます。
main ブランチ保護
main ブランチに保護をかけることで、
- 直接 push を禁止
- PR 経由でのみマージ可能
といった運用ができます。
これにより、
- 変更が必ずPRとして残る
- 実装の履歴がフェーズ単位で整理される
という効果が得られます。
なお、プロンプトでルールを明示しておけば十分な場合も多く、必須ではありません。
CI/CD で失敗も記録する
CI/CDを導入すると、テストの自動化だけでなく、
- どのフェーズでエラーが起きたか
- どう修正したか
が明確に残ります。
フェーズ単位でPRを切っていれば、
- フェーズAでCI失敗
- 修正PR
- 原因と対応をREADMEやIssueに記録
といった形で、トラブルシューティングのログ を蓄積できます。
まあバイブコーディングで生成されたテストコードに意味があるのかは疑問ですが、テストコードの読み方・書き方を学ぶ という観点では十分に価値があると考え、私は実践しています。
まとめ
- バイブコーディングは、そのままでは学習になりにくい
- PRを実装フェーズごとに切ることで、認知負荷をコントロールできる
- 学習用ドキュメントとフラッシュカードで「読めるコード」を増やせる
- GitHub CLI と AI エージェントで運用コストは下げられる
- PR・CIログ・失敗の記録そのものが、将来の学習資産になる
おわりに
この記事はポッドキャスト「ひまじんプログラマーの週末エンジニアリングレッスン」のコミュニティ「ひまプロ談話室」のアドベントカレンダーの記事です。
バイブコーディングでの生成物をよりよくするためにはプロンプトの語彙を増やすことが重要ですが、ポッドキャストはまさに語彙を増やすことに向いています!
例えば以下のエピソードで登場する"SOLID原則"や"宣言的なコード"などはプロンプトの作成にも有用です!
また、Slackコミュニティ「ひまプロ談話室」ではいろんなエンジニアと技術話や雑談ができるので是非参加してみましょう!