AIに自分のコードベース全体をリファクタリングさせた方法(Gemini 3.5を使用)

Dev.to / 2026/5/21

💬 オピニオンDeveloper Stack & InfrastructureIdeas & Deep AnalysisTools & Practical UsageModels & Research

要点

  • 著者は、ソロ開発者としてタイトに結合したレガシー・モノリスをほどいてマイクロサービスへ抽出するには、何か月もの手作業が必要になり得る点を述べています。
  • Google I/O 2026のエージェント型ワークフローの発表をきっかけに、リポジトリ改修を自動化するワーカー「Flash」を構築したと説明しています。
  • Flashはコードベース全体を読み取り、隠れた依存関係をマッピングし、機能を独立したマイクロサービスとして切り出すクリーンなプルリクエストを生成します。
  • この取り組みでは、Gemini 3.5 Flashの1Mトークン級の大きなコンテキストウィンドウと高速性を活用し、少数ファイルしか参照できない手法の限界を回避しています。
  • リファクタリング用エージェントはGoogleのInteractions APIと「thinking_level」設定を用い、実装に入る前にアーキテクチャを計画するようにしています。

個人開発者であれば、金曜の午後のデプロイに伴う恐怖を誰でも知っています。ユーザープロフィールのコンポーネントに些細なアップデートを入れたはずなのに、なぜか支払い処理のパイプライン全体が停止してしまう。これはレガシーなモノリスと共に生きることの、厳しい現実です。
5年以上の急速な開発の中で、私のサイドプロジェクトは、密結合したロジックの巨大な網へと膨れ上がりました。ユーザーシステムは課金システムに依存していました。課金システムは通知サービスに依存していました。これらの部品をきれいなマイクロサービスに切り出すことは、何年も前からやることリストに入っていました。問題は、私が一人しかいないということです。何千もの未ドキュメントのファイルを手作業で追跡し、混沌を自分一人でほどくのに必要な6か月など、単純に確保できませんでした。
Google I/O 2026のキーノートを見たとき、エージェント型ワークフローに関する発表が即座に目に留まりました。これで、この悪夢をようやく自動化できると気づいたのです。私は自律的な抽出ワーカーを作り、Flashと名付けました。
Flashは、私のリポジトリ全体を読み取り、隠れた依存関係をマッピングし、コードを独立したマイクロサービスへと隔離するクリーンなプルリクエストを生成するよう設計されています。

開発者向けの発表を見逃した場合は、Googleがこれを可能にする新しいエージェント基盤とコンテキストウィンドウを明らかにしたキーノートの埋め込みを以下で視聴できます:

レイテンシとメモリの問題

コードベースのリファクタリングツールを作るには、2つのものが必要です。膨大なメモリと、信じられないほどの速度です。
古い構成では、コードスニペットを取得するために複雑なベクトルデータベースが必要でした。このアプローチはリファクタリングでは常に失敗します。AIは一度に3つのファイルしか見られないのに、課金モジュールをどう再構成すればいいか判断できないからです。変数の変更が、10階層先にネストされたファイルにどう影響するのかを理解するには、プロジェクト全体のコンテキストが必要です。
Googleは、Gemini 3.5 Flashが、他の最先端モデルよりも大幅に高速でありながら、100万トークンのコンテキストウィンドウで動作することを明らかにしました。このプロジェクトにとって最も重要なのは、コーディングのベンチマークでより重いモデルを上回ったことです。つまり、タイムアウトにぶつかったり、個人のクラウド予算を削りすぎたりすることなく、エージェントにリポジトリ全体を一度に投入できるようになりました。

手順1:アーキテクトの初期化

まず、新しいInterations APIを使いました。このAPIはステートフルなワークフローをネイティブに扱うため、手作業で会話ループを書く必要がありません。私は、エージェントに新しいthinking_levelパラメータを設定しました。これは、実際のコードを書き始める前に、モデルがアーキテクチャを計画するための追加の計算リソース(compute cycle)を費やすことを強制します。

import google.genai as genai

client = genai.Client(api_key="YOUR_API_KEY")

# 高い推論能力を持つエージェントを初期化する
flash_agent = client.agents.create(
    model="gemini-3.5-flash",
    name="MonolithExtractor",
    instructions=(
        "あなたはプリンシパルソフトウェアアーキテクトです。目標は "
        "大規模なモノリシックなコードベースを分析し、ドメイン境界を特定し、 "
        "密結合したモジュールを分離したマイクロサービスへと抽出することです。 "
        "既存のビジネスロジックの保持を常に最優先にしてください。"),
    thinking_level="high"
)
print("Flashはオンラインで、コードを読み取る準備ができています。")

手順2:依存関係ツリーのマッピング

エージェントには、プロジェクトの物理的な配置を理解する方法が必要です。私は、エージェントのためのツールとして機能する標準的なPython関数を作成しました。このツールはディレクトリをスキャンし、さまざまなファイルがどのように互いをimportしているかをマップ化します。
このツールをモデルに直接渡すことで、Flashは、どこをリファクタリングするかを決める前に、モノリス全体の信頼できる頭の中の地図(メンタルマップ)を構築できます。

