最近はもっぱらAIをぶん回して開発する機会が増えてきました。 システム的な思考を持って多次元的に物事を考えられるエンジニアの重要性が高まっているのを常々感じています。
普段Goをよく書いている私ですが、とある記事に出会いました。
Go Group Product ManagerのCameron Balahan氏による、Goの次の記事です。
タイトルだけ見ると「AI時代にGoが最適」という、少し強めのGo推し記事なのかなと思っていました。
実際に読んでみると、そういう話というより、 AIが大量のコードを書く時代に、人間はどう安全にソフトウェアを作り続けるのかという話でした。
その中でGoが持つ性質が、今までとは少し違う意味で効いてきそうだなと思ったので、勉強になったことと自分が感じたことをまとめてみます。
まず刺さったのが、「書く」から「確かめる」への移動
これまで、プログラミング言語の生産性は「どれだけ速く書けるか」で考えがちでした。
でもAIエージェントは、数百行のコードを一気に提案してくれます。 これからボトルネックになるのは、人間がコードを書く速度ではなく、生成されたコードをレビューして、検証して、保守できるかどうかだというのが記事の中心でした。
“What matters now is reviewing, verifying, and maintaining that code once it’s already written.”
— Cameron Balahan, Why Go is an Ideal Language for AI-Assisted Software Engineering
これを見てかなりしっくりきました。
AIに実装を頼むと、コードが出てくること自体は早いです。 ただ、そのあとにやることはむしろ大事になります。
- 要件に合っているか確認する
- 既存の設計と矛盾していないか見る
- テストを実行する
- エラー処理や境界値を確認する
- 本番で安全に動かせるかを判断する
特にアーキテクチャやサービスの境界、運用上の安全性は、AIだけに任せられるものではありません。 AIを「めちゃくちゃ仕事が速いけれど、見守りが必要なチームメイト」と見ると、今の感覚にかなり近い気がします。
Goの「退屈さ」が、AI時代にはむしろ良さそう
Goは昔から、書き方の自由度が少ないと言われがちです。
gofmt を通せば見た目は揃うし、エラー処理は if err != nil が基本です。
凝った記法や魔法のような抽象化より、誰が書いてもそこそこ同じ形になることを大事にしています。
人間だけで書くなら、この素直さを少し窮屈に感じることもあります。 でも、AIがコードを書く前提で考えると、これはかなり大きな利点に見えてきます。
AIが同じロジックをいろいろな流儀で書いてしまうと、人間はまず「これは何をしているコードなのか」を解読する必要があります。
一方で書き方が予測できれば、レビューの注意をもっと重要なところに使えます。
- 存在しないAPIを呼んでいないか
- 条件分岐やエラー処理が抜けていないか
- 認可や入力値の扱いに問題がないか
- 既存の責務を壊していないか
“Ultimately, a language that is clear for humans is inherently clear for AI models.”
— Cameron Balahan, Why Go is an Ideal Language for AI-Assisted Software Engineering
記事中にもありましたが「Goでは、どのチームメンバーが書いたコードか分からないくらい同じ見た目になる」という話。私自身実際にGoを書いていてとてもそうだと感じています。というかGoの言語仕様のおかけで開発者ごとの実装のバラつきみたいなものを極限になくせています。 AIが書いたコードもそこに自然に混ざるなら、レビューの負担はかなり下げられます。
Goは言語だけじゃない。AI時代の開発プラットフォームとしても強い
今回いちばん勉強になったのは、Goを単体の言語ではなく、ソフトウェア開発全体を支えるプラットフォームとして見る視点でした。
Goには、最初からこうした道具があります。
gofmtによるフォーマットgo testによるテストgo modによる依存管理go vetによる静的な確認govulncheckによる既知の脆弱性の確認go test -fuzzによるファジング
AIに変更を頼んだあとも、いつものコマンドで確認できます。
gofmt -w ./path/to/file.go
go test ./...
go vet ./...
govulncheck ./...
この一連の流れは、人間が便利に使うためだけのものではなさそうです。
- AIが変更する
- formatter・コンパイラ・テストが結果を返す
- AIが結果をもとに修正する
- 人間は通過した変更をレビューする
AIに何度もリファクタリングを任せて、検証せずに次の変更へ進むと、少しずつ誤りが積み重なります。 ツールによるフィードバックを早く返せることは、品質だけでなく、AIとの会話を無駄に長くしないためにも大事そうです。ここは普段AIをぶん回していても結構感じます。
“When an AI agent is asked to refactor code iteratively without external validation, its performance can quickly degrade.”
— Cameron Balahan, Why Go is an Ideal Language for AI-Assisted Software Engineering
型と速いコンパイルは、AIのセルフチェックに向いている
LLMは、存在しないメソッドを呼んだり、型を取り違えたり、複数ファイルの整合性を崩したりします。
Goでは、そのような構造的な問題の多くがコンパイル時に止まります。
user, err := repository.Find(ctx, id)
if err != nil {
return err
}
return user.DisplayName() // 存在しないメソッドならコンパイルが通らない
もちろん静的型付け言語はGoだけではありませんし、コンパイルが通ることと正しいことも別です。 仕様の読み違い、境界値、認可漏れ、並行処理の設計は、テストと人間のレビューが必要です。
それでも、AIが「変更 → ビルド失敗 → 修正」を繰り返す際に、速いコンパイルで明確なエラーを返せるのは強いとということ! 機械的にあらかじめ潰せるミスに対応できるのはGoのよさの1つですよね。
“In Go, the compiler rejects these errors immediately.”
— Cameron Balahan, Why Go is an Ideal Language for AI-Assisted Software Engineering
依存関係とセキュリティの話も面白かった
事を読んで、生成コードとサプライチェーンをセットで考える必要があるのも勉強になりました。
AIに機能実装を頼むと、古いライブラリや、メンテナンスされていない依存を提案されることがあります。 Goは標準ライブラリが厚めなので、外部依存を増やさずに済む場面が多いです。 AIに実装を任せると依存候補も気軽に増やせるぶん、以前よりサプライチェーンを意識しておきたいと感じます。Goは標準ライブラリでカバーできる場面が多く、外部依存を必要以上に増やさずに済むのはいいですよね。
さらに外部モジュールを使う場合も、モジュールミラーやチェックサムデータベース、govulncheck といった仕組みがあります。
人間の注意力だけで依存の安全性を見続けるのではなく、ツールで確認できる範囲を増やしておく。
AIによってコード変更の量が増えるほど、この考え方は重要になりそうです。便利だからこそ、気軽に依存を増やさない仕組みも欲しいですね。
Day 2以降まで考えるGoらしさ
ここは読んでいて、地味だけどかなり大事な話だなと思いました。
コードはリリースしたら終わりではなく、要件は変わるし、依存も更新されるし、技術的負債も増えていきます。AIを使うと変更を作るスピードが上がるぶん、「直す」「追いつく」側の速度も一緒に上げないと、コードベースだけが先に進んでしまいそうです。
更新頻度が低いサービスを触るとき、どこまで影響が出るのかを考える時間は規模が大きくなればなるほど心理的な負担は大きくなります。
古いコードを新しいツールチェーンに持っていきやすい互換性の方針や、gopls・go fix のように標準的な道具で書き方を整えていけることは、そういうときの安心感につながる気がします。
しかも Go 1.26 では go fix が作り直され、go fix ./... でコードベース全体を新しいGoの書き方へ寄せる modernizers を実行できるようになりました。AIが少し古めのイディオムでコードを出してきても、あとから機械的に整えていけるのはちょっと嬉しいです。
単一バイナリとして配布しやすいこと、クロスコンパイルしやすいこと、プロファイリングやトレースが最初から使えることも同じです。普段は派手さを感じない部分ですが、AIが書いた変更を本番で長く扱うなら、こういう地味な土台のありがたさはむしろ大きくなりそうです。
“Codebases are living systems; they naturally decay, accumulate technical debt, and must constantly adapt to changing requirements.”
— Cameron Balahan, Why Go is an Ideal Language for AI-Assisted Software Engineering
もちろん、全部Goで書く話ではない
この記事を読んでGoをもっと使いたくなった一方で、すべてをGoで書くべきだとは思いませんでした。
機械学習モデルの学習や実験ならPythonのエコシステムは強いですし、より厳密な型の制約を設計に持ち込みたいならRustが合う場面もあります。 フロントエンドならTypeScriptを使うことが多いです。
ただ、AI機能を実際のプロダクトに組み込んだ後には、API、認可、ジョブ、キュー、外部サービスとの連携、監視といった「普通のソフトウェア」がたくさん残ります。
AIモデルの周辺を、長く安全に運用するサービスを書く場所で、Goはかなり頼りになりそうです。
読んでみて思ったこと
この記事を読んで、Goの良さを「速く書ける」ではなく、AIが書いたあとも確かめ続けやすいこととして捉え直せました。
書き方が大きくぶれにくいこと。 標準の道具で整形・テスト・脆弱性確認まで進められること。 コンパイラが早い段階で構造的なミスを止めてくれること。 そして、数年後にも保守しやすいこと。
コードを生成する速さが上がるほど、こういう地味な仕組みの価値は上がっていく気がします。
AIがどの言語でも高い精度でコードを組み立てられるようになれば、言語選定で「AIが書きやすいか」だけを見る意味はだんだん薄くなっていきそうです。今回の記事を読んで、AIが書いたあとにどう検証し、どう直し、どう運用していけるかまで含めて選ぶ視点が大事なんだなと思いました。
Goが言語だけではなく、ツールチェーンやエコシステムまで含めたプラットフォームとして整っているという話は、Goを選ぶべきだという結論よりも、AI時代に言語をどう選ぶかを考えるための目の付け所をくれた気がします。
GoがAI時代に特別な答えだとはまだ思っていません。 ただ、AIと人間が同じコードベースを扱っていくときに、Goの読みやすさや標準ツールは、以前より頼れる理由になりそうです。