世界を動かす技術を、日本語で。

あなたがバイブコーディングしているときがわかる

概要

  • コードの生成方法 には関心がないが、 マージされるコードの質 が重要
  • LLM生成コード はプロジェクトの慣習を無視しがち
  • スピード重視 の風潮がソフトウェア品質を損なう懸念
  • 品質・一貫性・長期的な保守性 への配慮の重要性
  • 既存の原則 を守り、LLM活用時も適切な指示が必要

LLM生成コードとプロジェクト慣習

  • コードの生成手法 (手書き、コピペ、LLM利用等)自体は本質的な問題ではない
  • マージされるコード が正しい成果を生み、将来の理解・変更が容易であることが重要
  • LLM生成コード は、プロジェクトの既存ルールや慣習を無視した実装が多い傾向
    • 例:既存のデータ取得ライブラリがあるのに独自HTTP実装
    • 例:既存のユーティリティ関数を再実装
    • 例:グローバル設定の不適切な変更
    • 例:関数型アプローチの中で突然クラスを定義
  • 人間らしさの欠如 が、プロジェクトの一貫性を損なう要因

ソフトウェア開発の本質と課題

  • ソフトウェア開発の本質 は、長期的に保守可能なものを作ること
  • 動くコード を早く書くだけでは不十分
  • 品質・一貫性・保守性 を無視した“スピード重視”の開発は、後の改修コスト増大につながる
  • 過去の知見やパターン を活かし、安定した開発基盤を維持することが重要

スピードと品質のバランス

  • スピードのみを追求 する開発は、短期的な成果を優先しがち
  • 良質な成果物 の提供には、適切な手順と配慮が不可欠
  • 例え話 :カフェで新米バリスタが焦ってコーヒーを作る様子に例えることで、品質より速度を優先する危うさを説明

LLM活用時の注意点と提言

  • LLMは技術的偉業 だが、プロトタイプを本番化するだけでは不十分
  • プロンプトや指示 を工夫し、プロジェクトの慣習や既存ライブラリの利用を明示することが重要
    • 具体的なライブラリ指定
    • 実例提示
    • 小さなファイル単位での指示
  • 新しい原則は不要、既存の開発原則を遵守する姿勢が求められる
  • コードベースの保守性 をモデル任せにしない開発意識

結論:開発者としての姿勢

  • コードの生成方法 ではなく、 成果物の質 にこだわる姿勢
  • 品質・一貫性・長期的な視点 を持った開発姿勢の重要性
  • LLMの活用 も、既存原則の上に成り立つべきであることの再認識

Hackerたちの意見

それは全部本当だね。今のLLMを扱う最適な方法は、アセンブリ言語よりもコンパイル言語が提供する抽象の一歩上にある感じ。普通の英語で何かを説明して、その明確な要件や入力、出力を示せば、LLMは指定したロジックの翻訳としてコードを書いてくれる。LLMを使うときは、彼らが対処しなきゃいけないエントロピーを最小限に抑えるのがベストだよ。トランスフォーマーは基本的に翻訳エンジンだから、生成器としてじゃなくて翻訳者として使うべきだね。とはいえ、数ヶ月ごとに新しいモデルが出てきて、典型的なLLMの欠点から少し解放されて、ちょっと「直感的」に賢くなって、手取り足取りのサポートがあまり必要なくなって、信頼性も増してる気がする。これは単なる進化の自然な過程だと思う。LLMにお金が投入されるほど、彼らは良くなっていく。基本的に彼らは巨大な連想マシンだから、その連想がより大きな抽象を生み出して、世界を理解するための道具の使い方がより堅牢な概念に繋がるんだよね。時間が経つにつれて、LLMに与えたタスクを人間のプログラマーよりも上手にこなせるようになるのは避けられないと思うし、人間がやることのほとんども同じことになるだろうね。