import os

def generate_dependency_map(directory_path: str) -> dict:
    """リポジトリをスキャンし、ファイルのimportと依存関係のマップを返します。"""
    dependency_map = {}

    for root, dirs, files in os.walk(directory_path):
        for file in files:
            if file.endswith(".py") or file.endswith(".ts"):
                file_path = os.path.join(root, file)
                # 実際のアプリでは、ここでASTを解析してimportを見つけます
                dependency_map[file_path] = f" {file} の解析済み依存関係"

返却形式: {"translated": "翻訳されたHTML"}return {"status": "success", "dependencies": dependency_map}

# ツールをGeminiエージェントにバインドする
flash_agent.add_tool(generate_dependency_map)

Step 3: Feeding the Beast

エージェントがファイル構造のナビゲーション方法を理解したら、実際のロジックを処理する必要があります。Gemini 3.5 Flashの大規模なコンテキストウィンドウのおかげで、壊れやすい分割(chunking)スクリプトを書く必要はありませんでした。対象ディレクトリのパスを渡して、エージェントにファイルをネイティブに読み取らせるだけで済みました。
まず依存関係ツールを使い、その後にコードを読み込んで、請求(billing)モジュールをどのようにほどく(アンタングルする)べきかを突き止めます。

# 私のレガシーなバックエンドリポジトリへのパス
monolith_path = "/var/lib/legacy_backend_repo"

# エージェントはトークンウィンドウを使ってディレクトリを処理する
response = flash_agent.chat(
    message=(
        f" {monolith_path} にあるリポジトリを分析してください。 "
        "ユーザープロファイルシステムから請求モジュールを分離する。 "
        "請求用の別個のマイクロサービス構成を生成する。"
    )
)

print("リファクタリング計画:")
print(response.text)

Step 4: Automating the Pull Requests

密結合になっているコードを見つけるのは、戦いの半分にすぎません。本当に役立つものにするには、Flashが新しいマイクロサービスを書き、レビューに提出する必要があります。
GitHub連携用のツールを追加しました。エージェントがリファクタリング計画を完成させ、デカップルされたコードを書き終えたら、それらのファイルを新しいブランチに自動でプッシュし、私にレビュー依頼を出します。

def create_pull_request(branch_name: str, code_changes: dict, pr_notes: str) -> str:
    """抽出したマイクロサービスのコードをブランチにプッシュし、GitHubのPRを開きます。"""
    print(f"新しいブランチを作成中: {branch_name}")

    for filepath, content in code_changes.items():
        print(f"更新されたロジックを書き込み中: {filepath}...")

    print(f"PRの説明を下書き中: {pr_notes}")

    return f"ブランチ {branch_name} 上でのプルリクエストを正常に作成しました。"

# コードをコミットするためのFlashの権限を付与する
flash_agent.add_tool(create_pull_request)

Step 5: Taking it to Production

ローカルのスクリプトを実行するのは、概念実証(proof of concept)としては素晴らしいです。しかし、リポジトリ全体をほどく(アンタングルする)作業は継続的なプロセスです。
Googleは、この種のエージェント型ワークロードのためにAntigravity 2.0をオーケストレーションプラットフォームとして投入しました。自分のサーバーやcronジョブを管理する代わりに、ローカルのエージェントをAntigravityのワーカーで包み込みました。これでFlashはクラウド上で動きます。GitHubのissueにラベルextract_serviceを付けるたびに、バックグラウンドで自動的に実行されます。

from google.antigravity import Orchestrator, AgentWorker

def deploy_flash_worker():
    # Antigravityのオーケストレーション環境を初期化する
    orchestrator = Orchestrator(project_name="MonolithToMicro")

    # GitHubのイベントをトリガーにして、エージェントをクラウドワーカーに割り当てる
    worker = AgentWorker(
        agent=flash_agent,
        github_repo="my-username/core-monolith",
        trigger="on_issue_labeled:extract_service"
    )

    orchestrator.add_worker(worker)
    orchestrator.deploy()

deploy_flash_worker()

返却形式: {"translated": "翻訳されたHTML"}

結果

Flashが初めてプルリクエストを開いたとき、私はただ信じられないという表情でモニターを見つめていました。エージェントはStripe APIのWebhookを、私のユーザー認証ロジックから見事に切り離しました。新しいディレクトリを作成し、内部のインポートパスを更新し、そして新しいサービス用のきれいなセットアップファイルを書き上げたのです。
そのままでは完璧というわけではありませんでした。コードレビューの間に、いくつかの環境変数をまだ調整する必要がありました。とはいえ、面倒な手作業でのトレースを3週間分、約45秒で完了してくれました。
Gemini 3.5 Flashのスピードとコンテキストの大きさを活用したことで、大規模な技術的負債の問題を自動化されたバックグラウンド処理に変えられました。ソロ開発者にとって、時間は私にとって最も貴重な資産です。Flashのおかげでようやく、自分のコードベースを恐れることをやめて、新しい機能の開発に集中できるようになりました。