みなさんこんにちは、XI本部エンジニアリングオフィスの佐藤太一です。
このエントリでは、私がRustで実装したJava用バージョンマネージャであるKopiを紹介すると共に、実装の過程で得た生成AIを使ったソフトウェア開発に関する知見を共有します。
Kopiのソースコードとドキュメントは全てClaude Codeによるものです。私自身は開発環境の構築とメンテナンスをしながら、プロンプトによる指示のみで、約2か月弱の期間に約四万行のRustコードと約六千行のMarkdownを書き上げました。行数の計測においては、コメントや改行は除いています。
成果物は全てオープンソースソフトウェアとして公開していますので、興味を持ったら是非、公式サイトに来てください。
Kopiの紹介
ここでは簡単にKopiを紹介させてください。
Java用バージョンマネージャとは何か
要はローカルにインストールした複数のJavaを必要に応じて切り替えられるソフトウェアのことです。
この手のソフトウェアで私が最初に使ったのは恐らくrvmです。次々とリリースされるRubyの新しいバージョンに追従するために、気軽に使えるインストーラーとして使っていたと記憶しています。
今やどのプログラミング言語にも開発ツールキットを切り替えられるソフトウェアが提供されています。Pythonならvenv、uv、pyenvがあり、Nodeならvolta、nvm、nがあり、様々な言語を統一的に扱えるasdfやanyenv、mise、aquaといったツールがあります。
もちろん、Javaにもバージョンマネージャはいくつかあります。jenv、jabba、sdkmanあたりがよく使われているんじゃないでしょうか。
Java用バージョンマネージャをなぜ新しく作るのか
生成AIに渡す課題として、大きすぎず小さすぎず実用性があり私が作りたいからです。検証課題として、どのようなことを考えていたのかは後述します。
一応、それっぽい説明をしておくと、Java専用に作られており、複数のプラットフォームで動作し、メンテナンスが継続しているものがないからです。
jenvやsdkmanはシェルスクリプトの塊なのでWindowsでは動作しません。jabbaはGoで実装されているので複数のプラットフォームで動作しますが、もう何年もメンテナンスされていません。
ちなみに、複数のプラットフォームで動作する様々な言語やツールに対応したバージョンマネージャとしては、miseがあります。
Rustで実装されているmiseは非常に高機能で、複数の言語を管理するだけでなく、環境変数をプロジェクトごとに調整しながら、タスクランナーとしても動作します。
Javaのバージョン管理機能もコア機能として含まれています。今の時点で、Kopiのmiseに対する優位性はJava専用の検索機能を提供していることと、再現性のあるフォーマットで詳細にバージョンを指定できることです。
インストール手順
どういうツールなのか分かったところでインストールの方法を説明しましょう。
OSとしては、Windows、Mac、Debian/Ubuntuをサポートしています。CPUについてはIntel系とARM系の両方をサポートしています。
Windows11でのインストールは以下のコマンドを実行してください。
winget install kopi
macOSでのインストールはHomebrewを使います。
brew install kopi-vm/tap/kopi
Debian/Ubuntuはgpgキーのインストールなど少々ややこしいのでシェルスクリプトを実行する形式です。中身は自前のPPAリポジトリからdebパッケージをダウンロードするようになっています。
curl -fsSL https://kopi-vm.github.io/install.sh | bash
Rustで実装したツールですので、crates.io にも公開してありcargoでインストールできます。
cargo install kopi
各パッケージマネージャでのインストールが終わったら、setup コマンドを実行します。
kopi setup
必要なディレクトリが作成されます。続いてshimsディレクトリをPATH環境変数に登録するように利用中のシェルに応じて指示が表示されますので、それに従って環境変数を調整してください。
例えば、bashでは以下のように指示が表示されます。
基本的な使い方
インストール方法が分かったところで次は基本的な使い方を説明します。
まずは、自分のプロジェクトで使うJavaを決めて設定ファイルを作成しましょう。
Kopiは専用の記法で選択的にJavaをインストールできます。
# 一番基本的なインストール。この場合ディストリビューションはTemurinになります。 kopi local 21 # ディストリビューションを指定する場合、@の手前にディストリビューション名を指定します。 kopi local corretto@24.0.2 # JRE を指定する事もできます。 kopi local jre@zulu@17.0
これによって、 .kopi-version
というファイルが出力されているはずです。例えば、一番上のコマンドを実行した後の中身は以下のようにインストールしたJavaのバージョンが記載されています。
temurin@21.0.8
この状態でjavaコマンドを実行してみましょう。以下のように出力されます。
java --version openjdk 24.0.2 2025-07-15 OpenJDK Runtime Environment Corretto-24.0.2.12.1 (build 24.0.2+12-FR) OpenJDK 64-Bit Server VM Corretto-24.0.2.12.1 (build 24.0.2+12-FR, mixed mode, sharing)
今度はJavaのディストリビューションを検索してみましょう。検索もインストールするのと同じ記法が使えます。
kopi search zulu@21
検索結果はこうなります。結果の最上部にあるものが実際にはインストールされるわけですね。2段目以降をインストールしたければ、より詳細にバージョン番号やビルド番号を指定しましょう。
最後は一時的に違うバージョンのJavaを使ってみましょう。
kopi shell oracle_open_jdk@21
このコマンドを実行すると、現在使っているシェルの子プロセスとして指定したJavaが使えるシェルが起動します。
生成AIを使ったソフトウェア開発
Kopi の基本的な機能を説明しましたので一定の実用性があるソフトウェアであることは、ご理解いただけたでしょう。
ここからは、Kopiをどのような手法で開発したのかを説明します。
KopiはRustを使って実装していますが、全てのソースコードをClaude Codeが記述しています。改行の一つも私は出力されたものに手を入れていません。Markdownで書かれたドキュメント類も同様です。
私がこの開発において作業しているのは、開発環境のセットアップ部分です。例えば、Rustの開発環境を構築するための Cargo.toml や rust-toolchain.toml は私が手書きしています。
また、CI/CD環境であるGitHub Actionsのワークフローについても私が手書きしています。
GitHubにはコミットしていませんが、開発に使っているDevContainerの構築についても私が用意しました。
Kopiの開発における課題設定
Kopiの開発は実用性があるソフトウェアを、生成AIでどこまで作れるのか?という研究開発の一環で行っているものです。
最終的には、弊社の主たるビジネスである受託開発やパッケージ開発において、生成AIを導入するための足がかりの一部となることを企図しています。
この開発を行うにあたって、最も重要な検証項目はコードを書く作業を一体どこまでなら生成AIに任せられるのか?ということです。
そこで、私自身が取り扱うことの出来ない言語を採用することで手出しが出来ないようにする必要がありました。そのために実装言語としてRustを選んでいます。お恥ずかしいことですが、私自身はどうしても借用の概念が理解できず、いまだにRustを手書きするといつまでたってもコンパイルが通りません。
これは、受託開発やパッケージ開発においてコードを大筋で読むことはできるが書くことは出来ない業務のエキスパートが生成AIを使った場合に、どのような印象を受けるかという視点を模倣したいという意図があります。
生成AIを使った開発の生産性
まずは、分かりやすい生産性指標としての生産コード行数を提示しつつ、この八週間くらいの間にどのような心境の変化があったのか説明しましょう。
ここでは、ノウハウにあたる部分については説明しませんので、読み飛ばして貰っても結構です。
まずは、コードの変更量グラフです。六月の中旬から開発を始めて、約一週間ごとに棒グラフになっています。最初の週が最も生産量が多く約二万行のコードを出力しています。これをピークにその後は徐々に生産量が減っていき、開発がほぼ終了した七月の最終週には一万三千行くらいになっています。
恍惚とした最初の一週間
最初の週はAIハッピーとも言える恍惚とした体験でした。Rustという自分では全く扱えない言語のコードを生成AIが想像を絶する速度で出力していき、それらが全て何となく動いているのです。
私にとって最も得意なプログラミング言語はJavaとTypeScriptですが、それらを使ったうえで働き慣れたプロジェクトで完全に整備された開発環境と疑う余地なく確定した業務仕様が存在するとしても、一週間で二万行のコードを生産することは不可能です。
この時点ではまだ、Claude Codeを使い始めたばかりで、暗中模索といった状況でさえこの量の動くコードが出力されるのですから、プロセスをきちんと整備し私自身が生成AIを使い慣れていけば、一人で月間十万行程度のコードは実装できるのではないかと考えていました。つまり、三か月もあれば三十万行程度のシステムが作れる……。
普通のSI案件なら十人単位の人間が働いてもおかしくない規模感です。そして重要なこととして生成AIに仕事を依頼中はプログラマの手は空くのです。つまり、PMと一緒になって顧客折衝に参加できます。この時点で私は生成AIの登場によって世界はひっくり返ったと感じていました。
リファクタリング地獄とプロセス整備の二週目、三週目
夢のような時間は長続きしないものです。
できあがった成果物を冷静になって評価してみると、間違いなく機能しているコードはあるものの、大半はそれっぽく名付けられているのがよく見ると意味不明な関数名やモジュールが一貫性なく定義されており、コーディングスタイルもバラバラです。見せかけだけで何もテストしていないテストコードや何も計測していないベンチマーク、そういった実際には役に立たないものが数万行規模であふれていたのです。
二週目と三週目はほとんど機能を追加することなく、コードの整理と名前付けルールの整備、開発プロセスの整備を行っていました。前の週と違って全く進捗を感じられない低調で辛い時間です。ここで、自らが持つ生成AIに対する過度な期待が打ち砕かれてしまいました。
この時期から、生成AIがある種のコンプリートガチャ(コンプガチャ)であると考え始めます。
コンプガチャとは、複数のアイテムをそろえることで特別な報酬を得られるガチャシステムのことです。2012年ごろに大きな社会問題化し規制されることになりました。
コンプガチャが規制されているのは、複数のアイテムをそろえることについて人間の認知する確率と実際の確率に大きな乖離があり、その乖離を意識しないままにガチャを回すことに熱狂してしまうからです。
Claude Codeの制約が急にきつくなった四週目
生成AIがコンプガチャであると考えることで、自分の精神状態がどうなっているのか客観視できるようになります。
ソフトウェア開発におけるコンプリート状態を定義するのは少し難しいものの、全ての機能が手書きしたときと同程度のソフトウェア品質で完成した状態を100%と仮定してみましょう。コンプガチャなので、四割から五割くらいまでは比較的容易に到達します。しかし、八割を超えたあたりから急速にアタリの頻度が低減します。
このように考えると、生成AIを使ったソフトウェア開発に対する熱狂と幻滅が起こる原理に近づいている感じがしませんか?
私が契約しているのはMAXプランの20倍ですが、DevContainerで構築した私の環境ではclaudeプロセスを複数同時に起動していると数分で一つを残してプロセスがシャットダウンされるようになってしまいました(8月現在は、その制限はなくなっているようです)。それまで、常時3つから4つくらいのclaudeプロセスを動かしていたので、成果物の生産量に大きくブレーキがかかってしまいます。ホストOS側のWindowsとDevContainer内の二つ同時に動かすことは出来ていたので生産力が激減という程でもなかったのが幸いでした。
プロセスを磨き続けた五週目、六週目
JDKのメタデータを取得するために使っているFoojayのデータが突然吹き飛んで何もデータが取れなくなるなど、アクシデントはいくつかあるものの順調に開発が進んでいきます。
安定して一万行程度のコードを生産しているように見えますが、実は五週目の中盤から六週目の前半にかけて夏休みをとっていたので、その間は全く稼働していませんでした。
ということは、この時点でかなり生産量が戻ってきているのです。しかし、六週目には当初に予定していた機能の実装が全て完了してしまいます。
生成AIの限界に到達した七週目
八月の第一週は露骨にコードの生産量が低減しています。これはなぜかというと、機能の実装が完了して各OS固有のパッケージングを実装し始めたからです。
例えば、WindowsではWiX Toolsetを使ってmsiに実行バイナリをパッケージングしています。まず、Wixという語がインターネット上では二つの全く違うものを指しています。一つはVisual Studioから分離したインストーラーの作成ツール、もう一つはWebサイトを簡単に作れるWix.com というSaaSです。
検索エンジンで知識を収集すると一定の混乱があるわけですね。このような状況では生成AIはほとんど機能しません。話を難しくする状況として、広く使われているWiX Toolsetはv3ですが、v4で大きな変更があった後、急速にバージョンアップが行われておりv3とv4のメンテナンスが終了し、現在はv6が最新です。公式のドキュメントは比較的充実していますし、MSDNにもドキュメントはそれなりに存在するのですが、生成AIにとって都合の良い形をしていないようです。
どうしてもv3対応の構成定義をしてしまいv6でビルドしようとしてエラーになる。細かく指示を出してv6の記法を使わせても、少しでも曖昧な指示をするとv3の記法を混ぜ込んでしまうことで混乱し、ビルドが失敗するようになる。こういうことを繰り返すので全く進捗しなくなってしまいました。
結果的に、Wix Toolset、Homebrew、nfpmを用いた構成定義と、それらをGitHub Actionsでパッケージングするワークフローは私が手書きしています。
見積り精度に現実味がでてきた八週目
パッケージングの動作確認としてインストールテストをしている最中に、比較的大きなバグを見つけてしまいました。八週目で突然コードの変更量が一万行にも及んでいるのは、このバグに対応する作業を実施したからです。KopiはmacOSでも動作するのですが、私がmacOSを普段使いしていないために、Application Bundleというディレクトリ構成に関する知見がなく、それを反映したアプリケーションの実装になっていなかったのです。
しかし、ここまでに蓄積した開発プロセスに基づいて、技術調査、機能設計、実装計画の立案という流れが安定していたので淡々と機能実装を進められました。
生成AIを使った開発プロセス
ここからは、この八週間で得た生成AIを使ったソフトウェア開発において私が蓄積した知見を説明します。
成果物の出力は基本的に英語でやるべき
生成AIが持っている知識や情報の検索処理は基本的に英語で実施されているようです。
生成AIの出力成果物であるドキュメントやソースコード、プロンプトの応答はコンテキストの永続化モデルです。
つまり、出力成果物は英語にしておくと翻訳タスクが実行されない分コンテキストウィンドウの消費量を低減し、処理効率の改善が見込めます。
生成AIは出力したものの中身を理解してないと考えるべき
生成AIの仕組みとして、コンテキストウィンドウに蓄積した情報に乱数を混ぜつつ、蓄積している断片的な情報を組み合わせて出力を行います。
つまり、出力したものの整合性が取れているかどうかは、現状だとほぼ検証されていません。
よって、生成AIが何かを出力したら、出力されたコードなりドキュメントなりを検証してフィードバックを返す必要があるのです。
フィードバックを生成AIに返す一番明確な方法は人間が出力成果物を理解したうえで、プロンプトによって伝えることです。
しかし、これは人間のレビュー速度が生成AIが成果物を出す速度を上回る必要があり、現実的には持続可能性がありません。
加えて、生成AIが出す8割の成果物はほぼ意味のないものです。人間は意味のないものを無限にレビューし続けることはできないでしょう。
幸運なことにソフトウェア開発には、これまでの技術的蓄積としてレビューを自動化するための仕組みが多数存在します。
それが、継続的インテグレーションです。現代的なプログラミング言語には、必ずコードフォーマッタやLinter、コンパイラなどの自動的にコードの不備を指摘するためのソフトウェアがそろっています。もちろん、自動化されたユニットテストや結合テスト、E2Eテストも成果物の妥当性を生成AIに伝える良い手段になります。
これらを使って生成AIが出力した成果物を自動的に検証し、無意味なものを人間がレビューせずに済む環境を構築しましょう。
要件定義→外部設計→作業計画の流れを作るべき
自然言語を使ってコンテキストを構築する以上、生成AIを使ったソフトウェア開発においても、これまで私たちが蓄積してきたノウハウはそのまま適用可能です。
Claude Codeのコンテキストウィンドウには二十万トークンという明確な制限があります。これを実作業に照らし合わせて考えると、おおむね30分~60分程度で実施できる作業範囲内に収まる情報量です。人間に比べるとあまりにも少ないですね。
つまり、生成AIに対して指示を出すにあたって、作業範囲に関する知識はできる限り小さく集約されており、一貫性があり、正確で再現可能なものであることが望ましいということです。
これは、プロンプトを記述する人間に求められる最も重要な技能です。自らの指示が、どういう意図で何をやりたいのか、作業の完了や完成をどのように定義するのかを言語化できると、生成AIが作り出す成果の精度が向上します。
例として、直近で私がそれなりに難しいタスクとして実装したApplication Bundleに関連する実装作業について確認してみましょう。
まず、私自身がmacOS用のインストールテストを実施している際に発見した奇妙な状況をClaude Codeに共有し、それがどういうものであるのかをplan-modeで説明してもらいました。
いくつかの質問と応答の後、その状況がApplication Bundleという仕様に基づくものであり、私が奇妙だと感じたものが、実はmacOSにおいてはきちんと仕様化されたものであることが分かります。
そうして生成AIと私が議論した結果をArchitecture Decision Record(ADR)として記録したものがこれです。
これによって、Application Bundleに対してKopiではどのような方向性で対応を行うのかが決まりました。
次はこれを使ってどのように実装するのか機能仕様をDesignDocとして記述してもらいます。
ここで、自分が生成AIに対して期待していることを余すことなく言語化します。要求の中で曖昧な部分や矛盾している部分を消し込んでいくために、出力されたDesignDocをレビューします。なお、Claude Codeはソースコードで説明しようと試みることがありますが、これを承認すべきではありません。
満足のいくDesignDocになったら、次は作業計画の立案です。
作業計画書のフォーマットにはいくつかポイントがあります。
- フェーズ分けをすること。各フェーズの切れ目では
/clear
コマンドによってコンテキストをクリアすることをプロンプトの中で宣言すること。 - 各フェーズで入力となる成果物を明記すること。
- 各フェーズで行うタスクの一覧は更新可能なチェックボックスで構造化し、作業状況の進捗に応じて作業計画を更新させること。
- 各フェーズでの作業成果物を明示するか、作業完了をどのように確認するか明記すること。
- 各フェーズは30分~60分程度で終わる粒度になるよう調整すること。長時間のタスクを現在の生成AIでは実施できません。
こうすることによって、生成AIが各フェーズ内において必要十分な情報をコンテキストに読み込んだうえでコードの生成を行うようになります。
作業計画の立案が終わったら、 /clear
コマンドでコンテキストをクリアし、 @docs/tasks/ap-bundle/plan.md のフェーズ1を実装してください
のような形で指示を出します。
出力されたソースコードを確認して、微調整をしたらフェーズの完了確認のために、自分でコミットをします。
私の場合は、生成AIに対しては基本的に読み取り以外のgit操作をさせないことにしています。それは、おおむね一発で精度の高い成果物を出してくるわけではないからです。細かい調整をしながら --amend
コミットをしても良いのですが、そうするくらいなら最初からコミットさせない方が良いという判断を現在はしています。
CLAUDE.md には以下のような記載があり、ほとんどの場合では、フォーマッターやLinter、ユニットや結合テストを実行するのですが、コンテキストに余裕がなくなってくると、生成AIがそれらを実施しないことがあります。
## Development Workflow ### Completing Work When finishing any coding task, always run the following commands in order and fix any issues: 1. `cargo fmt` - Auto-format code 2. `cargo clippy --all-targets -- -D warnings` - Check for linting errors in test code 3. `cargo test --lib --quiet` - Run unit tests (faster than full test suite) Address any errors from each command before proceeding to the next. All must pass successfully before considering the work complete.
実施していない様子が見えたときには、カスタムスラッシュコマンドとして /finish
というコマンドを定義していますので、これを実行します。
現時点では、生成AIの技術進歩や新しい技法の発見速度が非常に速いので、あまり多くのカスタムスラッシュコマンドを作りこんでしまわないようにしています。
ここで紹介したやり方は、AmazonのKiroと概要レベルでは非常に似通っていますが、ある程度の規模でAI駆動開発を行おうとすると、誰もが同じやり方に到達するのでしょう。ドキュメントを読む限りでは、Kiroの方が洗練されたやり方のように感じられます。私自身はKiroをまだ試せていないのですが、今後取り入れていきたいと考えています。
まとめ
このエントリでは、生成AIの一つであるClaude Codeを使って実装した、JDKのバージョンマネージャであるKopiを紹介しました。
この約二か月間の間に起きた私の心理的変化について、皆さんに共有したのは今の生成AIブームがある種の熱狂を生んでいると感じているからです。個人的には、15年から20年ぶりの技術的な熱狂を感じながら生成AIを触っています。
この新しい道具が一体どこまで成長し、私たちの仕事や社会を変化させるのか、一緒に楽しんでいけるなら幸いです。
執筆:@sato.taichi
レビュー:@yamashita.tsuyoshi
(Shodoで執筆されました)