ハクソク

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

AIが私たちに良いコードを書くことを強いている

概要

  • エージェント時代の「良いコード」の必須要素
  • 100%コードカバレッジの重要性と運用方法
  • ディレクトリ構造・型・自動化の最適化
  • 開発環境の即時構築と並列実行
  • 型システム・自動ツール活用による品質担保

エージェント時代の「良いコード」の本質

  • テストの徹底明確なドキュメント小さくスコープの明確なモジュール静的型付けの重要性
  • これらは従来「任意」だったが、エージェントには必須要素
  • 人間は後からリファクタや修正が可能だが、エージェントは「汚れを広げるRoomba」になりやすい危険性
  • ガードレール(自動化された制約やチェック)の設定・運用が不可欠
  • ガードレールが弱いと、痛い目に遭うリスク
  • 強固なガードレールがあると、LLMは正解まで自律的に試行錯誤可能

100%コードカバレッジの価値

  • チームの最重要かつ物議を醸すガイドラインは「100%コードカバレッジ
  • 100%カバレッジはバグゼロを保証するものではなく、全コードの挙動確認を目的
  • 95%や99.99%では「どの行をテストすべきか」の判断が残るが、100%で曖昧さが消失
  • カバレッジレポートがテストToDoリストとして機能
  • テストはエージェントの自由度を減らし、挙動の明示的検証を強制
  • 到達不能コードの削除エッジケースの明示化具体例によるコードレビューの容易化が副次効果

ファイル構成と粒度の最適化

  • エージェントは主にファイルシステムを通じてコードベースをナビゲート
  • 意味のあるディレクトリ構成・ファイル名設計の重要性
    • 例: ./billing/invoices/compute.ts > ./utils/helpers.ts
  • 小さくスコープの明確なファイルを多数用意
  • ファイルが短いほどLLMが全体を文脈に保持しやすく、エージェントのパフォーマンスが向上

開発環境の自動化と並列実行

  • 従来の「一つの開発環境」から複数同時・自動構築へシフト
  • ガードレール(テスト等)の高速化が必須
    • 例: npm testごとに新DB作成・マイグレーション・全テストを高速実行
    • キャッシュ活用で10,000+アサーションを1分以内で完了
  • 新機能開発コマンド(例: new-feature <name>)で即座に環境・設定を自動構築
  • 環境ごとの完全な分離(ポート、DB名、キャッシュ等)を徹底
  • Docker等の利用で容易に実現可能

型システムと自動ツールによる品質担保

  • 自動リンター・フォーマッターの厳格運用と自動適用
  • TypeScriptなどの強力な型付き言語推奨
    • Pythonの型注釈よりTypeScriptの型システムが優秀
  • 型によって不正な状態や遷移を排除し、意図の明示探索空間の縮小を実現
  • 意味のある型名(UserId, WorkspaceSlug, SignedWebhookPayload等)でエージェントの理解を補助
  • OpenAPIによる型付きクライアント生成でフロント・バックエンドの整合性確保
  • Postgresの型システムとチェック・トリガーでデータ正当性も担保
  • Kysely等で型付きTypeScriptクライアントを自動生成

エージェント時代の開発文化

  • エージェントは疲れ知らずで優秀なコーダーだが、環境次第で力を発揮
  • 従来「余計」とされてきた良いコードの作法が本質的価値
  • 初期投資は「税金」のように感じるが、長期的な生産性・品質向上に不可欠
  • エンジニアリングリーダーシップの理解と支援を得て、理想的なコードベースを実現

Hackerたちの意見

