Kengo's blog

Technical articles about original projects, JVM, Static Analysis and TypeScript.

Agentic Coding用classファイル静的解析ツールをAgentic Codingで実装した

Rust 製の class ファイル静的解析 CLI inspequte を、Agentic Coding を開発の中心に据えて実装しました。結果として、人間がレビューするのは spec とテストケース、そしてリリース内容だけという運用に到達しています。

本稿で紹介するCoding Agent に多くを任せて人間はリリース内容確認に注力するワークフローを通じて、今後の Agentic Coding が目指すべき形がある程度見えてきたと思っていて、このツールのような Coding Agent が Definition of Done を判断するための CLI が洗練されるのではないかと思っています。

11年間追いかけた「ぼくのさいきょうの静的解析ツール」

FindBugs への貢献を始めたころの2015年に、静的解析ツールはこうあるべきだという理想をまとめたことがあります。その実現のために OSS の静的解析ツールを読んだり、その拡張を書いたり、数学的・技術的なバックグラウンドを理解するために学んだり*1ということを続けてきて2度スクラッチ開発に挑戦しましたが、いずれも当時の技術的限界や単純な開発量に圧倒されて未達のままでした。

それが今回 Agentic Coding の登場によって前提が変わり、非 JVM 言語で class ファイルの静的解析を書くハードルが急激に下がったことで、次のような課題が一気に解決されました。

  • 実行可能バイナリに直接コンパイルできる言語(Rust)で Java バイトコードを高速に扱うこと
  • Test Harness によって MCVE をそのまま回帰テストに使える仕組み
  • Kotlin と Java の両対応
  • control flow graph や data flow のスクラッチ実装
  • マルチコアを活かすための並列実行
  • 人間と Coding Agent に向けたドキュメントの自動生成
  • 複数ルールの開発を並行させてもコンフリクトを起こさないプロジェクト構成*2

さらにプロダクトのメンテナンスで必要になる配慮がプロンプトという形で保存・再生できるようになり、ひとりでプロジェクトを回すことのハードルも下がりました。 もちろんリリース内容に責任を持つのは引き続き人間がやるべきなのでリリース前レビュー工程は外せないのですが、静的解析は正解・不正解を仕様やテスト結果から判断しやすいこともあり、ルール開発のレビューはかなり任せられます。たとえば次のような内容をプロンプトやスキルとして保存しておくことで、一人で複数の作業を同時に実行したり、短い時間で進捗を作ったりという価値を出せています:

  • ルールの実装とテストにおける手順
  • ルール検討における観点
  • 仕様作成における観点
  • 実装における保守性の考慮と不具合を作りにくいテストの書き方
  • 実装評価における観点
  • 偽陽性を洗い出すプロセス
  • 複数プロダクトに対して静的解析を実行するスモークテスト
  • 同一条件で継続的に性能テストを実行して性能悪化を早期に把握する体制
  • 同一条件で継続的に他ツールとの性能比較をする体制

グラフにすると次のような感じです。青のところは Coding Agent をはじめとした自動化に任せられるところで、人間は緑の判断だけやるのと、赤のリリース承認だけやればよいという状況です。開発したルールの採用判断はまだ人間がやっていますが、判断基準が言語化できたらこれも自動化できそうです。

graph LR

%% ===== スタイル定義 =====
classDef auto fill:#E3F2FD,stroke:#1E88E5,stroke-width:2px;
classDef semi fill:#E8F5E9,stroke:#43A047,stroke-width:2px;
classDef manual fill:#FFF3E0,stroke:#FB8C00,stroke-width:2px;

class A auto
class B semi
class C manual

%% ===== ルール実装 =====
subgraph ルール実装
  企画 --> 計画 --> 仕様策定 --> 実装 --> 仕様と突合しての評価 --> 実装
  仕様と突合しての評価 --> 採用判断 --> mainに反映 --> ドキュメント更新
  企画 --> 不採用企画を記録して次に活かす
  採用判断 --> 不採用企画を記録して次に活かす
end

%% ===== 定期メンテ =====
subgraph 定期メンテ
  依存バージョン更新
  偽陽性調査と修正
  パフォーマンス低下要因の分析と修正
end

%% ===== リリース =====
subgraph リリース
  rev(リリース内容を整理) --> merge(リリース承認) --> rel[リリース]
end

%% ===== 凡例 =====
subgraph 凡例
  A[自動化可能(Agentに委譲)]
  B[半自動(人がトリガー・承認)]
  C[完全手動(人が思考・判断)]
end

