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

AIを活用して高品質なコードを効果的に書く方法

概要

AIと協働したソフトウェア開発で高品質な成果物を得るための実践的な12のポイントを解説。 明確なビジョンの共有、詳細なドキュメント作成、レビュー体制やテスト戦略の工夫が重要。 AIの限界やリスクも意識し、人的なコントロールと分担が不可欠。 セキュリティや複雑性の管理、実験的アプローチの活用も推奨。 効率的かつ安全なAI活用のための具体的なノウハウ集。

AIと協働するための12の実践ポイント

  • 明確なビジョンの確立

    • プロジェクトの ゴールや要件 を明文化
    • アーキテクチャ、インターフェース、データ構造、アルゴリズム の事前検討
    • テスト方針や検証方法 の合意形成
    • 長期的・変更困難な意思決定の 透明化
    • 重要部分の設計やテスト範囲の 明確化
  • 詳細なドキュメントの維持

    • 要件・仕様・制約・設計 の詳細な記録
    • コーディング規約・ベストプラクティス・デザインパターン の明文化
    • フローチャートやUML図 等の視覚資料作成
    • 複雑なロジックには 擬似コード で意図を明示
    • ドキュメントは リポジトリ内で標準化
  • AI支援のためのデバッグシステム構築

    • 効率的なログ収集・抽象化表示 システムの整備
    • 例:「全ノードへのデータ送信状況」「ノードごとの保存状況」等の自動要約
    • CLIやブラウザ操作の負担軽減
  • コードレビュー水準の明示

    • 重要度に応じたレビュー指標 の導入
    • AIが生成した関数には //A 等のコメント付与
    • 人間未レビュー箇所の可視化
  • 上位仕様テストの自作

    • AIによる テストの抜け道利用や不正 を防ぐ
    • プロパティベーステスト の導入
    • サーバ再起動やDBチェック等で AIの“ごまかし”防止
    • テストコードは AI編集不可領域 に分離
  • インターフェーステストの分離

    • AIに 実装情報を与えず 仕様ベースでテスト生成
    • 実装依存性のないテスト で品質担保
    • テスト編集には 明示的な承認制
  • 厳格なリント・フォーマットルール適用

    • コード品質・一貫性 の維持
    • AIと人間双方 の早期問題発見
  • コンテキスト固有のエージェントプロンプト活用

    • パス単位のCLAUDE.md 等プロンプト自動生成
    • 規約・設計・要件等の高レベル情報 を事前提供
    • AIの再学習コスト削減・品質向上
  • 高リスク関数の特定と明示

    • 認証・認可・データ処理等の重要関数 を明示的にマーク
    • 例: //HIGH-RISK-UNREVIEWED, //HIGH-RISK-REVIEWED
    • 編集時は AIが自動で状態更新 する仕組み
    • 人間による最終確認 の徹底
  • コードの複雑性削減

    • 不要なロジックや冗長な記述 の排除
    • コンテキストウィンドウ圧迫の回避
    • メンテナンス性・将来のAI活用性 向上
  • 実験・プロトタイプによる問題探索

    • AIによる複数案の高速試作
    • 最小限の仕様で 多様なアプローチ検証
    • 最適解発見までのコスト削減
  • 一度に複雑な生成を依頼しない

    • 大規模生成の分割・段階的依頼
    • 各モジュールごとに 仕様適合性を確認
    • 全体把握困難時はリセット して再構築

AIとの協働開発では、 人間の責任範囲の明確化と情報の透明化 が不可欠。 ドキュメント・レビュー・テスト・リスク管理 を徹底し、AIの特性を活かしつつ安全な開発体制を築くことが重要。

Hackerたちの意見

最後に、リスクを取る価値があるのか疑問に思うよ。自分の考えを形成するのは、コードを書くことが大きいし、画面で見ることでその限界にぶつかるからね。やってる仕事の種類かもしれないし、単に自分がダメなだけかもしれないけど、コードは細かい部分を詰めるための強制力になってる。仕様書を書くときにはそれが感じられないんだよね。

その通りだね。30年前に知り合いの数学者が言ってたんだけど、「プログラミングの唯一の良いところは、正確さを求められることだ」って。頭の中で色々考えるのはいいけど、たまには現実に直面するのもリフレッシュになるよね。