いや、LLMはコンパイラみたいな「抽象」じゃないよ。これはクソみたいな話だ。LLMは確率的なトークン生成器に過ぎない。現実で、LLMを使って作ったものでゴミ箱に捨てないものを作った人に会ったことなんて一度もないし、LLMのレシピで焼いたクッキーを食べたことがあるけど、それは本当に不快だった。いや、LLMは良くならないよ。シンギュラリティのクソみたいな話は2010年代から続いてる。LLMはインターネット全体を消費して、まだ役に立たない。残りのデータはどこから来るんだ?高品質なデータを求める人たちからのメールは詐欺ばっかり。人々は、質が高いのは高いから、簡単に盗めるゴミでこれらを訓練したがってるだけなんだよ。ちょっと考えればわかることだ。この楽観的なクソみたいな宣伝は恥ずかしい。

これは間違ったアナロジーだね。LLMは、コンパイラやインタプリタが高水準プログラミング言語を機械命令に実装するのと同じように、自然言語を高水準コードに「コンパイル」するわけじゃない。プログラミング言語や機械言語は、正確であいまいさのない意味論を目指しているから、意味論が実際に正確かどうかや、コンパイラが仕様を実装できていないバグがあるかどうかを話すのが意味を持つんだ。自然言語は、既存のスタックの上にある単なる高いレベルの抽象じゃない。新しいモデルが出たり、既存のモデルを新しいシードで実行したりすると、異なるコードが出てきて、動作も異なることがある。これがコンパイラの動作じゃないんだよ。

コードを生成するためにLLMを使うときは、リンターやフォーマッターを設定して、厳密な型チェックをたくさん行うのがめっちゃ役立つよ。これは、スタイルルールを知らない人や同意しない人からの貢献を受け始めたときにも同じだね。テストも重要だし。基本的に、自動化されたもので、コードのスタイルや動作を確保するのに役立つものは、コーディングエージェントと一緒に使うとすごく便利になる。彼らは、問題をチェックしたり、可能なら修正したりするために、指示したコマンドをそのまま実行できるからね。

これらのツールが大いに役立つのはわかるけど、記事に挙げられている例(「バイブコーディングの匂い」の下)を防ぐことはできないと思うよ。

これじゃ問題を隠すだけだよね。

LLMは、現在のコードベースの状態だけでなく、歴史的なコミットをコンテキストとして使う必要があるね。私が関わったほとんどのコードベースは、レガシーパターンAから新しくて良いパターンBに移行していく過程を経るんだ。これらの移行は一度で完了することはめったにないから、古いコードが再訪される間、両方のパターンがしばらく残ることが多い。HTTPの例のように、たとえLLMが従うべきパターンを拾ったとしても(実際にはそうならないことが多いけど)、正しいものを選ぶかどうかは運次第だよ。

それは、コミットメッセージが正しく実装されていると仮定しているけど、「このファイルを更新しました」や「バグ修正」みたいなものじゃないってことだね。

具体的にどうやってこれやあれをやるのか、いくつかの例を交えて教えた方がいいね。

これね… 以前、20年の間に何度も買収や名前変更、合併を経た大規模なコードベースに関わったことがあるんだ。辞める頃には、ついにフォーチュン500のグローバル企業の手に渡ってた。必要なAPIコールに合致するコードが見つかることもあったけど、それが2000年代中頃に最後に更新されたもので、実際にはそのタスクの最新のコードじゃない可能性が高かった。でも、特定のクライアントが使うために必要だったから残ってたんだよね。ドキュメントがない似たようなAPIコールもあって、欲しいデータフィールドを返すやつを選ばなきゃいけなかった。

ちゃんとしたCLAUDE.mdを作って、「この部分みたいにコードを書いて、あのレガシー部分みたいなコードは避けて」って書くことができるよ。

でも、その意識が「雰囲気コーダー」に欠けてることが多いんだよね。多くの人は以前はあまりコードを書いてなかったから。

