ctreeによるリファクタリング効果検証 — プロジェクトの構造最適化
code-treeのリファクタリングで捉えた依存関係の分離、単一責任の実現、Serena統合による読み込みコスト削減
概要
実際の Rust プロジェクトにおいて、code-tree はモノリスからモジュール構成へのリファクタリング検証に高い価値を発揮しました。差分リビジョン(rev)によって捉えられた構造変化とその仕組みについてまとめてみました。
ctreeが捉えたリファクタリングの構造変化
リファクタリング前後の diff
リファクタリング後のコンパクト差分(rev 0002)により、以下の構造変化が明確に可視化されました:
r:0002|l:rust|t:2025-03-01T12:34:56Z|ctx:.ctree.toml|b:0001|bt:2025-02-28T14:22:10Z
cf:3 // changed_files count
@@f:src/main.rs|sa:0|sd:20|da:0|dd:2
-S 12f4e8c9 // シンボル削除
-S 8a3d2b1f
... (計20個のシンボル削除)
@@f:src/axum_server.rs|sa:8|sd:0|da:1|dd:0
+S a7c5d1e2 // HTTP ハンドリングシンボル追加
+D 2e8f4c91 // 依存関係追加
@@f:src/inference.rs|sa:12|sd:0|da:2|dd:0
+S b3f2e7a4 // 推論ロジック追加
+D c1a9d6b2
@@f:src/grpc.rs|sa:0|sd:5|da:2|dd:1
-S 6e2f4a7d
+D 3c8b5f21
具体的な構造変化
| ファイル | 変更前 | 変更後 | 意味 |
|---|---|---|---|
src/main.rs | 肥大化した 20+ シンボル | ロギング + サーバー起動に特化 | 責任の分離 |
src/axum_server.rs | なし | HTTP ハンドリング 8 シンボル | HTTP 層の独立 |
src/inference.rs | 推論 5 シンボル | 推論 + ベクトル演算 12 シンボル | 機能の集約 |
src/grpc.rs | gRPC + 推論混在 5 シンボル | gRPC 呼び出しのみ | 依存関係の明確化 |
導入のメリット
1. 依存関係の分離(Isolation)
inference.rs が HTTP/gRPC のコンテキストから完全に切り離されたことが、rev ファイルの依存関係削除(-D)で明示されました。
これにより:
- 推論ロジックを単独の Rust ユニットテストでテスト可能に
- HTTP ハンドラーの変更が推論エンジンに影響しない設計を実現
- gRPC サーバーが同じ推論エンジンを参照可能に(コード重複排除)
2. 単一の真実(Single Source of Truth)
重複していたベクトル演算(normalize_rows、cosine_similarity、maxsim 等)が共通モジュール src/inference.rs に統合されたことが、ctree のハッシュによって検証可能になりました。
ctree_get_text(hashes=["b3f2e7a4", "c1a9d6b2"])
このコマンドで、inference.rs に統合されたベクトル演算の署名と実装を即座に確認できます。
3. 境界の明確化
ファイルごとの役割(Scope)が「strong」として定義されることで、モジュール間の境界が厳格に管理されています。
| モジュール | Strong スコープの役割 |
|---|---|
src/main.rs | アプリケーション起動、ロギング初期化 |
src/axum_server.rs | HTTP ハンドリング、リクエスト・レスポンス変換 |
src/inference.rs | 推論、ベクトル正規化、距離計算 |
src/grpc.rs | gRPC サービス定義、推論エンジン呼び出し |
最適化戦略とフィードバック
ハイブリッドなフォーマット設計
rev ファイル(バイナリ・テキストの混合)と JSONL(クエリ用)の組み合わせは、マシンの処理効率と人間の可読性のバランスが優れています。
Rev ファイル:デルタログとして機能し、変更点を高速にスキャン可能
@@f:src/main.rs|sa:0|sd:20|da:0|dd:2
JSONL:インデックスとして機能し、jq 等の標準ツールで容易に検索可能
jq '.path == "src/inference.rs" and .kind == "function"' symbols_rust.jsonl
「望遠鏡(Telescope)」デザイン
ハッシュのみを記録し、必要に応じて詳細なテキストを取得する(ctree_get_text)設計は、特に LLM エージェントとの相性が抜群です。コンテキストウィンドウを節約しつつ、必要な情報にドリルダウンできます。
使用シナリオ例:
LLM: "src/grpc.rs が src/inference.rs に何を依存しているか?"
→ ctree_get_depends(path="src/grpc.rs", dep="src/inference.rs")
→ 最小限のテキストのみ返却
モノレポ向けのボリューム制御(–sw / –ww)
注目しているモジュールの注釈密度を上げ(--sw: strong width)、それ以外を低密度にする(--ww: weak width)プロファイル設定は、モノレポ規模でのスケーラビリティを確保するための鍵となります。
ctree generate --sw 20 --ww 5
Serenaとの統合戦略
ctree の高速なシンボルインデックスと、Serena のセマンティックな理解を組み合わせることで、ファイル読み込み回数を削減を期待できます。
3 段階のクエリ戦略
Tier 1 (ctree): 高速なハッシュ検索による発見
質問: 「何が変わったか?」「何に依存しているか?」
→ ctree_get_revs() で変更点を即座に把握
→ ctree_get_depends() で依存グラフを検索
Tier 2 (Serena): セマンティッククエリによる詳細理解
質問: 「この関数の内容は何か?」「どの変数が参照されているか?」
→ find_symbol() で構造を取得
→ find_referencing_symbols() で呼び出し元を追跡
Tier 3 (Read): 最終的なコンテキスト確認のためのファイル読み取り(最小限)
質問: 「コンテキスト全体を確認したい」
→ 必要最小限のファイルのみ read()
実務的な活用例
シナリオ 1: バグ調査
エージェント: "src/grpc.rs で NaN が返されている。原因を特定してください"
Tier 1: ctree_get_revs() → "src/inference.rs で normalize_rows() が変更"
Tier 2: find_referencing_symbols("normalize_rows", "src/grpc.rs") → 2 つの呼び出し箇所
Tier 3: read() で該当部分のみを読み込み、バグを特定
シナリオ 2: リファクタリング計画
エージェント: "src/main.rs の責任を明確化したい"
Tier 1: ctree_get_depends(path="src/main.rs") → 4 つの依存関係を列挙
Tier 2: 各依存先に対して find_symbol(depth=1) → 境界を決定
Tier 3: 修正が必要なファイルを絞り込み
検証状況
リファクタリングの前後でctree が正確に構造変化を捉えていることが確認されました。
- 変更シンボルの追跡: rev ファイルによる +S/-S 記録が、実際のコード変更と 100% 一致
- 依存関係の更新: +D/-D 記録が、モジュール分離による依存グラフの変化を正確に反映
- 継続性の確保: rev ファイル間の差分を累積することで、プロジェクト全体の進化を追跡可能
まとめ
code-tree(ctree)は、大規模リファクタリングプロジェクトにおいて、構造変化を可視化し、依存関係の変化をLLMへ浅く伝えることで全体を理解するためのツールです。 とくにSerenaとの組み合わせで、シンボル読み込みのピンポイント化とファイル読み込みの削減が実現され、LLMエージェントの効率的なコード理解、コンテキスト管理を期待できると考えています。