俺もそう思う。ラテを飲みながら新しいSAASプロダクトを作るために5人のエージェントを動かしてるって言ってる人たちを疑う権利は十分あると思う。そんな風に働くには、コードを深く掘り下げるのをやめなきゃいけないと思うし、良い品質を求めるならそれが必要だよね。でも、コードを書くエージェントは、些細だけど時間がかかる作業には結構役立つと思う。例えば、テストを書くのは得意だし。テストを調整して、ちゃんと動くか確認する必要はあるけど、全体的にはプロセスが早くなると思う。特定の設定での問題を解決するのも得意だし、Androidマニフェストの隅っこでの問題も見つけてくれる。ただ、解決策がない場合でも見つけようとするから、ちゃんと管理しておかないとね!今日は、5年前に放置してたプロジェクトを進めるためにClaudeを使ったんだけど、まだ進行中だけど、AIなしでは無理だと思ってたタスクが2-3時間で半分まで来た感じ。

これには同意する。これが私たちが理解を形成するための問題だよね。これが手元の作業で、自分たちのメモや人との議論、頭の中でエラーやアイデアを処理する静かな散歩…子供の頃からずっとこうだった。誰かに遊んでもらいながら、自分の欲求に合うかどうか評価するのを待ちたくなかった。欲求は遊びから来ることが多いし。これをLLMにアウトソーシングするのは、飛行機が失速するのに似てる…精神的にダウンしちゃう。ストレスもなくなるけど、LLMが「問題」を解決してくれると思うと、もう考えたり創造したりするインセンティブがなくなっちゃう。人によってアプローチが全然違うのが驚きだよ。仕事で、コードを作ってもらえることに夢中になってる人たちもいるけど、俺はそのグループには入ってない。

俺もこれには同意する。手書きの方がいい文章が書ける気がする。ニッチなアプリケーションに取り組んでるけど、標準的なCRUDやReactアプリではないからね。LLMは、以前のStack Overflowの使い方と同じように使ってる。もっと自動化しようとすると、自分でコードを書くよりもクリーンアップに時間がかかることが多い。AIが変なことをすることもあるし。非標準の幾何学的プリミティブのテクスチャ投影を書いたとき、投影に使った数学は局所的な領域でしか有効じゃなかった…長い話だけど。Claudeは、その関数を正しいと思って書き直そうとし続けて、関係のないタスクに指示しても全然やめなかった。超イライラしたよ。結局、その関数をコメントで包んで「消えてくれ」って言っておいた。

それは、多くの開発者がこういう働き方に慣れているからだよ。AIを使うなら、ソフトウェアアーキテクトのように考えるのが正しいアプローチなんだ。コーディングしながら考えるのではなく、事前に頭の中で計画することを学ぶのは、考え方のシフトが必要だけど、新しいツールを使うためには重要なんだ。これが自然にできる人もいれば、すごく難しいと感じる人もいるよね。

今でもそうしてるけど、書かれたものをレビューしたり、作ったものをテストしたりする時にね。私の見方では、重い仕様書アプローチに戻った感じだけど、エージェントのおかげで回転が早いから、アプローチを変えるコストがすごく低いから、すごく反復的に感じるんだ。今では仕様書(適用可能なテストも)を本当の仕事として扱ってる。できるだけ多くのことを仕様書に詰め込むけど、常に反復してる。エージェントと一緒に進めていく中で、機能やその全体的なアプローチを完全にやめることもよくある。AIエージェントは私にとってツールであり、加速装置なんだ。自分に合ったもっと自由なアプローチを見つけた人もいると思うけど、少なくとも今は、私たちが生み出しているものをレビューして考えることが私のアプローチになってる。それが進むにつれて私の考えを形成していくんだ。