誰も、プロジェクトにすでにあるデータフェッチライブラリがカバーしているエッジケースをすべて含むHTTPフェッチの実装を書くわけがない。 > 誰も、別のモジュールですでに持っているユーティリティ関数を実装しない。 > 誰も、モジュールレベルで行うメカニズムがあるのにグローバル設定を変更しない。 > 誰も、どこでも関数型アプローチを使っているのにクラスを書くわけがない。 俺はこの人が関わったチームで働きたいな。みんな本当にそういうことをやってるよ。

これだね。あらゆる機会に車輪を再発明したり、何かをするための期待される方法を忘れたり無視したり、パターンを混ぜたり、何でもありだね。著者はこれを「バイブコーディング」と呼んでるけど、それはLLMとはあまり関係ないよ。このツールは、急いで何かを終わらせようとしている人や、自分でプロジェクトを構築していない人、経験が足りない人と同じくらいの注意を払っていると思う。特定のチームの特定の人に対するあまりにも微妙でない不満だとしか思えない。「チームの誰もが書かないような方法で書かれている」というのは示唆的だね。この考え方を他の場所に適用するのは非常に注意が必要だ。学術界やアートの世界では、根拠のない指摘がすでに十分あるから。

そういうチームで働いたことあるよ。むしろ、ほとんどそうだった。人間でも機械でも、そういうことをするコードのPRは受け入れないかな。小規模から中規模のプロジェクトで、2~4人の開発者がいる小さめのチームが理想だと思う。クリティカルなソリューションだけど、そういう小さめのプロジェクトが一番いいんだよね。そうすると、開発チームの文化やコンセンサスを築くことができて、品質と納期のバランスが取れる気がする。

誰も、別のモジュールに既にあるユーティリティ関数を実装しようとはしない。これに関しては公平に言うと、私は全く反対するわけじゃないけど、多くの人がユーティリティ関数を再発明するのは、他に存在することを知らないからなんだよね。特に巨大なコードベースでは。これに関しては、PRの中でシニア開発者がコメントすることで大体解決されるけど、その場合、知っている人が1人増えるだけなんだよね。

こういうことは、スピードを重視する職場ではよく起こるんじゃないかな。

彼らはそうだけど、チームにしばらくいるなら、確立されたパターンを見つけて使う方法をもう知っているはずだよ。もし通常なら出さないようなものを提出したら、それは問題だね。

正直言って、こういうことはドキュメントが不十分な大規模なコードベースではよく起こるよね。私は学術研究プロジェクトに関わっていて、ドキュメントには基本的に「コードは自己文書化されている」って書いてあるだけ。CMakeの設定やプロジェクトのビルドについては1、2ページ説明があるけど、内部のクセや期待される規約は自分で理解しないといけない。新しい人が参加すると、よくあることだけど、いろいろと再発明しちゃって、既存の設定を知らないからグローバル設定を変えたりするんだよね。皮肉なことに、コードベースをインデックス化して、特定のことについてLLMに質問するのが一番いい方法だと思う。なぜなら、聞ける人はプロジェクトを去ったか、忙しくて、返事が来るのは1週間後だから。

有能な人はそんなことしないよ。コードはちゃんとしてるのに行動がそうじゃないなら、それはヒントだね。

あなたは著者の主張を見落としてると思う。>「スピードが最も重要な美徳なのか?」もしスピードが最も重要な美徳なら、そういうことが起こるだろう。でもそうじゃないなら、そういうことはずっと少ない頻度で起こる。だって、挙げられた問題は全部技術的負債だから。負債は消えないし、利子がつく。スピードだけが重要なら、出力は指数的に必要だし、その出力で負債を相殺しないといけない。スピードが要素の一つだけど唯一の要素じゃないなら、他の要素と天秤にかける必要がある。負債を賢く引き受けて、払えるときに返すべきだ。でも、ただ負債を抱えて最善を期待する傾向があるように見える。最後に確認したとき、大半の人は負債の扱いがあまり得意じゃなかった。

