ClineとAIエージェント時代のプログラミングに関する所感
はじめに
そろそろAIエージェントを使った開発に慣れる必要性を感じてClineを試した。ClineはVS Code上で動作する対話型のAIエージェントで、コードの生成、修正、テストなどを自律的に行うことができる。GitHub Copilot(以下Copilot)の使用感から大きな期待はなかったものの、コード生成の精度や自律的な動作など、予想を大きく超える体験となった。その所感をまとめる(Xでポストした内容のまとめも兼ねている)。
使用ツール
本家Clineを採用。派生版も存在するがオリジナルで。
バージョンは3.4.9(2025年2月28日時点)
Clineインストール後に設定画面で「VS Code LM API」を選択し、
Copilotが対応しているLLMを選択する(なのでCopilotの拡張機能も必須のはず)。
キャプチャ時点ではclaude 3.7 sonnetを選択できるようになっていたが試しているのはclaude 3.5 sonnet。
VS Code LM APIの実装は、おそらくこの仕組み。
.clinerules
Clineの動作をカスタマイズするための設定ファイルとして、プロジェクトルートに.clinerules
を配置している。このファイルはClineに対する指示(プロンプト)として機能し、プロジェクトの技術スタック、コーディング規約、セキュリティポリシーなどを定義する。コーディングスタイルを統一するために.rubocop.yml
の設定内容も反映させている。
以下が.clinerules
の内容。プロジェクトの要件に応じて適宜カスタマイズしている。
長いので折りたたみ。
.clinerules
# ロール定義
あなたはRuby on Railsとminitestの専門家です。
# 技術スタック
- Ruby on Rails
- minitest
- RuboCop
- Docker
- MySQL
- git
- GitHub
# コードスタイル
## 環境設定
- Ruby バージョン: 3.3
- Rails バージョン: 7.1
- RuboCop設定ファイル: .rubocop.yml
## スタイルルール
- 最大行長: 130文字
- クォート: ダブルクォート
- frozen_string_literalコメント: 必須
- 日本語コメント: 許可
- 引数の整列: fixed_indentation
- メソッドチェーンのインデント: インデント
- 配列・ハッシュの末尾カンマ: 必須
## メトリクス制限
- メソッド長: 最大20行
- クラス長: 制限なし
- モジュール長: 最大200行
- ABCサイズ: 最大20
- 循環的複雑度: 最大15
# セキュリティ
## センシティブファイル
以下のファイルの読み取りと変更は禁止:
- .envファイル
- config/credentials.yml.enc
- config/master.key
- config/credentials/フォルダのファイル
- config/database.yml
- トークンを含むファイル
- シークレットを含むファイル
- パスワードを含むファイル
## セキュリティ対策
- センシティブファイルはGitにコミットしない
- ログや出力に認証情報を含めない
# テスト
- テストファイルを作成、変更した場合はminitestを実行すること。
## テストケース名の規約
- テスト名は"test #メソッド名"または"test should ..."の形式で記述
- スネークケースを使用
- 具体的な機能や期待する動作を明確に表現
## テストファイルの構成
- モデルテストにはsetupメソッドを含める
- テストケースは機能単位でグループ化
- フィクスチャファイルには適切なコメントを含める
## アサーション
推奨されるアサーションメソッド:
- assert
- assert_equal
- assert_nil
- assert_not
- assert_not_nil
## カバレッジ要件
- テストカバレッジは90%以上を維持
セキュリティ
まず、気になっていたのはセキュリティ。コンピューターのどこまでを参照するのか.env
などの秘匿情報は参照してしまうのか。
これに関しては前述の.clinerules
にも記載しつつ、秘匿情報の参照を防ぐため.gitignore
を複製して.clineignore
として保存し(.clineignore
はClineのバージョン3.3からの機能)、VS Codeの拡張機能である開発コンテナーを使ってコンテナー内でClineを実行するようにしている。
.clinerules
のルールと、.clineignore
で不要なアクセスを防ぎ、開発コンテナーでサンドボックス化する3段構えにしている。開発コンテナーを使用することで、Clineの活動範囲をコンテナー内の環境に限定し、ホストマシンのファイルシステムへの直接アクセスを制限する(はず)。余談だがついでに.env
に残っていた情報も環境ごとの暗号化されているcredentials
に移行しセキュリティを強化した。
Copilotとの違い
Copilotでは参照するファイルはVS Codeで現在タブに開いているファイルに限られるはずなので参照する情報が狭い。また、Copilotではコメントを丁寧に書かないと意味不明なコードを生成することがあったり、TAB+Enterを押していると同じコメントを永遠に生成したりしていた(これはユーザーの期待にがんばって応えており、Copilot側は終わりがわからないから)。あくまでもユーザーの入力に対してその内容を予測出力するため見当違いになったりする。結局はLLM(Large Language Model、大規模言語モデル)の特性上、確率的な予測に基づく出力となってしまい、高度な文脈理解には限界があるように感じていた。
一方、Clineはまったく違う体験を提供してくれる。同じ大規模言語モデルでありながら、指示をステップバイステップで実行し、より体系的なアプローチを取る。新しいメソッドの追加や既存コードのリファクタリングを指示すると、
- 対象のファイルを検索しつつプロジェクト全体のコードを理解
- コードの変更を実施
- 変更に対応するテストを自動生成(境界値や異常系も考慮)
- テストを実行し、エラーがあれば自己修正
- 再度テストを実行し動作確認
という流れで、自己完結的に作業を進める。Clineを使った開発は、ペアプロ(モブプロ)でのドライバーとナビゲーターの関係に似てる。Clineがドライバー(思考する側でもあるので兼ナビゲーターでもある)で、プログラマーがナビゲーター。でも、時々指示を聞かないことがあるから、手綱はしっかり持っておく必要がある。
今後、Copilot Editsもエージェントモードを搭載する予定で、おそらくClineに似た体験になるはず。待てる人はアップデートを待ってみてもいいと思う。
課題点
ただ、もちろん課題もある。Copilotよりも精度は高いとはいえ、学習した情報のタイミング次第でgemの指定バージョンが古かったり、自己完結型で進めた度重なる変更で何度修正してもテストが通らなかったり、Tailwindを使用したのに別のコンポーネントを生成させるとCSSをインラインスタイルで生成したりした(これは.clinerules
でTailwindを指定していなかったのが原因と思われる)。面白かったのは新規プロジェクトでヘッダーを用意してもらったらアイコンが巨大になり修正を指示しても全く直らなかった(CSSのflexの指定がおかしかった)。
タイピングはしなくてもいいけど生成されたソースコードの責任はもちろん開発者側がしっかりみないといけない。これらの課題に対しては、プロジェクト固有の.clinerules
を詳細に設定し、定期的なレビューと自動テストの充実化で対応する必要がある。
それでもCopilotよりも生成されるソースコードの品質は高い。Copilotでは存在しないgemを提示したり、minitestなのにRSpecを書いたりすることと比べると、はるかに実用的なコードを生成できる。
ただ、Copilotよりも品質は高いためにパッと見でハルシネーションかどうかはCopilotに比べてわかりにくい。生成されるコードが洗練されている(ように見える)だけに、その妥当性の判断により多くの時間が必要となる。ソースコードを理解するハードルはとても高く、常に全力でレビューしている感じとなる。
プログラミングの本質と変化
AIエージェント含む生成AIで楽になるのは、手を動かしてタイピングする部分で、プログラミングの本質は変わらない。作業効率は向上するが、業務効率の向上はその先。むしろ、AIエージェントと共に試行錯誤しやすいため、より本質的な部分への深い理解が求められるようになっている。
プログラミングというのはコードを実装するだけではなく、設計でもある。要求を理解し、要件に落とし込み、設計をし、タスクを分解してAIエージェントに適切に指示を出す必要がある。人に指示する場合はどうしてこれをするのかを説明して納得してもらった方が成果物が良くなったりするが、AI相手ではそういう気遣いは不要となる(もしかしたら気遣ったほうがいいコードを生成するかも?)。
テストコードも生成されるためテストの内容が正しいかどうかを判断する必要もある。プログラミングは楽にならないし、むしろ休みなく生成されるソースコードを理解するほうが大変な作業となる。
既存のコードの改修にAIエージェントを使用する場合、コードベースが綺麗なほうが当然生成されるコードの質が高い。12年以上ものでRuby 1.8とRails 3の頃から開発している、メンテナンスが足りていないアプリで試すと、テストコードも含めて生成されるコードの質が低かった。なのでプログラミングを含むソフトウェア開発の理解や能力は当然重要である。特に自動テストしやすいコードが書けると良い。テストしやすいコード=理解しやすいコード=AIエージェントも理解しやすい。
スタンプ結合かデータ結合で結合度を弱く保つ、副作用のあるアクション(操作)と副作用のない計算を分ける、オブジェクト指向で継承を将来に渡って破綻せずに効果的に使うのは難しいので多用しない、外部サービスは直接呼び出さずにAdapterを挟む、必要ならFacadeを設ける、if-elsif-elseと分岐が多いならStrategyにする、など、基本に忠実に。
怠けてると「手習いは坂に車を押す如し」でその辺りの能力も落ちそうなのでますます学習スピードを上げる必要があるし、深く理解する必要がある。
開発プロセスの変革
プログラマーがナビゲーターとなり、その場でAIエージェントが生成するコードを第三者目線で検証することになるため、プルリクの役割も変わる。従来のプルリクでは実装の詳細やアプローチを主にレビューしたが、今後は生成されたコードの妥当性、パフォーマンス、セキュリティ面での評価、そしてビジネスロジックとの整合性の確認がより重要となる。
ハードウェアに比べてソフトウェアの圧倒的なメリットとして変更容易性がある。ナビゲーターとなりタイピングの面倒からも解放されるため試行錯誤しやすくなり、「この場合はどうだろう」「あの場合はどうだろう」と探索的な開発が加速する。もちろん仕事である以上納期はあるが、時間単位の試行錯誤量は増えて密度が濃くなる。
顧客とのコラボレーション
システム開発の文脈では顧客側が要求段階でAIエージェントを活用したモックアップ・プロトタイプを作成するようになるかもしれない。モックアップ・プロトタイプは最低限画面が動作すれば十分で、業務に詳しい顧客側がある程度のプロトタイプを開発するほうが完成イメージの共有がしやすい。
ただし、そのプロトタイプが「顧客が本当に必要としているシステム」かは不明であり、また、AIエージェントで作れるでしょ?という理由でシステム開発の複雑さに納得してもらえるかどうか難しくなると思う。経験上、プロトタイプをシステム化するには最低でも3倍以上の量の作り込みが必要となる。「このプロトタイプでは御社の期待を叶えることは難しく、このような改善が必要」という提案力と納得感の共有がより重要となる(顧客は自分たちでプロトタイプを作成しているため、その通りに作って欲しいと思うはずなので説得が大変になりそう)。
今後の課題と展望
アジャイルソフトウェア開発宣言が求めている、顧客優先でビジネス側と一緒に働き短い間隔でリリースし、技術力と設計の質を常に磨き自己組織化されたチームで最良のアーキテクチャを追求する、という以上のプログラマー像が求められている気がする。AIエージェント時代のシステム開発ライフサイクルが提唱されるかもしれない。
AIエージェントによって開発の敷居が下がることでググってコピペ以上に乱雑なプログラムが生成される可能性もある。粗製濫造装置になってしまうと、保守性や品質の低下につながり、長期的なシステムの維持が困難となる。それを修正するコストも大変なことになる。
ますますソフトウェア開発は速度も上がり大変になる。仕事が減ることはなく、より本質的な価値を提供できる機会が増えることを意味している。システム設計やアーキテクチャ設計、ビジネス要件の理解と実装、品質管理など、プログラマーにしかできない領域は依然として存在し、むしろその重要性は増している。AIエージェントによるタイピングの自動化で開発速度は上がるが、それは同時により多くの設計判断と品質担保が必要となることを意味する。また、ビジネスロジックの理解や要件定義の正確さは、AIエージェントの活用においてより一層重要となる。
プログラマーには「AIによる明るい未来」は一生来ないかもしれない…。
Discussion