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

生産的なモノレポの要素

概要

  • Developer Productivityチームmonorepo 導入を検討する際の実務的な課題整理
  • 大手企業の事例を 鵜呑みにせず、自社に合った理由と目的の明確化が重要
  • O(change)原則 に基づいたツール設計の必要性
  • ソース管理・ビルド・テスト における現実的な対応策と課題
  • 一歩ずつ地道な改善 が成功の鍵

モノレポ導入の現実と心得

  • Google、Meta、Uber などの大規模成功事例は、自社にそのまま適用できない現実
  • 導入理由 は「一貫性」「組織的な整合性」「共通ツール化」など、自社文化・価値観に根ざしたものに限定
  • 大手の成功ブログ は最終形の話であり、現状の自社リソースや規模では同じ体験は難しい
  • モノレポ導入 は新たな課題も生み出すため、短期的には後退も覚悟
  • エンジニア間の協力コーディング規約統一 など、長期的な組織的メリットを重視

モノレポツール設計の黄金律

  • O(change)(変更範囲のみ)で完結する高速処理 の徹底
  • 従来ツールやプロセスは O(repo)(全体規模依存) が多く、モノレポ拡大でパフォーマンス問題が顕在化
  • 大手企業の独自ツール開発 も、ほとんどがこのO(repo)問題への対応策
  • 設計時は常に「O(change)」を意識 してツール選定・実装

ソース管理の現実的アプローチ

  • git は分散型設計ゆえ、巨大モノレポでは 性能劣化 (git status等)が発生
  • 現状は git/GitHub で十分運用可能、規模拡大時に問題が顕在化
  • Microsoft はgitをフォーク、 Meta はMercurialをフォーク、 Google は独自実装やPerforce利用
  • サブセットチェックアウト (git sparse checkout等)や 仮想ファイルシステム (オンデマンドDL)の導入事例
  • IDL(protobuf/thrift等)による自動生成コード の管理でリポジトリ肥大化に注意

ビルドシステムの選定と実装

  • Bazel はマルチランゲージ・モノレポに強いが、専任チームが必要なレベルの複雑さ
  • 可能な限り 単一言語 でモノレポ運用を推奨、言語標準ビルドツール(Maven/Gradle/CMake/Cargo/Go等)で粘る
  • O(repo)問題 はあるが、意外と長く運用可能
  • ターゲット決定器(determinator) の実装で、最小限のビルド対象抽出が重要
    • Rustなら guppy crate、Goなら go/packagesライブラリ 等で実現可能
    • Bazel/Buck2等の高度なリモート実行・キャッシュは超大規模向け

テスト運用の課題と解決策

  • 全テスト実行 は非現実的、 ターゲット決定器 で影響範囲のみ抽出
  • フレーク対策 として自動リトライ・隔離機能が必要
  • テスト信頼性 が低いとCI失敗率が急上昇、開発者の不満増加
  • 言語標準テストツール では要件を満たせない場合が多い
    • Rustの nextest やJavaの JUnit 等、一部対応ツールあり

継続的インテグレーション(CI)の役割

  • プルリクエスト発生時 に、影響範囲のビルド・テストを効率的に実行
  • O(change)原則 をCIパイプラインにも適用し、全体最適化を図る
  • CIシステム自体のスケールやパフォーマンスにも注意

次のセクションや論点があれば、新たなタイトルで整理して続けてください。

Hackerたちの意見

大手テック企業での経験から言うと、ビルドシステムを管理するには、そのシステム自体に取り組むチームが必要になるんだよね。基盤となるリポジトリ技術もスケールで動かなきゃいけないし、ソースファイルは必要なときにダウンロードされる仮想ファイルシステムを使ってた。この記事で触れられていないことの一つは、ほとんどの開発がデータセンターで動いている開発サーバー(大体50~100コアくらい)か、数時間ごとに良いコミットで更新される短命なコンテナみたいな「オンデマンド」マシンで行われていたってこと。IDEは開発サーバーやマシンと統合されていて、一般的に言語サーバーや他のサービスは事前にウォームアップされていたり、ChefやAnsibleで自動的にセットアップされてた。大きなモノレポをノートパソコンで動かすことはほとんどないよ(例外はモバイルアプリやMac OSアプリとか)。

そうそう、私もそのビルドチームで働いてたかも!多くのユーザーにとって、モノレポの開発環境が特にローカルかリモートかよりも再現性が重要だと思う。リモートの開発サーバーで定期的にイメージを取得する方が確かにやりやすいよね。

この記事で触れられていないことの一つは、ほとんどの開発がデータセンターで動いている開発サーバー(大体50~100コアくらい)で行われていたことだ。私も多くの小さなチームでこれをやってきたよ。エンジニアが開発中に「ローカルに考える」のをやめさせるのはかなり難しい。現代のハードウェアのコストや密度を考えると、開発チームのためにどこかにラックを見つけるのは理にかなってるよね。開発、ステージング、テスト、必要なツールを動かすためのボックスをいくつか作るのは簡単だし、成長する余地もある。インフラに近くて、本番環境に似ていると、モノレポの中のコードがすごく違って見えてくる。 > 大規模なビルドシステムを管理するには、そのシステム自体に取り組むチームが必要になる。これが多くの小さなチームがモノレポに移行するのを妨げているんだ。あなたの10~20人のチームは、GoogleやFB、MSには決してなれない。大規模なビルドシステムの問題は起きない。すべてを維持するのは、20人のチームで非常に複雑な製品がある場合に誰かのパートタイムの仕事になるかもしれないけど、それでも厳しいかも。