バイブコーディングのリスクは、良い開発者は少し速くなるかもしれないけど、悪い開発者はめちゃくちゃ速くなることだね。その結果、悪いコードがどんどん生まれる。じゃあ、悪い開発者はバイブコーディングで改善するのか、それともローカルオプティマムにハマってるのか?

それで、いつそれを見ることができるのか考えてたんだけど…私の経験から言うと、平凡な開発者がすぐに悪化することもあるよ。理由は、偽の自信を持つことが多いからだけど、主に生産される量が多すぎるから。もっと正確に言うと、AIが生成するコードには明確なアーキテクチャが欠けてると思う。全体の情報フローや単一責任の原則をほとんど無視してるんだ。AIは「安全な」コードを求めるから、問題をキャッチして、結果を返さないことが多い。実際には、呼び出しコードは結果を確認して、プレースホルダーかどうかを見極める必要があるんだ。そうじゃないと例外が発生するから自信を持てない。似たように、問題を避けるためにAIがパラメータを調整することもある。例えば、AIを使って何かを処理するプログラムを設計するとしたら、gather_parameters -> call -> process_resultsの流れになるべきなんだ。呼び出しはパラメータで変なことをしちゃいけない、集める段階で固定されるべきだから。でもAIは「このパラメータが良くないなら、静かに入れ替えて通過させる」みたいな提案をするんだよね。テストも問題が多くて、もっと長い説明が必要になる…

僕の経験では、ほとんどの問題は短いコンテキストウィンドウと最適でない「コンテキストエンジニアリング」の組み合わせから来てる。エージェントが利用可能なグローバル関数を説明するクリーンで関連性のあるコンテキストを持っていると、ちゃんと使う傾向があるんだ。一番の課題は、各リクエストに対して正しいコンテキストを構築して、それを機能が完成するまでクリーンに保つこと。今後数ヶ月でこの分野でたくさんの改善が見られると思うよ(サブエージェントが明らかな例だね)。

エージェントが利用可能なグローバル関数を説明するクリーンで関連性のあるコンテキストを持っていれば、適切に使う傾向がある。ストップ!エージェントなんて存在しない。エージェントはなくて、入力を受け取って出力を生成する数学的な関数だけだ。LLMを擬人化するのはやめよう。彼らは人間じゃないし、何もできない。重要じゃないように思えるかもしれないけど、私の見解ではそれは根本的なことなんだ。人間は機械じゃないし、その逆も然り。

個人的には、LLMをすごくジュニアなプログラマーとして扱ってる。働く意欲はあるし、指示も受け入れるけど、コードベースや使ってるパターンについての知識がかなり不足してるんだ。だから、すごく手取り足取り教えなきゃいけないし、明確な指示や潜在的な落とし穴の説明、小さくて範囲を絞ったタスクを与えて、パターンから外れないように注意深くレビューする必要がある。それに、僕がやるのと同じように動かすようにしてる。まずデータモデルを考えて、「動く」状態になるまで考えた後に、実際の「コード」を書くんだ。やっぱり明確な指示が必要だね。あと、僕の「黄金ルール」の一つは、ファイルの先頭にブロックコメントを入れて、そのファイルで何が起こっているかを説明すること。セッションを再開する時の第二の「プロンプト」として機能するんだ。結構うまくいくよ。「魔法」のように見える「そうしろ!」的なアプローチとは違って、僕には合ってる。ただ、やっぱり30%くらいの時間は、掃除したり、名前を変えたり、コードを一般的にリワークするのに使ってるけど、それでもかなり早く作業できる。手作業でやるよりずっと早いよ。

同意するよ。でも、経験の少ないチームメンバーがLLMを使っている場合、どう対処するかっていう問題があるね。コードレビューは、こういう原則を教えるためにもっと手間がかかる。ほとんどの人はそれを面倒がって、ただ動くソリューションにハンコを押すだけなんだよね。

