リファクタリングの長い夜:GitHub Copilot vs. Cline
午前2時47分、私はWebSocketの再接続ロジック、レート制限、データベースフォールバックをすべて1つのモノリシックブロックで処理する400行のPython関数を見つめていました。私のタスク:37のユニットテストを壊さずに、それを保守可能な部分に分割すること。私には2つのAIアシスタントが利用可能でした:確立された市場リーダーであるGitHub Copilotと、「エージェンティック」なコーディングを約束する新興のCline。私は同じ条件下で、同じ問題にそれぞれ公平に挑戦させることにしました。その後に続いたのは、これらのツールが真に輝く場所と、失敗する場所についての、啓示、フラストレーション、そして苦労して得た洞察の夜でした。
セットアップ
私の開発環境:VS Code 1.97、Python 3.12、pytest、asyncio、websocketsを含む仮想環境。両方のツールは新しくインストールされ、認証済みでした。タスクは両方で同一:モノリスを、適切な関心の分離を持つConnectionManagerクラスにリファクタリングし、既存の動作をすべて維持すること。完了までの時間、コード品質、必要な手動修正の数を測定しました。
GitHub Copilot:スムーズなオペレーター
Copilotのアプローチは、予想通り、シームレスでした。ファイルを開き、モノリシック関数をハイライトし、Ctrl+Iを押してインラインチャットを開きました。次のように入力しました:「これを、再接続、レート制限、DBフォールバック用の個別のメソッドを持つConnectionManagerクラスにリファクタリングしてください。既存のテストはすべて合格したままにしてください。」
12秒以内に、Copilotは150行の提案を生成しました。クラス構造はクリーン:設定パラメータを持つ__init__、指数バックオフを使用する_handle_reconnect()、スライディングウィンドウを使用する_rate_limit_check()、元のロジックをミラーリングする_db_fallback()。生成されたコードには型ヒントとドキュメント文字列も含まれていました。
良かった点: Copilotは暗黙的にコンテキストを理解しました。self._wsがWebSocket接続であり、self._dbがデータベースプールであり、元の関数のwhile Trueループが_run()メソッドになるべきであることを認識しました。コードは最初の試行でコンパイルされました。
欠点: Copilotはレート制限ロジックで微妙なエラーを犯しました。元のコードはmaxlen=1000のdequeを使用し、手動でタイムスタンプをチェックしていました。Copilotのバージョンはtime.monotonic()を導入しましたが、dequeが空の場合を処理するのを忘れていました——最初の呼び出しでIndexErrorが発生しました。これにより3つのテストが壊れました。手動でガード節を追加する必要がありました。修正には4分かかりましたが、それは典型的な「正しく見えるが、間違っている」シナリオでした。
別の欠点: Copilotはテストファイルの存在を認識していませんでした。リファクタリングされたクラスを生成しましたが、テストが元の関数名(handle_connection)を呼び出している可能性を考慮していませんでした。新しいクラスメソッドはrun()だったため、handle_connection()へのすべてのテスト参照が失敗しました。テストのインポートと呼び出しを手動で更新する必要がありました。これは回避できたはずの10分のタスクでした。
パフォーマンス指標:
- 最初の提案までの時間:12秒
- 生成された行数:150
- 最初に合格したテスト:32/37
- すべてのテストを修正する時間:18分
- 最終コード品質:7/10(クリーンな構造だが、エッジケースの処理が不完全)
Cline:エージェンティックな挑戦者
Clineは異なるアプローチを取りました。インライン補完の代わりに、サイドバーチャットを開き、明確化の質問をしました:「ConnectionManagerはシングルトンにすべきですか?WebSocketがDB書き込み中に切断された場合の期待される動作は?非同期コンテキストマネージャーサポートは必要ですか?」私は簡潔に答え、Clineは計画で応答しました:「3つのファイルを作成します:connection_manager.py、rate_limiter.py、db_fallback.py。元の関数はマネージャーを呼び出します。また、pytestフィクスチャを使用するようにテストファイルを更新します。」
良かった点: Clineのエージェンティックモードは実際にファイルを書き込みました。ディレクトリ構造を作成し、新しいモジュールを書き込み、そして——重要なことに——テストファイルを開いて既存のテスト名とパターンを検査しました。次に、すべてのテストファイルでhandle_connectionをConnectionManager.runに名前変更する移行スクリプトを生成しました。レート制限器は最初から空のdeque処理を適切に行う別のクラスとして実装されました。DBフォールバックには、元のコードにはなかったジッター付きのリトライメカニズムが含まれていました。
欠点: Clineは遅かったです。計画フェーズには45秒の思考時間がかかりました(「コードベースを分析中...」と表示)。次に、ファイルを順次書き込み、各ファイル間に5〜10秒の遅延がありました。最初の完全なソリューションまでの合計時間:2分18秒。この間、VS Codeはほぼ応答不能でした——ClineのバックグラウンドプロセスはCPUの40%と1.2 GBのRAMを消費しました。
別の欠点: Clineは過剰にエンジニアリングしました。元の関数は400行でしたが、Clineのソリューションは3つのファイルにまたがる520行でした。ConnectionConfigデータクラス、カスタム例外階層、およびローテーションファイルハンドラ付きのロギングセットアップを追加しました。これらは要求されていませんでした。技術的には正しいものの、追加された複雑さによりコードのレビューが難しくなりました。不要な部分を削除するのに15分費やしました。