%% ===== 分類 =====
class A,rev,実装,仕様と突合しての評価,mainに反映,ドキュメント更新,企画,計画,仕様策定,不採用企画を記録して次に活かす,依存バージョン更新 auto;
class B,偽陽性調査と修正,パフォーマンス低下要因の分析と修正,採用判断 semi;
class C,rel,merge manual;

AIを開発の中心に据えつつ人間がその説明責任を追うためのワークフローとして、この skill による自動化と人間によるリリース承認を中心に据えたやり方は筋が良さそうだと感じています。

で、ここまでだけなら「夢が叶いました!」なんですが、今回はもう少し風呂敷を広げて Agentic Coding 時代に求められる理想の静的解析ツールを追求しました。

Agentic Coding 時代に不要となったものもある

今回昔から思い描いていたツールを実現したと言っていますが、実際には必須と思っていた機能が不要となっている部分もあります。

2013年に FindBugs 関係の記事を書いたときは変更されたコードとその影響を受ける部分だけを解析する incremental analysis が必要だと思っていましたが、SonarQube のような巨大プロダクトですら10秒で解析できるようになるとシンプルに寄せられます。マルチコアを活かすための並列実行は重要ですが、複数ノードでの分散実行は大仰すぎました。Google Errorprone や Prettier が提供している自動修正はぜひ欲しいと思っていましたが、Coding Agent に十分な情報を提供できれば不要と判断しました。また IDE 統合も不要です。IDE を開発に使う頻度も落ちていますし、仮に使う場合でも Gradle 統合で乗り切れそうだからです。

なお Coding Agent が書いた Rust コードについては、人間はそこまで見ていません。人間は spec とテストケースだけ見るようにしています。共通コードに手を加える場合は既存テストケースを変えていないか厚めにレビューしますが、そうではない場合は spec が合理的で偽陽性検証のテストが書けていれば良しとしています。ルール変更の影響はそのルールに閉じるように設計することで、これを可能としています。つまりコードレビューもほとんど不要にできたということです。

Agentic Coding 時代、静的解析に求められること

Agentic Coding によって我々の開発サイクルはすでに大きな変貌を遂げています。 Coding Agent による PR レビューがすでに実用化され、人間も意識できていなかった観点を踏まえた高品質なレビューが安く早く行えるようになりました。 PR のレビューすら Coding Agent に任せて、リリースという意思決定を高速化しているチームも多いでしょう。

また Claude Code Security という、セキュリティ上の課題を高速かつ広範囲にわたって発見できるサービスも登場しています。不具合を中心に探してくれるBugbotもあります。静的解析を入れなくても、脆弱性や不具合を簡単に見つけられる時代になりつつあります。

さて、ではもう静的解析ツールは不要なのでしょうか?私はそうではないと考えています。静的解析の価値は「全自動マサカリ投擲機」であること、すなわちコードの品質を底上げるために「どこが問題か」「なぜ問題か」「どう改善できるか」を「めちゃくちゃ速く頻繁なスパンで」書き手に返すことです。そして Agentic Coding 時代でもこうした働きは次に挙げる2つの理由から引き続き必要です:

  1. Coding Agent には確実性が期待できないこと。品質底上げ効果にもムラがあるし、Coding Agent が書いたコードにも誤りが入る可能性がある。これは LLM の原理からも言えますし、複数のモデルやハーネスを組み合わせて利用することが一般的となっていることからも言えます。
  2. コードの書き手が人間から Coding Agent に変わっても「書き手にフィードバックを返す」ことの価値は毀損されていないこと。むしろテストやハーネスといった資産を整理することが重視されているように、フィードバックの価値は高まっています。

この2点を踏まえて考えると、いま必要な静的解析ツールは次のような特徴を備えているべきです:

  1. とにかく高速に実行できること。実行に数分かかってしまうようでは、Coding Agent の良さが活きないため。
  2. 結果が揺れないこと(同一入力に対しては常に同じ結果を返す)。
  3. CLI で動くこと。API や MCP を否定するものではないが、Coding Agent が変えたものの検証をその場で高速かつ少ないトークン消費で行うため。
  4. 出力が簡潔で Coding Agent にとって扱いやすいこと。

私は今回、こうした課題を次のようなアプローチで実行できると考えました:

  1. Rust で実装し、マルチスレッドを標準的に採用すること。
  2. ソースコード分析よりも多くの確定度が高い情報をもとにルールを適用するために、バイトコード解析を採用すること。
  3. CLI を実行可能バイナリとして頒布し、JRE のような前提を作らないこと。
  4. SARIF v2.1.0という Coding Agent が“常識”として知っているJSONベースの業界標準書式を採用し、その分析と解釈を助けること。