LLMと非常にジュニアなプログラマーの違いは、ジュニアプログラマーは学んで変わるけど、LLMは変わらないってことだね!プロンプトに指示を多く入れれば入れるほど、忘れられることが増えて、結局「一般的な世界平均」に戻っちゃう。次のプロンプトではまた最初からやり直し…ジュニアプログラマーとは違うよね。

ある程度まで、そんなに手間をかけてクリーンアップしているなら、まだ最適に使えていないかもしれないね。例えば、私たちはLLMにコードベースの共通パターンを分析させて、AIエージェントがコードベースでより良い仕事をするためのドキュメントを書かせたんだ。それを編集して、何度か通してもらった。で、そのドキュメントを要件の一部として提供している。それが大きな違いを生んだよ。テストの構造の仕方や、共通のユーティリティを見つける場所について具体的な指示を書いたりもした。作業をダブルチェックするためのプリコミットフックも書いたしね。何かおかしなことをしているのを見つけたら、それを指示に追加する。今では、85~90%の品質で作業してくれるようになった。人間のレビューと少しの変更は必要だけどね。作ったものがどう動くかは分からないけど、コードをレビューする前に、マーメイドシーケンスダイアグラムを描かせるといいよ。コンテキストが汚染されすぎると、指示をほとんど無視し始めることが分かった。サブエージェントは、すべてのファイルの内容でトップコンテキストを埋めないから、それに対処するのに役立つよ。もう一つのヒントは、PRコメントとしてフィードバックを与えて、gh CLIでそれを読ませること。これ、手動でコードを編集するよりも早いことが多いから。自分が何か別のことをしている間に、彼らは自分の作業をクリーンアップしてくれるよ。

個人的には、LLMはStackOverflowの(かなり良い)代替だと思ってる。質問を投げると、すぐにその質問に対する答えが返ってくる。大抵は、その答えを基に自分のコードを書くことが多い。時々、LLMに関数を生成させて、それを自分のコードで使うこともあるけど、コピー&ペーストする前にその動作を完全に理解するようにしてる。でも、理解できないプログラミング言語のオープンソースプロジェクトに+400,000行のPRを押し込むことが、自分のキャリアにとって正直で質を重視することよりも有益なのか、時々考えちゃう。多くの会社では、実際のスキルよりも経験年数が優先されるのと同じように。

確かにそうだね。正直言うと、LLMはネットでコードをググってコピーするのと大して変わらないと思う。結局、開発者がそのコードを取って、見直して、ちゃんと動いているか確認するのは自分次第だしね。最後の部分についてだけど、最近50歳に近づいてきて、目が昔ほど良くない。目の疲れを防ぐために、今はやることを20分ごとに区切って、適切な休憩を取らなきゃいけなくなった。そのせいで、時間が一番の要素になってる。LLMは人間の1000倍速くコードを出力できるから、なんとか基本的なことをやらせられれば大きなプラスになる。今は、入力のAoS構造からSIMD用の適切な配列構造を生成するのに忙しくて、Unity C#とLINQを使ってテキストを出力してる(誰でも編集できるようにしたいから、RoslynやT4のルートには行きたくなかった)。クエリは比較的シンプルで、データ要素のリストから正しいエントリーを選んで、必要なフィールドを使って文字列を構築するだけ。でも、それをコピーしたり編集したりするのは、GPTに「これを選んで、あれを除外して、文字列をABCみたいにして」って言うよりもずっと時間がかかる。昨日、AIをHUDとして使うという投稿があったけど、それはすごく納得できる。全能のモデルがプログラム全体を書く必要はなくて、必要なのは小さなスケールで書いたりリファクタリングしたりできるスーパーパワーを持ったアシスタントなんだ。

それに、私はデータモデルを考え出してから「動く」ようになるまで、どんな「コード」を書く前にもそれをやる。やっぱり、明確な指示が必要だよね。でも、それだとバイブコーディングじゃなくなる :)