1987年に初めてコーディングを始めたとき、最初はBASICで書いてみて、遅すぎるからアセンブリに書き直したり、最初からアセンブリで書かなきゃいけないってわかってたんだよね(BASICでは全然機能が使えなかったから、64Kのメモリの第二部やダブルハイレゾグラフィックスを使うために)。先週は、他の人が書いたウェブソリューションを数日かけて修正して、TerraformベースのデプロイからCloudFormationにCodexを使って変換したんだけど、フロントエンド開発を10年やってなかった自分でも、コードを見ずに機能を確認できたよ。もっと関連する話として、数時間かけてアーキテクチャを考えたんだ。クラウド + Amazonのマネージドサービス + インフラストラクチャーをコードで + 実際のコーディング、図を描いてラベルを付けて、分解やフェーズを考えながら進めた。必要な要件をマークダウンファイルにまとめて、ClaudeとCodexに各項目をテストしながらチェックさせて、何をしているかを要約させた。ウェブフロントエンドの修正と新しい作業の量を考えると、AIベースのコーディングがなければ、他の開発者に手伝ってもらっても2週間かかってたと思う。でも、一人で3、4日で終わったよ。実際のところ、数百のドキュメントには期待通りに動いたけど、20倍のドキュメントをシステムに投げ込んだら完全にダメになっちゃった。LLMがなかったら、顧客に「今、2週間の時間を無駄にして、他の2人のリソースも使った」と言うのは完全に無能に見えたはず。今は、まさに白紙に戻って、再設計して、マネージドサービスが抽象化していたことを少し手を加えてコードでやり直して、新しいマークダウンファイルを作って1日で終わらせた。その再作業だけでも1週間かかってたと思う。マネージドサービスがやっていることの理論は知ってたけど、実際にやったことはなかった。自分一人でデリバリーを責任持ってやったのは10年以上前で、他の人に委任することなく、デザイン文書を作るほど単純なものだった。最近の1年で、調整や「神話の人月」のオーバーヘッドなしで、自分一人で大きなプロジェクトを引き受けられるようになった。イライラした瞬間にCodexに「お前がやったのは過剰に複雑なクソみたいなもんだ、基本から実装を考え直せ」と言えるようになっても、HRに報告されることはないしね。今は、やるべきことがわかってるから、時間がかからずにやれることも多いよ。

歴史的に見ると、ソフトウェアエンジニアリングは多くの人に「組み立てライン」の仕事だと見なされてきた(仕様の引き渡しやウォーターフォールを通じてアウトソーシングしようとする努力を見てみて)けど、実際には設計しながら構築する形で実施されてきた(誰もすべての質問やエッジケースを事前に予測することはできないし、ソフトウェアの仕様は実際のコードの分岐の数よりもはるかに単純なことが多い)。ミッションクリティカルなアプリケーションにおいて、「実際のコードを書く」ことがこれほど安くなると、コードを書く際に人間が直接関与しないときに、もっと正式な設計を前もって行う方が理にかなってくるのではないかと疑問に思う。

自分の考えを形成するのは、コードを書くことと、それを画面で見て、その限界にぶつかることに影響されてる。完全に同意だけど、そうやって仕事を見積もるのはどうするんだろう。もっとひどいのは、他の人がやる仕事を見積もるプランニングポーカーだよ。

自分の考えを形成するのは、コードを書くことと、それを画面で見て、その限界にぶつかることに影響されてる。私が長年持っている二つの原則が、あなたの感情やこのスレッドに関連していると思うので、以下に再掲するね。役に立てばいいな。まず、ソフトウェアを作るときは、それが問題に対する自分の理解のスナップショットであることを忘れないで。未来の自分を含め、みんなに自分のアプローチや明確さ、問題に対する解決策の適切さを示すものだから、発言は慎重に選ぼう。そして、コードは何をするか、どうやってするか、いつ使うか、誰が使うかを答えるけど、なぜ存在するのかは答えられない。コメントがそれを達成するんだ。もし開発者がコードがなぜ存在するのかを考えないなら、彼らと一緒に働く意味はあるのかな?

ソフトウェア開発者が、自分たちを嫌って6-12ヶ月で時代遅れだと笑う人たちのために水を運んでいるのは残念だよね。彼らはキャビアを食べながら(制裁を逃れてるかも)ダボスでシャンパンを乾杯してるんだから。みんなの成果を盗んだ後にね。https://xcancel.com/hamptonism/status/2019434933178306971

アンダーグラウンドレジスタンスがAIを毒データで妨害しようとしている https://news.ycombinator.com/item?id=46827777

