LLMにとって読みやすいコードとは何かをLLMに聞いた
はじめに
Claude Codeによる爆速コード生成をみなさん試されているところだと思いますが、いくつか類似の課題が発生すると思います。
- 生成コード量が多くなり人間のレビューがしんどい
- CIの整備が必須になるが拡充するのがしんどい
- 複雑なドメインだと全然違う意図のコードが生成されてしんどい
じゃあそもそもLLMが認識しやすいコードにしてあげればミスも減るのでは?
今は人間が読む前提だから歪になっているのでは?
と思ったのでLLMにとっていいコードとは?という内容をLLMとやり取りした記録がこの記事です。
人間が重視する「いいコード」の特徴
長期的な視点
- 半年後、1年後に自分や他の開発者が読んで理解できるか
- プロダクトの成長に合わせて拡張しやすいか
- チームの技術レベルに適した複雑さか
文脈への適応
- プロジェクトの規模や期限に応じた適切な抽象化レベル
- チームの慣習やコーディング規約との整合性
- ビジネス要件の変更に対する柔軟性
経験に基づく直感
- 過去に痛い目を見たアンチパターンの回避
- パフォーマンスのボトルネックになりやすい箇所への配慮
- デバッグしやすさを重視した書き方
LLMが評価する「いいコード」の特徴
理論的な最適性
- 設計パターンやベストプラクティスへの忠実さ
- 一般的に推奨される書き方の網羅的な適用
- 型安全性や関数型プログラミングの原則の厳密な遵守
即座の完璧性
- 現時点で考えられる全ての要素を盛り込んだ設計
- エラーハンドリングやエッジケースの包括的な対応
- 拡張性を見越した過度に抽象化された構造
知識の一貫性
- 学習したベストプラクティスの機械的な適用
- 文脈に関係なく「教科書的に正しい」コードの生成
LLMはどのようなコードを出力するのか
パターン認識による出力
- 学習データの中で「良い」とされているコードパターンを組み合わせて生成
- エラーハンドリング、型定義、命名規則などのベストプラクティスを機械的に適用
- でも「なぜそれがいいのか」を本当に理解しているかは疑問
安全性への偏向
- 批判されにくい、一般的に受け入れられる書き方を選択
- 過度に防御的なコード(過剰な型定義、エラーハンドリング)を生成しがち
- 「動かないコード」よりも「冗長でも安全なコード」を優先
文脈の欠如
- プロジェクトの制約、チームの技術レベル、締切などを考慮できない
- 「教科書的に正しい」ことを「実際にいい」ことと混同している可能性
これも実際に使用していて納得のある内容。
LLMにとって安心するコードとは?
LLMが「不安」になるパターン
- 型が明示されていない変数
- エラーハンドリングがない非同期処理
- 魔法数値(ハードコードされた数値)
- 単一文字の変数名
LLMが「安心」するパターン
- 明示的な型定義
- 網羅的なエラーハンドリング
- 詳細なコメント
- 長い説明的な変数名
ここから少し面白いなと思ったのは、
人間は「相手の認知負荷」を基準にコンテキストの過不足を判断しているのに対し、LLMは「一般的な正しさの基準」で判断している。
だからLLMは:
- 必要以上に防御的なコードを「安全」だと感じ
- 人間が「当然わかる」と思う部分まで明示したがり
- 逆に人間が「なぜそうするのか」を知りたい部分(ビジネスロジックの意図など)は見落とす
そういうコードが生成されるのはわかりつつも、文章として出力されるとしっくりきますね。
ということは、LLMが安心するパターンのコードベースにしてしまえば、LLMフレンドリーなものを達成できて、出力制度が上がりそうな気がする。
LLMにとっての読みやすさを深掘り
構造的明確性
- 型システムによる明示的な契約
- 関数の入出力が型で完全に表現されている
- 副作用が明確に分離されている
意味的一貫性
- 命名規則が体系的
- 抽象化レベルが一貫している
- ドメイン概念が型として表現されている
変更容易性の新しい定義
- 型レベルでの変更影響範囲の把握
- インターフェースの安定性
- 組み合わせ可能性(composability)
これらの文字だけ見ると、人間が読みやすいとされているコードと一緒かなと思います。
とはいえ人間ではないので判断基準の差分はどこかにあるはず。
LLMフレンドリーであるとは?
人間向け指標 | LLM 向けに置き換えた指標 | 破綻リスクが下がる理由 |
---|---|---|
読みやすさ (短く単機能) | トークン分布が均質 | クロスエントロピーが下がり推論安定。 |
命名・型が明瞭 | AST パターンが一貫 | 参照解決が確定し"幻関数"生成を防ぐ。 |
WHY をコメント | 構造化 Docstring / スキーマ | Few-shot 手本として仕様を直接条件付け。 |
網羅テスト | 自動フィードバック | 失敗ログ→再プロンプトで自己修復ループ。 |
人間とLLMで言葉を分けるとこういう分け方がある模様。
これらは巷で言われていることとほぼ一緒の内容なので納得感ありあり。
トークン分布は以下のような調査結果もあるようなので、読みやすい方法については色々試さないとなんとも言えないですかね。
実際、関数 50 行/モジュール 300 行 付近でコード perplexity が急上昇し、生成エラーも増えるとの報告があります。 
ASTについては以下の方法もおすすめしてきました。たしかに一理ありそう。
linter だけでなく 構造ハッシュ や Embeddings 類似度 を CI で検査
まとめ
これ以外にも色々なやりとりを複数のLLMとしていたのですが、濃淡はあれど似たような回答になってました。
LLMの爆速コード生成に対応するために人間が何をすればいいのか、引き続きあーだこーだ言いながら試していきたいですね。
- ドメイン知識を明文化
- CIの拡充は必須
- 命名規則やパターンを統一して推論しやすく
Discussion