これ、いいね。「ベストプラクティス」ってのは、結局その時の技術の状況次第だよね。コードを書くのがめっちゃ簡単になるツールがあるから、100%カバレッジが人間が書いたコードでは得られない形で効果を発揮するのが見えるよ。LLMが得意な部分(コードをガンガン書くこと)を最大限に活かしつつ、判断をあまりせずに狙いやすいターゲットを与えてくれる。LLMがテストの価値をどれだけ変えるかって、あまり探求されてないと思うんだ。昔の職人が手作りしたコードの時代では、ユニットテストは主に足場として役立ってた。テストから得られる価値のほとんどはコードを書くときにあったから、マージする前にユニットテストを削除しても90%の価値は得られてた。今は、AIはあまり足場としてユニットテストを必要としないけど、テストがあることで将来のエージェントとのやり取りが安全になるんだ。テストは具体的な文脈として機能するからね。
コードのライフサイクルによるかもしれないね。10年間も進化し続ける生産クリティカルなシステムのテストは、ほんとに貴重だよ。テストなしで何かを触るなんて想像できない。多くのテストは、修正が必要なチケットを参照してるから、時には痛い思いをした教訓でもある。
前にも言ったけど、コードの「ベストプラクティス」って、実装やアーキテクチャが違っても結構典型的だよね。シナリオに対してLLMに最高のコードを書かせると、たぶん自分の実装とあまり変わらないと思う。書くことやアート、クリエイティブなアウトプットは、コードとは全然違うから、ソフトウェア業界は自動化の中でも特別な位置にいると思う。
だからこそ、ソフトウェア開発がエンターテインメント以外でLLMの唯一の実用的な応用かもしれないと思ってるんだ。他の分野ではできないような、タイトなフィードバックループを自分たちで作れるからね。LLMと計画を合意して、数分後や数時間後にそれがうまくいかないことに気づくと、LLMが「だからそんな風にやるべきじゃなかったんだ!」って言うのが面白い。まるで家をゼロから建てて、電気システムをアメリカのウェブサイトを参考にしてたのに、カナダの食洗機を取り付けるまでその問題に気づかないみたいな感じ。
まさに、食洗機を取り付けてる最中に、食洗機が「だから言ったじゃん!」って叫ぶ感じだね ;)
> 「ゼロから家を建てることを想像してみて。だからこそ、エンジニアリングの分野には厳しいルールがあって、正式な教育が必要だったり、誰かが大きなミスをすると刑務所に入ることもあるんだ。ソフトウェアはずっと簡単で安全だけど、最近まで匿名のエンジニアリングが普通だったから、Appleが製品の署名を求めるのにみんなイライラしてる。高給のソフトウェアエンジニアは異常だったけど、今はそれが終わりつつあるのかも。将来的には、本当に新しい解決策や高リスクのソフトウェアをコーディングする人だけが高く評価されるようになるかもね。」
> 「これが、ソフトウェア開発がエンターテインメント以外でLLMの唯一の実用的な応用かもしれない理由だと思う。すごいよね。あと、自己学習とかもどう?一般的に、すべての「本当の」応用を経験したって言うのは、かなり傲慢だよね。* - 例えば、今日と昨日、LLMを使ってRLC回路や「インバータ」について自分で学んでたんだ。」
これについてもう少し考えてみると、シミュレーター(いわゆるデジタルツイン)を考慮していなかったかもしれないね。シミュレーターは現実に物を作らなくても、かなり信頼できるフィードバックループを作れるはずだから。例えば、この飛行機のデザインは離陸できるのか?それでも、ユニットテストを書くことで現実に少し触れられることに感謝してるよ。
あなたが言っている経験が、どうしてLLMがソフトウェア開発に役立つかという結論に至るのか理解できないよ。「だから、こんな風にやるべきじゃなかった!」っていう反応は、いつもの「あなたは絶対に正しい!混乱を招いてごめんなさい」っていうバリエーションみたいだね。AIが無意味なことを大量に生み出して、それを一生懸命デバッグして反論するループにハマるのは、どう考えても良いループじゃないと思う。
記事は、AIを効果的に使いたいなら、良いコードを書くべきだって内容だと思ってた。気づいたのは、Claudeは論理的でない、わかりにくい、または悪い変数名のコードに対してつまずくことが多いってこと。例えば、変数が「iteration_count」って名前なのに、実際には合計を含んでるとAIを「騙す」ことになる。だから、コードをきれいに保つことで、AIにとって何が起こっているのかが明確になって、より良い結果が得られるんだ。でも、これは人間にも同じことが言えると思う。
でも、人間はこういうケースをうまく扱えるのは、より良い記憶にアクセスできるからだよね。「iteration_count」を次に見たときには、それが実際には合計を持っていることを知ってるけど、新しいAIセッションはゼロから再発見しなきゃいけない。時間が経つにつれて、これがどんどん良くなると思うけどね。
自分がうまくいくと思うのは、メソッドのシグネチャを作って、入力や出力、変化やビジネスロジックについての意図をコメントに書くことだね。それにアプローチの指示も加えるといいよ。LLMはこれを一発でうまくやる可能性が高いから。
それに関連して、AIがチームにドキュメント、特に良いコメントを気にするように強制するのが効果的だったみたい。以前は人間だけがこれを読んでいたから、最新の状態を保つモチベーションがあまりなかったんだ。今は、AIがそのドキュメントを知識ベースの一部として使ったり、プロセスを評価するかもしれないという考えが、実際に内部ドキュメントを更新するために時間を使うように人々を動機づけているみたい(もちろん、AIの助けもあるけど)。ちょっと逆行してるけど、前にやっておけばよかったなと思う。でも、優先されることはなかった。今では良い内部ドキュメントがモデルにフィードバックするから、必須と見なされているんだ。
このプロンプトをいじくる会社に典型的なソフトウェアエンジニアリングの専門知識が、このブログ記事に表れてるね。彼らは100%のコードカバレッジが魔法の弾丸じゃないことを知ってるはずだ。コードの流れや動作は入力によって異なるからね。たまたま全てのコード行をカバーする例を見つけたからって、全ての組み合わせをカバーしてるわけじゃない。愚者の楽園に住んでるってことは驚きじゃないよ。LLMを信じるのは愚者だけだからね。コードベースの正式な証明を求めてるけど、もちろん誰もそんなことはしない。コストが天文学的になるからね(しかもLLMはそれには役に立たない。ソフトウェア関連の全てに役に立たないのは特別じゃないけど、特にこれには使えない)。
LLMが形式的検証に役立たないっていうのは大胆な主張だね。人々がしばらくの間、証明支援ツールに接続してるのに。これは悪いアイデアではないと思う。LLMは仕様にいくつかのミスをするかもしれないけど、99%の確率で関係ない詳細に対しては、ちゃんとした仕事をすると思うよ。
昨日から始めたことなんだけど、これが広まるといいなと思ってるのは、TLA+/PlusCalで自分が欲しい仕様をかなり高いレベルで書いて、それをCodexに正確に実装させることなんだ。仕様から全く逸脱しないように指示して、できるだけクリエイティブにならないように頼んでる。仕様にかなり忠実だから、TLA+は状態を変更することに関するものだから、生成されるコードは結構醜いけど、醜くて正しいコードは、検証されていない美しいコードよりもマシだよね。完璧ではないけど、仕様に単純に従うものは最適化されていることは少ないし、TokioやMioに置き換えたり、ループを最適化しないといけないこともある。生成されたコードが遅すぎて使えないこともあるし、時にはコードがあまりにも醜くて我慢できないから書き直さなきゃいけないこともあるけど、それをするのにかかる時間は、自分で完全に翻訳するよりもかなり少ないんだ。これを始めた理由は、最近実験しているのがロックフリーのデータ構造で、たぶん自分がやっていることが新しすぎてCodexが自分の望むものを生成できていないから。ロックやロックファイルを使うし、文句を言うと「あなたは絶対に正しい」と言って、結局ロックを使うことになる。ある意味、これが自分が本当に望んでいた理想的なケースに近いんだ。高レベルの数学的なロジックに集中できて、実際にコードを書く細かい部分はメタファリカルなAIインターンに任せられるからね。Rustを書くのが楽しくないわけじゃないけど、コードは自分にとっては実装の詳細に過ぎない。このやり方で、自分がやるべきこと、つまり「まず正式に仕様を指定して、次にコードを書く」ということができてる気がする。
これが最近の自分のコード開発のやり方でもあるよ。自分の意見は、豚の本の著者とかなり似てるかな。 https://martin.kleppmann.com/2025/12/08/ai-formal-verificati....
LLMに仕様書自体に貢献させると成功するかもしれないよ。最近の最前線のモデルで急にうまくいくようになって、書くコストが10倍から100倍安くなるって感じで経済が変わった。
試したわけじゃないけど(注意ね)、LLMに100%カバレッジを与えると、悪い前提や間違った機能が固定されちゃうんじゃないかって心配してる。そうなると、何が間違ってるかを見つけるのが難しくなるよね。とはいえ、ここで話してるのは雰囲気でコーディングしてるわけじゃなくて、ちゃんとレビューされたコードのことだよね?だから、人間は「いや、これは違うから、これらのテストを削除して、この基準に合わせて実装して」って言うわけだよね?
その通り、100%正しいよ。私たちはまだテストケースをレビューしてアドバイスしてるし、事前にPRDも書いてるよ(LLMが私たちにインタビューしてくれる!)から、範囲や期待値はかなり明確になってる。
それ、すでに経験してるよ。何も強制しなくても、LLMが「1 = 1?」みたいなテストをたくさん作ってる。
これは幻覚だね。もしくは営業トークかも。もし本番のバグや、機能するコードベースを維持する必要が「良い」コードを書くきっかけにならないなら、何も効果がないよ。現状の技術レベルでは、「AI」は逆に悪化させる傾向がある。
シーッ、元の投稿者はAIベースの会社のCEOだよ。バイアスなんてないに決まってるよね。/s
ほとんどのことが私たちにも当てはまるよ、同じ理由でね。大きな古いプロジェクトをこの方向に進めてきたし、新しいプロジェクトもそこから始まってる。スキルファイルを信じるよりも、ツールチェックを通じてやる方が簡単だよ。結果的にできたコードが良いとは言えないけど、みんながつまずいてる部分ではあるけど、予測可能で、退屈で、テスト済み、純粋で、すぐに反復できるコードが得られてるのは、確かに私たちのSDLCの原則の一部だよ。一部のアドバイスはちょっと極端で、100%のコードカバレッジには価値を見出してないけど、90%なら全然オッケー。他の人たちはニュアンスを見逃してることがあって、AIが型チェックを覆すのを防ぐために頑張らなきゃいけないんだ。デフォルトでは、型エラーを回避するために、どこでもgetattr/cast/typeignore/Anyを使ってるからね。私が期待してるのは、AIコーダーが静的解析ツールや検証ツールを使うのが上手くなること。ここでの実験はあまり良くなかったけど、GFQL(GPUグラフクエリ言語)の一部にアロイモデルチェッカーを追加するのにすごく手間がかかったし、バグも見つからなかった。でも、私たちのコードと過去のバグに基づいてユニットテストスイートのテスト増幅をコーデックスに頼むのはうまくいったよ。同様に、基準からポート適合テストを作ったり、ドキュメントを実行可能にしてドリフトを防ぐのも簡単だね。新たに見始めているのは、本番ログに基づいた自動バグパッチだよ。これは、雰囲気コーディングのために設定したエリアに実用的で、逆に私たちがもっと気にかけているエリアでもある。自動依存関係更新ボットは信じてなかったけど、こういうのはもっと信頼できてレビュー可能になる。もう一つ注目しているのは、新しい「テレポート」モードで、PRをリモートの非同期開発に移せるようにすること。以前はサポートする価値がないと思ってたけどね。
100%カバレッジには落とし穴があるよ。エージェントがコードとテストの両方を書くと、同義反復の罠にはまるリスクがある。エージェントは欠陥のあるロジックと、その欠陥を検証するテスト(通るやつね)を書くことができる。100%カバレッジは、テストがコードの前に書かれるか、人間によって厳密に検証される場合にのみ意味がある。それ以外は、幻覚をテストでカバーして信頼性の幻想を作ってるだけだよ。「実行可能な例」は、文法的に正しいだけじゃなくて、意味的に正しい場合にのみ役立つ。
その通りだね。そういう時は、テストやアサーションをじっくり見直すのが好きなんだ。実際、SUT自体を見るよりも早いことが多いよ。
まあ、ビジネスロジックのコードとテストは人間が書くことが多いからね。ちなみに、例から離れてプロパティに焦点を当てると、テストがもっと進むよ。
フェーズチェンジ仮説はちょっと間違ってると思う。100%のカバレッジじゃなくて、例えば100%のMC/DCテストカバレッジで起こるんじゃないかな。SQLiteや航空宇宙ソフトウェアが目指しているのはこれだよ。*これは査読付きの研究で確認されていないけどね。
異なるエージェント(バージョンや会社)を使うことで、そのリスクを軽減できるよ。
あなたが挙げた問題は確かにそうだけど、解決策はあまり良くないね。大学時代に、講師自身の例で形式手法や検証の価値を示そうとしていた時に、人間でもこの問題を見たことがあるよ。解決策は「人間にやらせる」でも「コードを書く前にやる」でもなくて、むしろ「いろんな考え方を持った人たちを巻き込んで、お互いの盲点をチェックし合う」ことだと思う。AIモデルをいくら投げても、異なるプロバイダーからのものであっても、結局は一つの考え方にしかならないからね。人間のテストとAIのコード、AIのテストと人間のコード、人間がAIのコードをレビューするのもその逆も、全部いいと思う。ただ、二人の異なる人間は通常、異なる盲点を持っているけど、時には一人の人間が上司の全力サポートで唯一の声になろうとすることもあるから、AIがそれを助けるわけじゃないよね。
どんなグルーヴ感のコーダーがその日吸引したかに関係なく、if err != nil { return fmt.Errorf(...) } を全部カバーするつもりはないよ。