あのエンジニアたちがCCのひどいパフォーマンスを直すまで、信じられないな(冗談だけど、なんでできないのかは気になる。できそうな気がするし)。実際、あの人は6〜12ヶ月以内にIPOを狙ってるみたいだよ。「クラウドを使わないと置いていかれる」って言ってるのは、そのせいなんだろうね。

AIが提供する本当の価値は、その作業のスピードと、ほぼ人間のように「理解する」能力、あいまいさをうまく扱う能力だと思う。まるで同僚のエンジニアに任せるみたいな感じ。それが価値なんだよね。ここで挙げられていることを全部やってしまうと、結局ウォーターフォールを再現して、スピードの利点を失っちゃう。だったら、自分でコードを書いて、AIを自分が書いたコードの初回レビューとして使った方がいいよ。著者が指摘している多くのことは、古いモデルの落とし穴に対する安全策のようにも感じる。12番目のポイントには同意する。タスクが小さいほど、モデルが本筋を外れていないか確認しやすい。小さな更新を早く行って、それを検証する方がいいし、その小さな更新の組み合わせが最終結果を生む。これは完全に「仕様書ドキュメント」のウォーターフォールに行かずにアジャイルだよ。

全体的にしっかりした投稿だし、経験豊富な人にとってもいいアイデアがいくつかあるね。「認証や認可など、高いセキュリティリスクのある機能を特定してマークする」っていうのはその一つで、こういう領域のコードを書く時はもっと時間をかけるけど、明示的なマークシステムは素晴らしい提案だよ。即座にレビューするメリットに加えて、将来のアップデートにもその文脈が残るからね。「物事を分解する」っていうのは、今やほとんどの人が本能的にやってることだけど、経験の浅い人がそれをうまくできないのをよく見るよ。

コードを書くのを避けるために、こんなに手間がかかるなんて、ちょっと大変すぎるよね。昔はコーディングが楽しくて仕方なかったのに…

私は逆のことを感じてる。昔は手書きで全部書くのが好きだったけど、今はClaudeのおかげでアーキテクチャにもっと集中できるようになった。コーヒーを飲みながらプロジェクトの次の部分について考えるのが好きで、どう書きたいかを考えると、Claudeがそれを埋めてくれるんだ。時々間違いもするけど、自分が気づいてなかったコードのミスも見つけてくれる。

しっかりした足場とお世話があれば、モデルをもっと早く効率的に動かせるよ。ツールを早く作れるしね。私はただコードを書くためにコードを書くんじゃなくて、作りたいものを作るためにコードを書くんだ。

コーディングの前に詳細な仕様書を書く必要があったのを覚えてる?それからみんな、仕様書を飛ばしてコードを書く方が早くて簡単だって気づいたよね?今また元に戻ってるのかな?詳細な仕様書を書くことの問題の一つは、それによって問題を理解していることを意味するけど、実際には問題を理解するのではなく、コーディングやテストを通じて理解することを学ぶんだ。じゃあ、今はどこにいるの?

宇宙飛行士1、AI支援の開発者たち:つまり、コードを書く前に何を書きたいかを計画して仕様を決めるのが重要ってこと? 宇宙飛行士2、ティム・ブライス:いつもそうだったよ…

まだ「ポータルで考える」ってことが足りてないよね。普通は、コーディングは高くついて時間もかかるから、事前に詳細な仕様を求めるんだけど、AIがある今はコーディングが安くなった。だから、AIに仕様を飛ばさせて、適当にコードを書かせて、次にそのソリューションを見直させて理解を深めさせて、より良いソリューションのための仕様を設計させて、また書かせる。必要なだけこれを繰り返せばいい。これ自体は新しいことじゃなくて、基本的にはジョー・アームストロングのプログラミング手法だよ。歴史上初めて、これが過剰に高くつかないってことなんだ。

みんなが基本的なベストプラクティス(リンティング、ドキュメンテーション、小さなインクリメンタルな変更)を今さら発見してるのが本当に馬鹿らしいと思わざるを得ない。AIが必要だからじゃなくて、前からこうやってやるべきだったんだよ。

