大規模モノレポを制する:HHVM型チェッカーの「Incremental Check」を極めるアーキテクチャ設計
皆さん、こんにちは。Hackの深淵へようこそ。
大規模なモノレポで開発していると、コードを書くたびに型チェック(`hh_client`)が終わりを告げず、コーヒーを淹れに行く時間すらなくなってしまう……そんな経験はありませんか?
今日は、HHVMの心臓部である型チェッカー(HHClient/HackServer)がいかにしてコードを読み解いているのか、その「脳内構造」を紐解きながら、大規模環境でも爆速で型チェックを終わらせるためのアーキテクチャ戦略を伝授します。
—
1. 型チェッカーの「脳内」を知る:Incremental Checkの真実
HHVMの型チェッカーは、ただファイルを上から順に読んでいるわけではありません。「依存グラフ(Dependency Graph)」をメモリ上に構築し、変更された部分とその影響範囲だけを再計算する「Incremental Check(差分チェック)」という強力な武器を持っています。
しかし、このグラフが巨大になり、依存関係がスパゲッティ化すると、チェッカーは「どこまで影響が及ぶか」を計算するだけで力尽きてしまいます。
なぜ「型定義の肥大化」が遅延を招くのか?
型定義ファイルを巨大な単一ファイルにまとめると、「たった1行の変更が、そのファイルをインポートしている数千のファイル全てを再検証対象にする」というトリガーを引いてしまうからです。
—
2. 戦略的設計:型定義を「分離」して解析効率を最大化する
型チェック時間を短縮する黄金律は、「依存の境界線を物理的に分離すること」です。
悪い例:全てが繋がったモノリス
// types.hack (すべてがここに集約されている)
type UserData = shape(‘id’ => int, ‘name’ => string, …);
type OrderData = shape(‘id’ => int, ‘items’ => vec
// これを変更すると、全プロジェクトが再チェック対象になる!
良い例:ドメインごとの型分離
型定義を小さなファイル(またはモジュール)に分割します。HHVMは「変更されたファイル」が属するモジュールのみを優先的に解析するため、グラフの再構築コストが劇的に下がります。
// UserTypes.hack (ユーザー周りの型だけ)
namespace App\Types\User;
type UserData = shape(‘id’ => int, ‘name’ => string);
// OrderTypes.hack (注文周りの型だけ)
namespace App\Types\Order;
type OrderData = shape(‘id’ => int, ‘total’ => float);
—
3. 【上級編】HHVMの型チェッカーを最適化する3つのテクニック
ここからは、現場で即効性のある具体的な最適化術です。
① `newtype` を使い、型の「壁」を作る
`type` は単なるエイリアスですが、`newtype` を使うと型チェッカーに対して「この型は中身を深追いするな」というヒントを与えることができます。
// 外部から中身を隠蔽することで、依存関係を限定できる
newtype UserId = int;
function getUser(UserId $id): void {
// 中身がintだと分かっていても、型システムはUserIdとして扱う
}
② `HH\Lib` などの標準ライブラリを最大限活用する
自前で複雑な `shape` を定義しすぎると、チェッカーは構造の比較に膨大なCPUを使います。`vec`, `dict`, `keyset` といったプリミティブなコレクション型を多用するほうが、チェッカーの推論エンジンは高速に動作します。
③ `hhconfig` で解析対象を絞る
プロジェクトルートの `.hhconfig` で、不要なディレクトリを `ignored_paths` に入れるのを忘れていませんか?
.hhconfig の例
解析不要な自動生成コードやテストデータを除外するだけで、
型チェッカーの負荷は驚くほど軽くなります。
ignored_paths =
./vendor/.
./generated/.
—
4. 陥りやすい罠:型エラーの「負の連鎖」
初心者がよくやってしまうのが、「型エラーを無視してコードを書き進める」ことです。
Hackの型チェッカーは、エラーを検知すると「その先」の推論を放棄(エラーリカバリ)することがあります。この放棄が繰り返されると、本来は正しいコードまで「型不明」として扱われ、解析キャッシュが汚染されます。
- アドバイス: `hh_client` が出したエラーは、たとえ些細なものでも即座に修正してください。型システムと対話し、常に「Clean State」を維持することが、最速の型チェックへの近道です。
—
最後に:Hackという言語の重みを知るということ
Hackの厳格な型システムは、あなたの敵ではありません。むしろ、大規模なシステムにおいて「何がどこに依存しているか」を数学的に証明してくれる最強のパートナーです。
型チェックが遅いと感じたときは、言語のせいにするのではなく、自分の書いたコードが「依存の網」を無駄に広げていないか、一度立ち止まって考えてみてください。
「型定義を小さく保ち、依存の境界を明確にする」。これだけで、あなたの開発体験(DX)は劇的に向上します。さあ、この美しいアーキテクチャを武器に、今日も最高に堅牢なコードを書いていきましょう!
ここをクリアすれば、あなたはもう立派なHackのアーキテクトです。応援していますよ!