世界を動かす技術を、日本語で。

コードベースを学ぶ新たな方法:ビジュアライザーを作成する

概要

  • 他人のコードを読むことの多さ に初期キャリアで衝撃を受けた体験談
  • 巨大なコードベース を理解するための実践的なアプローチの紹介
  • Next.jsのturbopack(Rustバンドラー) を題材とした学習プロセスの追体験
  • バグ調査・可視化ツール作成 を通じた理解の深化
  • ツール構築の有効性 と現代ソフトウェア開発環境の課題提起

初めての巨大コードベースとの遭遇

  • 他人が書いた膨大なコード を読む必要性への戸惑いと恐怖
  • 全体を理解しなくても貢献できる という事実の発見
  • 実体験を通じた学び方 の提示意図

コードベースの学び方:再構成版

  • 経験則による近道 は他者には伝わりにくい現実
  • 知識ゼロから理解を深め、正しい質問をする プロセスの再現
  • Next.jsのturbopack(Rustバンドラー) に焦点を絞った探索
  • 単なるバグ修正や機能追加とは異なる 「全体像把握」のためのアプローチ

コードベースの構造把握の第一歩

  • main関数から始めるのは非効率、特に巨大なプロジェクトでは入口が複数
  • パッケージ・クレート・turbopack の構成をざっと確認
  • turbopack配下に54個のcrate が存在し、規模の大きさを実感
  • バグレポートを出発点 にすることで、学習の具体的な糸口を得る

バグレポートを活用した学習

  • 再現手順だけのバグ報告 が学習には最適
  • バグの最小再現ケース を自作し、問題点(未使用enumがバンドルに残る)を特定
  • バグ修正が目的でなく、関連コードの理解がゴール であることを強調

開発環境構築の現実

  • プロジェクトを動かすだけでも一苦労 な現実
  • turbopackのRustコードの変更反映 に苦戦
    • symlink未対応、tarball経由でテストプロジェクトへ導入
  • 依存関係やtarball内容の調査 でnativeコードが含まれていない問題を発見
  • 正規表現のミスによるファイル除外問題 を特定し、修正(regexやソート活用)

ツリーシェイキング(tree shaking)調査

  • 「tree shaking」が本当に問題か? 用語の使い方にも注意
  • turbopackTreeShaking設定 の有無・デフォルト値を調査
  • コード探索による理解が困難な場合、別のアプローチへ切り替え

コードフローの追跡と可視化

  • swcによるパース・変換処理 の流れを調査
  • Turbopackの非同期・複雑なRustシステム ゆえ、ログ出力だけでは不十分
  • 独自可視化ツールの作成 で、ファイルや値の流れをWebSocket経由で可視化
  • Scope HoistingによるPUREアノテーションの消失 とバグの本質に迫る

バグの根本原因と修正

  • swcのASTとコメント管理方式 (byte posによるハッシュマップ管理)
  • turbopackでのモジュール跨ぎのbyte posエンコード問題 を特定
  • PURE値のエンコードミス が原因、最小限の修正でバグ解消
  • 他のセンチネル値(PLACEHOLDER, SYNTHESIZED)やdecode処理の考慮も必要

ValueCell(Vc)と計算グラフの理解

  • Vc(ValueCell)=スプレッドシートのセルのようなインクリメンタル計算単位
  • turbo engineの高レベル概要や類似技術(salsa, reteネットワーク等)
  • 小さな範囲からグラフを可視化し、依存関係・再計算の最小化を体感

可視化による学習・ツール構築のすすめ

  • backendで実行制御・ツール挿入が容易な設計
  • WebSocketによる双方向通信でタスクの実行状況を可視化
  • 可視化により疑問点を発見し、深い理解につなげる
  • ツール構築を通じた学習法の有効性 の実感

ソフトウェア開発環境への課題提起

  • 現代のソフトウェアは「ライブで内側を観察する」手段が乏しい
  • UI環境の制約やパフォーマンスへの懸念
  • 今後の発展への期待

このプロセスは 一朝一夕で身につくものではなく、地道な試行錯誤とツール構築の繰り返し によるものであることを強調したい。 可視化やツール作成を通じて「ブラックボックス」を「理解可能なもの」に変える ことが、巨大なコードベース攻略の鍵となる。

Hackerたちの意見

ビジュアライザーの構築自体は、結果やあなたの結論に比べるとあまり興味がなかったな。ソフトウェアの構造や論理を取り入れる新しい方法を見つけるのはすごく役立つと思うし、あなたの解決策もいいね。試してみる方法はあるの?

リバースエンジニアリングでは、実行フローを見るためにグラフビューを使うことが多いよね。他でも使われてるのを見ると嬉しいな。

それを自動化してるの?もしそうなら、どんなツールを使ってるの?