大手テック企業のモノレポには2種類あるんだ。一つはこの記事で説明されている「THE」モノレポで、ほぼ全体のコードベースを含んでいて、カスタムVCSやカスタムCI、そして200人のエンジニアチームが支えているもの。UberやMeta、Googleも今はこういうやり方だよね。ここに到達するには何年も苦労が必要。もう一つの「モノレポ」は、個々のチームがプロジェクトを緩く組織化してモノレポに集め始める「マルチレポモノレポ」。フロントエンドの人たちはTurborepoを使いたがって、Bazelが大嫌い。Javaの人たちはBazelを使いたがっていて、他に何があるか知らない。Pythonの人たちはPoetryを諦めた後に好きなようにやってる... 最終的にはこれらが大きなモノレポにまとまるかもしれない。どちらのアプローチも数百万ドルと数百万時間の開発者の時間と努力がかかる。ビジネスリーダーには技術VPが巧みにその努力を正当化して、結果的に開発者たちはその苦労を忘れようとしている。

ほとんどのモノレポは、GoogleやUber、他のテックジャイアンツのリポジトリと同じサイズにはならないってことは覚えておく価値があるよ。毎日新しいサービスを導入する会社もあれば、サービスの数が安定している会社もある。もし会社が100のサービスを持っているなら、VCSのスケール問題は起きないし、LSPはノートパソコンのメモリに全コードベースのタグを収められるし、CIで全てのテストを実行するのもほぼ問題ない。要するに、すべての会社がGoogleの規模になるわけじゃないし、なるべきでもない。

大きなモノレポの会社で元ICだったけど、ポリレポよりモノレポの方が好きだった。これは「THE」モノレポで、会社のサービスグラフやコールグラフ、オーナーシップグラフなどがすごく明確に理解できた。クリスタルクリアで、鮮やかに。ポリレポは部族的な知識みたいなもので、どこに何があるか分からないし、探すこともできない。各チームがそれぞれのやり方でやってるから、新しいコードを引き継ぐのは呪いみたい。コード考古学は、隠された難解な書物の図書館での根本原因分析の冒険みたい。ポリレポはDiscordやSlackのチャンネルに閉じ込められたメッセージや知識みたいで、保持ポリシーが悪い。すべてが暗い隅で萎縮していく。モノレポが数百万のコストなら、ポリレポも別の形で同じくらいかかると思う。モノレポは巨大なメガファウナの大陸。大きなリソース、単一栄養。ポリレポは千の種が生きたり死んだりしていて、繁栄するものもあれば、知られることのないものもあり、大半は完全に暗闇の中。

うちの会社は言語スタックごとにモノレポに移行してるんだ。まあ、悪くない妥協だと思う。

今の職場では、バックエンドが約11個のGitリポに分かれてて、1つの機能が4〜5個のマージリクエストに分かれちゃってて、すごく面倒なんだ。これからモノレポを導入して、全部まとめることを検討する予定なんだけど、リポをまとめられない場合、モノレポ以外の選択肢は何になるんだろう?

モノレポとマルチレポの議論であまり見かけないことの一つは、逆コンウェイの法則が存在するってこと。どちらかを選ぶことで、組織の構造や問題解決の仕方に影響を与えるんだ。例えば、モノレポは共通のインフラチームの間で個々のヒーロー的な行動を促す傾向がある。多くの変更が同時に入るから、共通エリアに触れるものは潜在的な破損が多くなるので、たった一つの「機能」を提供するのにも膨大な努力が必要になる。マルチレポで同じことをするには、数週間にわたっていくつかのPRを調整したり、内部の政治が絡むこともあるけど、それは専用のビルドチームにいない異なる開発者の間で分担されることもある。

あなたの前提は、組織が最初からどちらかに進むことを望んでいなくて、技術的な選択によって後から押し出されるということ?たいていの場合、哲学的な決定(より共有された部分か、より良い分離か)は、リポジトリの扱いを決める前にされていると思う。もし組織が途中で方向を変えたとしても、コードの扱いは根本的にリポジトリの構造を切り替えなくても適応できる。多くの組織はマルチレポだけど、エンジニアはほとんどすべてのコードにアクセスできるし、モノレポチームも自分たちのやっていることを強く隔離することができる。異なるCIルールやデプロイ管理を持つこともできるんだ。

ポリレポの設定で起こることについて、楽観的な見方だね。一般的な代替案(おそらくこっちの方が多いと思う)は、共通エリアに変更が加えられるけど、下流のリポジトリには反映されないってこと。そうなると、みんな異なるバージョンの共通リポに固定されちゃって、数年も古くなると更新が大変になるんだよね。

たくさんの変更が一度に入るから、共通エリアに触れるものは壊れる可能性がすごく高くなる。そのため、単一の「フィーチャー」を提供するための労力が急増する。モノレポの特定の変更が非常に中心的に埋め込まれていて、原子的に行うためには信じられないほどの労力が必要な場合(モノレポを持つ利点)、それでも複数の段階的な変更に分けることができる(「数週間にわたっていくつかのPRを調整する必要があり、内部の政治も絡むけど、それは専用のビルドチームにいない異なる開発者の間で分けられることもある」)。だから、モノレポではマルチリポで説明したのと同じ利点を享受できるし、モノレポのおかげで段階的な変更の展開をより良く把握できるんだ。

Hacker Newsで議論の続きを見る