今のところこれらのアプローチは狙った結果を出しているように思います。Coding Agent からもビルドツール(Gradle)からも使いやすく、業務で開発する規模のマルチモジュールプロジェクトでも高速に分析して Coding Agent に対する入力として使えています。コーディングエージェントはプロンプトで明示的に教えなくても SARIF 2.1.0 を知っているので、SARIF ファイルを渡せば問題を理解して自分で修正してくれます。

実際どのくらい速いのか

「高速」を自称する以上、数値で語れるようにしたかったので、多くの静的解析ツールで実装されているNULLNESSルールに対象を絞って主要ツールと比較したベンチマークを公開しています:

ざっくり言うと、Guava 33.5.0-jre を対象にした比較では、inspequte の中央値は 0.250s で、同条件の nullness 系ツールに対して概ね 数倍〜桁違い の差が見えます(例:NullAway 1.234s / Checker Framework 1.314s / PMD 3.785s / SpotBugs 12.397s)。

また SonarQube 25.6.0.109173 を対象にした比較では、PMD 9.411s / inspequte 13.123s / SpotBugs 466.245s という結果になりました。比較対象や前提の違いもあるので詳細はリンク先に譲りますが、少なくとも「CI とローカルで何度も回す」用途でボトルネックになりづらい速度を狙って出せている、という手応えがあります。

他に試していること

ChatGPT による画像素材の作成も試しています。以前 99designs でプロダクトロゴを描いてもらったことがあるのですが、手間と資金が必要になるわりに思ったような結果は得られなかったんですね。ChatGPT なら当然レスポンスも早く、違ったときにやり直せるので、ズバリの結果が得られなくてもまぁ良いかなと思えるものにできました。ただ縦横のピクセル数だけは何度言っても変わらなくて、トリミング作業は自分でやっています。

ChatGPT に作成させたロゴ画像

ChatGPT に作成させた OGP 画像

また X におけるリリース通知の文面作成も任せてみましたが、こちらは「このリリースの目玉はそうじゃないんだよな〜」と思う結果が多く、結局文面を自分で作成して ChatGPT にレビューさせる運用になりました。

CHANGELOG の生成までは自動化できる(今回はモノレポに対応している release-please を利用*3)のですが、そのリリースに込めた思いのようなものは人間がまとめて伝えていく方法を採りたいと現状感じています。

静的解析以外の課題領域で同じアプローチが使えるか

今回実装だけではなく企画や仕様策定、評価までを Coding Agent に渡せたのは、静的解析やプログラミングにおける知識を彼らが元々持っていたからです。設計意図だけを書けばそれで十分で、data flow であるとか JVM stack であるとかの概念を教える必要はありませんでした。また入力や出力がほぼテキストとバイトコードという、LLM にとってもともと扱いやすいものだったのも今回の成功に強く寄与しているはずです。

これが Coding Agent が詳しくないドメインを扱うとか、人間などの不安定なインタフェースを相手にする必要性とかが生じると、コンテキストを伝えることの比率が上がって難度は上がるでしょう。それでも今後の技術発展によって扱えるコンテキスト量が増えるとか、サブエージェントの活用によってコンテキストを分割統治する体制を組むとか、Definition of Done をコマンドで検証できるようにしていけば、必ずできるようになるでしょう。特にこの「Definition of Done の検証」を CLI で高速に検証することの重要性は、今後静的解析以外のジャンルでも重視されると思います。個人的には品質目標とユーザインタフェースの評価についてこれができるようになり、人間の同期的な介入なしにプロダクトが成長する未来に関心がありますし、遅くとも年内には近い未来が見えるんじゃないかと期待するところです。

まとめ

Agentic Coding 時代の静的解析を再定義し、そのためのツールを Agentic Coding で実装しました。 人間は仕様とテストケース、リリース予定内容だけをレビューする体制になり、コードレビューも不要とすることで、 リリースの判断以外のほぼ全てを Coding Agent に任せられるワークフローが実際に構築できました。

こうした開発ワークフローを静的解析以外の課題領域でも構築できるかはまだわかりませんが、技術革新によってそれが可能になる未来はすぐに来るんじゃないかと期待しています。 その時に決め手になるのはコンテキストを分割統治する手法と、Definition of Done の検証を CLI で高速に検証する技術のはずで、関連する動きを追いかけていこうと思います。

*1:University of Aarhus の情報が役立ちました

*2:今回の静的解析プロジェクトの構成やプロンプトは次回掘り下げます

*3:リリース自動化については以前ブログ記事を書いています