これは面白いアプローチだね。ある意味、私がやってることと似てると思う。キャリアの大半を契約で過ごしてきたから、いくつかのコードベースにすぐに慣れなきゃいけなかったんだ。どうやってこれをやるか選べるときは、最近閉じたイシューを見つけて、それに対するユニットテストを書こうとするよ。そうすれば、テストがどこにあるか(存在する場合ね)や、何かをいじるときにどれだけの安全ネットがあるかがわかるから。テストを追加して実行する方法がわかれば(これは記事で言ってたコードベースのセットアップ問題に対処するのにすごく良い方法だよ。多くのオンボーディングドキュメントは、必要な配管なしでコードベースを動かすところまでしか行かないから)、コードを完全に理解しなくても大丈夫な気がする。やりたいことを証明するためにいくつかのテストを投げ込んで、テストやCI、フックが私を悪いことから守ってくれることを願う感じ。完璧ではないし、プロジェクトの構築やメンテナンスの良さによって変わるけど、簡単に壊せるなら、みんな壊れることに慣れてるだろうし、そこから初めての意味のある貢献への道が開けるんだ。壊れにくくすることが目標だね。

ここに以前投稿された小さなツールキット、覚えてる?新しいコードベースを理解するためにそのクリエイターたちが特別に作ったやつ。

https://gtoolkit.com/ または https://moosetechnology.org/

GitHub Nextが思い浮かぶね。 https://githubnext.com/projects/repo-visualization/

あんまり役に立たないよね?

AIに関してはかなり懐疑的で控えめなんだけど、特に次世代のエンジニアへの影響についてはね。でも、AIを使ってコードベースを学ぶのは人生が変わるほどだよ。最初は足元を探るための杖みたいなもので、慣れてきたらその杖を捨てる感じ。地図を使って道を覚えるみたいなもんだね。

あなたのビジュアライザー、めっちゃいいね!タスクをキューに入れて実行するのが、ランタイムアタッチ中にコードだけを操作するんじゃなくて、すごくいいと思う。そんなの見たことなかった。最初にUnrealのブループリントを使った後、自分のコード用にノードグラフユーティリティを作ったんだ。二つが同じコードベースの違うビューだって気づいたとき、もう夢中になっちゃった。ノードグラフの方が理解しやすいし、コードをプレーンテキスト(IDEや言語サーバーを使って)で書くのも楽だしね。もっと一般的なユーティリティがあれば、js/ts以外の言語でも使えるのにって思うよ。とにかく、素晴らしい仕事だね!

これはDoxygenで得られるものに似てるのかな? https://en.wikipedia.org/wiki/Doxygen#/media/File:Doxygen-1....

スレッドの契約者のユニットテストアプローチは素晴らしいね。「最近閉じた問題を見つけて、それに対するユニットテストを書いてみる」ってやつ。これでテストインフラ、モジュールの境界、実際の動作を理解することが強制されるんだよね。コード構造だけじゃなくて。もう一つ、私にとって効果的だったテクニックを追加したいな。HTTPエンドポイントからデータベースまでのリクエストをトレースして、戻ってくるってやつ。FastAPIアプリの場合、ルートハンドラーから始めて、依存性注入のチェーンを辿って、ORMやクエリレイヤーがどう動くかを見て、レスポンスのシリアライズを理解するってこと。実際のパスを追うことで、スタックのすべてのレイヤーに触れることができるんだ。一度に全コードベースを理解しようとするんじゃなくてね。ビジュアライザーは「全体像」を把握するにはいいけど、コードがどうしてそう動くのかを理解するのにはあんまり役立たないよ。理由はgitの履歴や閉じた問題にあって、依存関係グラフにはないんだ。

大抵の人のコードの問題は、余計な複雑さが満載で、めっちゃ手間がかかることだよね。少なくとも「トップ」企業の「トップ」エンジニアが作ったプロジェクトの90%は、余計な複雑さでいっぱいで、全体の動きをかなり遅くしてる。実際、1人の優秀なエンジニアでできる仕事を、20人以上のエンジニアのチームが必要になっちゃってる。現代のコード品質の指標に基づくと、ほとんどの人は自分が悪いコードを見ていることに気づかないんだ。表面的には結構良さそうに見えるひどいコードベースをたくさん見てきたよ。良いリンティング、一貫した命名、関数型プログラミング、静的型付けとかね…でも、アーキテクチャ的には衝撃的に悪い。コードを常にリファクタリングしないといけないように設計されてるし、ビジネスレイヤーが明確じゃない。ビジネスロジックがすべてのコンポーネントを横断して、いわゆる汎用的なものにも絡んでる。悪いコードだと、ビジネス要件の変更には深いリファクタリングが必要になる… で、人々は「TypeScriptを使ってるから、リファクタリングの一環として必要な20個のファイルの参照を更新するのをうっかり忘れないで済むのが嬉しい」って言うんだよね。ニュースフラッシュ:あなたのちょっとしたビジネス要件の変更が、コードがクソだから20以上のファイルを更新しなきゃならないってこと!確かにTypeScriptはこの場合助けになるけど、型安全性は心配するべきことの中で一番下の方だよ。コードがちゃんとアーキテクチャされていれば、複雑な抽象は一般的に1つか2つのファイルを超えて広がることはないんだ。「漏れた抽象」って言う理由があるんだよ。複雑な抽象が多くのファイルの境界を越えて漏れ出るなら、それは抽象であって、漏れてるってこと!