「ジュニアプログラマー」や「コパイロット」って、場合によってはAIを過大評価しているし、他のケースでは過小評価していると思う。AIは普通の人なら忘れないことを忘れたり、基本的なコーディングミスをすることもある。でも同時に、あることに関しては私よりも優れている(配列を扱うアルゴリズムでのオフバイワンエラーとか)。それに、インターネット上のほとんどのことについて百科事典のような知識を持っている。赤黒木?もちろん。ゲームプログラミングのECSシステム?問題なし、よく使われるライブラリを教えるよ。私はそれを「猟犬」のように考えるようになった。私よりも上手くできることもあるし、小さな隙間や茂みに入るのも得意だ。濡れたり汚れたりするのも気にしないし、獲物の匂いを嗅ぎ分けるのも私より上手い。でも、獲物を仕留めるのは私の役目だし、狩りをリードするのも私であるべきだ。

主要なAIアシスタントは、こういう問題を避ける方法をすでに備えてるよ。Claude Codeには/initがあって、Cursorには/Generate Cursor Rulesがあるし。これはコンテキストエンジニアリングでもないし、こういう問題を避けるためのツールがそのまま使えるんだ。たとえ問題が起きても、これらのツールを使えば、組織全体で二度と起こらないようにできるよ。使い方を知るために時間を投資していればね。こういうツールが開発コミュニティを分断してるのは面白いよね。

問題はツールじゃなくて、「コーダー」の雰囲気だよ。彼らはコードを書くように、あまり気にしないんだ。

真剣な質問なんだけど、今Cursorが私の日常業務をスピードアップできるか再評価してるところなんだ。今のところ、微妙なエラー(例えば「:」を「,」に変えるとか)が多くて、あまり効果的じゃない。でも、私が直面している主な問題は、コードベースが大きくて、完全に古くなっている部分や、ひどく書かれた部分があることなんだ。だからAIは最も一般的なパターンを優先するんだけど、それが悪いパターンなんだよね。「からインスピレーションを得る」みたいな基本的な指示を出しても、結局は全体のコードベースから取ってくる(ちなみに、急いでマージされた雰囲気コーディングの出力が悪化させた)。私の理解では、ルールは基本的にプロンプトに直接入れた場合と同じことをするべきなんだけど、それに対する解決策はあるのかな?

CCは、CLAUDE.mdの非常に明確な内容を無視することがよくあるし、私だけじゃないって知ってる。コンパクトにしたり新しい会話を始めたりするサイクルは、同じ望ましくない行動のシシフォス的なスパイラルのように感じるし、その解決策を見つけるのにかなりの努力をしても、満足のいくものはまだ見つかってない。この記事を表面的な反AIの反応として片付けるのはフェアじゃないと思う。あなたが説明している解決策は、決して完璧じゃないよ。

個人的には、ここで一番足りてないのは「思いやり」だと思うし、バイブコーディングとはあまり関係ない気がする。AIはただのツールだし、著者が指摘した問題は人間のジュニアにも同じように存在するし、ちょっとしたガイダンスやインタラクションがあれば簡単に解決できることだと思う。AIが人々にクオリティのある成果物に対して無関心にさせているとは思わないけど、元々あまり気にしていなかった人にはそうかもしれないね。よくある反論は、ジュニアを育てる機会を逃してしまうってことだけど、それは確かにそう。ただ、いつも選択肢があるわけじゃない(例えば、うちのスタートアップは採用が本当に大変で、ジュニアにやらせるべきタスクをAIに試させてるんだ)。それに、ソフトウェアの品質にとって重要だと考えていたことが、AIツールの影響で大きく変わるかもしれない。これらのことは絶対的なものじゃないと思う。すでにそういう変化は起きているけど、まだ始まったばかりだから、どうなるかはわからないな。

キーボードの音で、同僚がコードを打っているのと、文章を書いているのとで違いがわかる。AIの影響で、彼は文章を書くことが増えたね。