開発者を10分以上やったことがある人なら、納期が迫っているときにベストプラクティスを常に守るのが難しいってことはわかるよね。でも、実際のコーディング時間がゼロに近づいているなら、他のことにもっと時間を使えるようになるんだ。AIシステムが実際に書いたドキュメントをコンテキストの一部として使うから、その重要性も増すよ!直接的な価値が見えると、以前は贅沢だと思われていたことを真剣に考えるようになるんだ。開発者を10分以上やったことがあるなら、非常に良いドキュメントを一生懸命書いたのに、次の人に無視された経験があるはず。LLMはそうじゃない。彼らは君のドキュメントを読むんだ。

投稿では7のリンティングについて簡単に触れているけど、私にとっては、大量の静的コード分析チェックを設定することがコード品質に最も大きな影響を与えた。私の静的分析の階層はこんな感じ(以下の階層はTypescriptに特化してるけど、他の言語にも応用可能):1. 型安全なコンパイラ(tsc) 2. 基本的なリンティングルール(eslint) 3. サイクロマティック複雑性ルール(eslint, sonarjs) 4. 最大行長の強制(eslint経由) 5. 最大ファイル長の強制(eslint経由) 6. 未使用コード/エクスポート分析(knip) 7. コード重複分析(jscpd) 8. モジュール化の強制(dependency-cruiser) 9. 共有/utilディレクトリが過剰に詰まらないようにするカスタムスクリプト(依存関係クルーザーをライブラリとして使って作成) 10. セキュリティチェック(semgrep) これらすべてを一つのpnpm checkコマンドにまとめて、タスクを完了としてマークする前にこれを実行するエージェントルールを定義してる。最後に、pnpm checkがコミット前フックの一部として実行されるようにして、エージェントがすべての問題に対処していることを確認している。これによってコード品質が劇的に改善されて、LLMのスロットマシンが時々詰まったときでも、手動でコードを簡単に修正できるようになった。(編集:初回コメントで触れ忘れたコミット前フックについて追加)

私のセットアップにはいくつかのことが含まれていて、時々LLMが何かが通過したと嘘をつくことがあるんだ。

こういうのは、あんまり直面しない問題だな。考えが曖昧だったり、冗長なコードだったり、不必要に防御的なプログラミングが本当にコードベースを腐らせる。正直、上に挙げたルールの中には、最大限の保守性を目指すなら無視してほしいものもある。

これ、私も同じようなところに落ち着いてる。プリコミットフックは譲れない。Claude Codeが「すべてのチェックが合格」と報告したとき、実際には14個のeslintルールが失敗してたこともあったし。静的解析を超えて、もっと厄介な問題にぶつかってる。すべてのリントルールを通過し、クリーンにコンパイルされ、テストスイートもグリーンだけど、仕様の微妙に間違った解釈を実装してるコード。例えば、404の代わりに空の配列で200を返すAPIハンドラーとか、技術的には正しいけど意味的には間違ってる。意図に対する行動の正しさを評価すること、単なる構文や型安全性だけじゃなくて、これはまだ誰も解決できてないギャップだよ。プロパティベースのテストは役立つけど、 invariantsを事前に形式化する必要があって、これがしばしば難しい部分なんだよね。

これの一番いいところは、AIボットが今、世界中のスマートなコーダーたちによって書かれている「AIで書く方法」に関する百万の投稿を読み、学び、消化することだよ。そして次世代のAIはこれをすべて取り入れて、皮肉なことに必要なくなるんだ。

彼らはまた、現在および過去の世代のLLMによって生成された無駄な情報も読むことになる。

一般的に、私はトップレベルの設計や大きな抽象化を自分でやりたい。結束性や結合度にすごく気を使うし、インターフェースには多くの思考を与えたい。実際には、LLMがいくつかの手間を省いてくれるのは嬉しいけど、いつカードを折ってゲームをやめるべきかを知る必要があると思う。生成されたコードの小さなバグは、自分で直す方が好きで、エージェントに頼むと、彼らが自分のコードを直すときに行き過ぎちゃうことが多いからね。

アイロニックなことに、エージェントを使って節約した時間を使って、技術書を猛烈に読んでる。コーディングエージェントのおかげで、O'Reillyのサブスクリプションに払ったお金の価値を本当に感じられるようになった。だから、コーディングエージェントは、時間を作って本を深く掘り下げることができるから、私をより良いエンジニアにしてくれてるんだ。時間に追われて、何かが動くために必要なことだけを読むのではなくてね。