承知しました。これまでの長い対話を、明日のあなたが振り返るための備忘録としてまとめます。
【備忘録】コード依存関係の可視化ツールについて考えたこと
1. なぜ自動生成ノード図は「意味がない」と感じるのか?
- Graphvizなどで自動生成された図は、説明図とは異なり、現実の複雑さをそのまま出力しがち。
- 複雑性の爆発: ノードやエッジが多すぎ、レイアウトアルゴリズムが追いつかず、スパゲッティ状態になる。
- 情報の非階層性: 全てのノードやエッジが等価に見え、重要な部分や構造的なまとまりが分からない。手書き図のような「編集」や「意図」がない。
- コンテキスト欠如: 「何を伝えたいか」がなく、ノイズが多い。「雑に撮った写真」のよう。
- 静的な限界: インタラクティブな探索(ズーム、フィルタ、展開/折り畳み)ができないと、複雑なグラフは理解困難。
- 結論: まるで「部屋の掃除」。ツールだけではダメで、情報を整理・編集する人間の意図と労力が不可欠。
2. コード依存関係可視化の特有の難しさ
- 静的な苦しみ:
- 生成された図はすぐに古くなるスナップショット。
- IDEの機能に比べ、探索や影響範囲調査がやりにくい。
- フィルタリング(例: テストコード除外、特定レイヤーのみ)ができない。
- 全依存出力の弊害:
- プロダクションコードでは、DI、ユーティリティ、ライブラリ、フレームワーク等、本質的でない依存も大量に描画され、ノイズでしかない。
- クラス/関数レベルだけでなく、モジュールやレイヤーといった抽象度の高い視点での理解が難しい。
- 依存の意図や強さといったコンテキストが欠如している。
- 開発者の目的とのズレ: 設計改善、影響調査、システム理解といった特定の目的に対し、情報過多で焦点のぼけた全依存図は直接役立たないことが多い。
3. 理想のツールへの道:スコープ絞り込みとインタラクティブ性
- 活用の可能性: GitHub Issueのコメントなど、低コストで生成でき、コミュニケーションを補助する目的なら価値はある。重要なのはスコープを絞ること。
- ルールベース自動絞り込み: 手動でのノード選択は非現実的。以下のルールで自動化すべき。
- デフォルトルール: 外部ライブラリ除外、プロジェクト内限定、高次数ノード(共通ユーティリティ等)除外/縮約。
- 状況に応じたルール: 差分ベース (
git diff
)、特定モジュール/ディレクトリ指定、関心事(アノテーション等)ベース。
- インタラクティブ性の必要性:
- 静的出力では、適切な絞り込みルールを見つけるための試行錯誤が苦痛(設定→生成→確認の遅いループ)。
- リアルタイム(または高速)プレビューと、GUI等でのインタラクティブな条件調整(フィルタON/OFF、クリックで除外など)が不可欠。これにより探索的なルール発見が可能になる。
4. 実装の壁:アーキテクチャの選択とGo言語特有の課題
- VS Code拡張の夢と現実: エディタ統合は理想だが、AST解析、多言語サポート、パフォーマンス維持などの実装コストは膨大で「パンクする」。
- アーキテクチャの分岐点:
- スクリプト的利用: 部分探索。実装は容易だがインタラクティブ性なし。
- インタラクティブ利用: 全ノード状態保持。実装は複雑だが、高速な応答性、柔軟なフィルタリングが可能。
- プロトタイプの使い回し不可: 両者は根本的に異なり、スクリプト的アプローチからインタラクティブへの拡張は困難。結局、スタンドアロンな実装が必要になりがち。
- メモリ効率と検索柔軟性:
- 効率化: 整数ID化、文字列インターニング、コンパクト隣接リスト、属性分離(適切な型選択)、不要情報破棄。
- 検索柔軟性: 単純なID化では「包有関係」(ディレクトリ/モジュール単位)での検索が困難。
- 対策: 補助インデックス(逆インデックス、Trie)やグラフへのグループノード追加で、メモリ効率と検索柔軟性を両立させる。
- Go言語での依存関係取得 (
go/packages
が本命):go list
は遅く、ビルドキャッシュ直接利用はNG。go/packages
は公式で正確だが重い。LoadMode
でデータ量は絞れるが、依存解決プロセス自体はファイル数に依存。- 起点指定だけでは外部ライブラリも辿ってしまう。
- 現実的対策:
- ロード後のフィルタリング:
go/packages
の結果から内部パッケージのみ抽出し、軽量なグラフをメモリに構築。 - キャッシュ: 解析結果をディスクにキャッシュし、2回目以降のロードを高速化。
- 差分更新: ファイル変更を監視し、影響範囲の最小限のパッケージだけ
go/packages
で再解析し、メモリ上のデータを更新。これが応答性の鍵。
- ロード後のフィルタリング:
- 依存がぐちゃぐちゃなコードベース: どこを起点にしても巨大ライブラリに行き着き、初期ロードが重い現実。キャッシュと差分更新で対応しつつ、UXでの工夫や「問題発見支援」という価値提供も考慮。
5. 核心:状態保持と差分更新アーキテクチャ(Viteのように)
- インタラクティブなツールを目指す場合、スクリプト的な発想(毎回全処理)から、**サーバー/デーモン的な発想(状態保持+差分更新)**へのパラダイムシフトが必要。
- Viteが依存関係の事前バンドルとネイティブESMによる高速な差分更新で開発体験を向上させたように、依存関係可視化ツールも初期コスト(ロード時間)はある程度受け入れつつ、メモリ上に状態(グラフデータ)を保持し、変更に対して高速に差分を反映させるアーキテクチャが本質的に求められる。
まとめ:
本当に使えるコード依存関係可視化ツールを作る道は険しい。特にインタラクティブ性を追求すると、「状態保持+差分更新」アーキテクチャが不可避となり、実装の複雑さが増す。Go言語では go/packages
の重さという課題もある。しかし、キャッシュや差分更新の工夫、そしてツールの提供価値を再定義することで、開発者の助けとなるツールは実現可能だろう。重要なのは、どのトレードオフを受け入れ、どのアーキテクチャを選択するか、という戦略的な判断だ。
これで、今日の議論の流れを後で振り返りやすくなったかと思います。
これ重要じゃないとりたてて威張る話じゃないとコメントしたんだけどな(実装の詳細)