モノレポ(Monorepo)戦略とポリレポの比較
1. 概要
定義: モノレポ(Monorepo)とは、複数のプロジェクト・サービス・ライブラリのソースコードを一つのバージョン管理リポジトリに統合して管理する構成管理戦略である。単一リポジトリの中でコードを共有し、一つのコミットで複数モジュールを原子的(atomically)に変更し、統合された一つのビルド・依存関係グラフの上で開発する。単一のデプロイ単位を指すモノリシックアーキテクチャとは区別される、コード組織化(code organization)の問題である。
ソフトウェア組織が成長すると、サービスやライブラリの数は数百・数千に増える。 各成果物を別々のリポジトリに置くポリレポ(Polyrepo, Multi-repo)方式は初期には自然であるが、共通ライブラリを複数のリポジトリがバージョンで参照することで「どのリポジトリがどのバージョンを使うか」を追跡しにくくなる。 共通モジュールのセキュリティパッチ一つを反映するには、それを使う数十のリポジトリにバージョンアップグレードのPRをそれぞれ上げなければならない、いわゆる依存関係地獄(dependency hell)とダイヤモンド依存の問題が発生する。
モノレポはこの問題を観点の転換で解決する。 コードを「リポジトリ境界で分割しバージョンで結合」する代わりに、「一つのリポジトリの中でソースレベルで結合(source dependency)」するのである。 その結果、共通ライブラリを修正するコミットと、それを使うすべての消費者の修正が同じコミット・同じPRの中で原子的に行われる。 「変更がどこに影響を与えるか」は、バージョンマトリクスではなく依存関係グラフに対する静的解析によって即座に分かる。
技術士の答案の観点では、モノレポは単なる「大きなリポジトリ」ではなく、原子的変更・単一の真実の源・全体可視性という価値を得る代わりにビルド性能・アクセス制御・拡張性というコストを専用ツールで相殺するエンジニアリングのトレードオフとして記述すべきである。 Google・Meta・Microsoftなどの超大規模組織がモノレポを選んだという事実そのものよりも、「なぜ彼らは専用ビルドシステムなしにはモノレポが成立しないのか」を説明することが核心である。
1.1 登場の背景と必要性
第一に、コード共有と重複排除の要求である。 マイクロサービスが増えると、認証・ロギング・シリアライズといった共通コードが各サービスにコピーされるか、社内パッケージとして切り出されバージョンで配布される。 コピーは一貫性を崩し、バージョン配布はアップグレードの遅延を生む。 モノレポは共通コードを単一のソースとして置き、すべての消費者が最新のHEADを直接参照させることで、二つの問題を同時になくす。
第二に、大規模リファクタリングとAPI変更の安全性である。 ポリレポでは共通ライブラリの関数シグネチャを変えると、消費者はまだ旧バージョンを参照するため、変更が「壊れたか」を即座に分からない。 モノレポではライブラリとすべての呼び出し元を一つのコミットで共に直し一度にテストするため、コンパイル・テストが通れば組織全体が壊れていないことが保証される。
第三に、開発者体験とオンボーディングである。 新規開発者がリポジトリを一つクローンすれば全コードベースを探索・検索・変更でき、統合されたコードスタイル・リント・CIルールを一括適用できる。 ただしこの利点は、リポジトリが数千万ファイル規模になるとクローン・ビルド性能の問題へ反転するため、必ず専用ツールと共に論じなければならない。
2. 全体構造と依存関係モデル
モノレポの本質はリポジトリのレイアウトではなく、プロジェクト間の依存関係をソースレベルのグラフで表現する点にある。 以下の構造図は、単一リポジトリの中に複数のアプリケーションと共有ライブラリが一つの依存関係グラフに束ねられ、共通のビルド・CI・ツール層の上で動作する様子を示す。
graph TD
subgraph REPO["単一リポジトリ(モノレポ)"]
subgraph APPS["アプリケーション層"]
WEB["web-app"]
API["api-service"]
BATCH["batch-worker"]
end
subgraph LIBS["共有ライブラリ層"]
AUTH["lib-auth"]
LOG["lib-logging"]
MODEL["lib-domain-model"]
end
WEB --> AUTH
WEB --> LOG
API --> AUTH
API --> MODEL
BATCH --> MODEL
BATCH --> LOG
AUTH --> LOG
end
TOOL["ビルドシステム・CI(グラフ認識)"] -.解析.-> REPO
上のグラフでlib-loggingを修正すると、それを(直接・間接に)参照するlib-auth・web-app・api-service・batch-workerが影響範囲(affected set)に入る。
モノレポ専用ツールの中核的な能力は、まさにこの影響グラフを正確に計算し、変更されたコミットに対して「再ビルド・再テストすべきプロジェクトだけ」を選別することである。
これをaffected/impacted分析と呼び、リポジトリ全体を毎回ビルドせずとも安全性を保つ性能の秘訣である。
2.1 ソース依存と原子的コミット
ポリレポが成果物をバージョン番号(例: lib-auth@1.4.2)で参照するバイナリ依存(binary dependency)である一方、モノレポはソースツリー内のパスを直接参照するソース依存(source dependency)を基本とする。
この違いがモノレポのほぼすべての長所と短所を派生させる。
ソース依存ではライブラリの「現在のHEAD」が唯一のバージョンであるため、複数バージョンが同時に存在して生じるダイヤモンド依存の衝突が根本的に消える。
同時に原子的コミット(atomic commit)が可能になる — 例えばlib-domain-modelのフィールド名を変える変更と、そのフィールドを使うapi-service・batch-workerの修正が一つのコミットに束ねられ、リポジトリは常に「ビルド可能な一貫した状態」を保つ。
ロールバックも、そのコミット一つをgit revertすれば全体が共に復元される。
逆にこれは「私の知らぬ間に誰かが共通ライブラリを変え、私のサービスが壊れうる」という密結合のリスクも意味する。
そこでモノレポは、所有権境界をコードで強制するCODEOWNERS、可視性ルール(visibility)、そして変更前に全体の影響テストをCIで回す体系が必ず伴わなければならない。
2.2 ビルド・CIパイプラインの動作
モノレポで「全体をビルドする」という素朴なアプローチは、リポジトリが大きくなる瞬間に破綻する。 数千のプロジェクトを毎コミットごとにビルド・テストすればCI時間が数時間へ急増するからである。 したがってモノレポのツールは次のパイプラインで必要な作業だけを行う。
flowchart LR
COMMIT["コミット/PR変更ファイル"] --> GRAPH["依存関係グラフ計算"]
GRAPH --> AFFECTED["影響を受けるプロジェクト選別(affected)"]
AFFECTED --> CACHE{"ビルドキャッシュ命中?"}
CACHE -->|"命中(hit)"| REUSE["キャッシュ成果物の再利用"]
CACHE -->|"不一致(miss)"| RUN["該当作業のみビルド・テスト"]
RUN --> STORE["リモートキャッシュに保存"]
REUSE --> RESULT["CI結果"]
STORE --> RESULT
核心は二つの最適化である。 第一に、影響ベースの選別: 変更ファイルから逆方向に依存関係グラフをたどり、再検証すべきプロジェクトだけを選ぶ。 第二に、コンテンツアドレス指定キャッシュ(content-addressed cache): 作業の入力(ソース・依存関係・コマンド・ツールチェーン)をハッシュで指紋化し、同じ入力であれば既に計算された成果物をリモートキャッシュ(remote cache)からダウンロードして再利用する。 開発者Aがローカルでビルドした結果を開発者BとCIが再利用する、この分散キャッシュ共有が大規模モノレポの生産性を左右する。
3. 類型と代表的ツール
モノレポを支えるビルドシステムは、設計思想によって大きくグラフベースのタスクランナーと厳格な密閉型ビルドシステムに分かれる。 前者は既存エコシステム(npm・Gradleなど)の上に影響分析とキャッシュを載せる軽量なアプローチであり、後者はビルドの入力・出力を完全に制御し再現性と遠隔実行まで保証する重量級のアプローチである。
| 区分 | グラフベースランナー | 密閉型(hermetic)ビルドシステム |
|---|---|---|
| 代表ツール | Nx, Turborepo, Lerna | Bazel, Buck2, Pants |
| 思想 | 既存パッケージマネージャ上のオーケストレーション | 入力・出力の完全制御、再現可能ビルド |
| キャッシュ | 作業単位のローカル・リモートキャッシュ | アクション単位のコンテンツアドレスキャッシュ + 遠隔実行 |
| 導入難度 | 低(段階的適用が容易) | 高(BUILDファイルで全面再記述) |
| 適合規模 | 中小〜大規模 | 超大規模・多言語・長期維持 |
ここで留意すべき点は、ツール選択が「どちらがより良いか」ではなく、組織規模と再現性要求の水準への適合性の問題だということである。 数百人規模のウェブ中心組織がBazelを全面導入すれば、BUILDファイルの作成・維持コストが生産性を圧倒しうるし、逆に数千人・多言語の組織がグラフランナーだけを使えば、ビルド再現性と遠隔実行の限界に突き当たる。
3.1 密閉型ビルドと再現性
密閉型ビルドは、ビルド作業が宣言した入力(ソース・依存関係・ツールチェーンのバージョン)だけを見られ、ネットワークやシステム状態のような非宣言の入力に依存できないよう隔離する。 そのおかげで「同じ入力 → 常に同じ出力」が成立してキャッシュ命中率が最大化され、ビルドを数百台の遠隔ワーカーに分散(remote execution)できる。 Googleの内部ビルドシステムBlaze(オープンソース版がBazel)が数十億行規模の単一リポジトリを支える秘訣が、まさにこの密閉性と遠隔キャッシュ・実行の結合である。
一方、密閉性はすべての依存関係を明示的に宣言せねばならないため、初期の転換コストが大きい。 従来は暗黙的に参照していたシステムライブラリや全域ツールをすべてBUILDルールへ引き込まねばならないため、レガシーなコードベースを一度に密閉化することは事実上不可能であり、段階的な移行が必要である。
4. ポリレポとの比較 — 違いが生じる理由
モノレポとポリレポの対立は「リポジトリを何個に分けるか」ではなく、結合の時点をソースへ引き寄せるか、バイナリへ先送りするかの選択である。 この根本的な違いから、以下のすべての実務的な違いが派生する。
| 観点 | モノレポ | ポリレポ |
|---|---|---|
| 依存結合 | ソース(最新HEAD) | バイナリ(バージョン固定) |
| コード共有 | 直接参照、即時反映 | パッケージ配布・バージョンアップが必要 |
| 原子的変更 | 一つのコミットで全体変更 | 複数リポジトリの調整が必要 |
| アクセス制御 | 細分化が困難(別途ツールが必要) | リポジトリ単位で明確 |
| ビルド/CI | 専用ツールがないと急増 | リポジトリごとに独立、単純 |
| チーム自律性 | 共通ルールを強制、自律性↓ | チームごとの技術選択の自由↑ |
原子的変更が可能な理由はソース依存である。 ポリレポで共通APIを変えるには「ライブラリ配布 → 各消費者がバージョンアップ → 各自が再デプロイ」という多段階の調整が必要で、この過程で新旧バージョンが共存し互換性の負担が生じる。 モノレポはこの調整をコンパイラ・テストに置き換え一度に終わらせる。
アクセス制御が困難な理由は、一つのリポジトリがすなわち一つの権限境界だからである。 金融・国防のようにソースアクセスをチーム・等級別に厳格に分離せねばならない組織では、リポジトリ単位で権限が明確なポリレポが規制対応に有利である。 モノレポで細分化されたアクセス制御を行うには、疎なチェックアウト(sparse checkout)・サブツリー権限などの追加メカニズムが必要であり、運用の複雑度が上がる。
実務的な含意として、多くの組織がハイブリッドを選ぶ。 製品群・ドメイン単位でモノレポを置き(例: フロントエンドモノレポ、データプラットフォームモノレポ)、規制・外部公開・まったく異なるライフサイクルを持つ領域は別のリポジトリへ分離する、といった具合である。 すなわち「一つの巨大なリポジトリ」は目標ではなく、凝集度の高い境界の中での統合が実践的な志向点である。
5. 深化 — 超大規模モノレポの拡張技法と事例
モノレポの最大の技術的難題はGit自体の拡張限界である。
Gitは全履歴と作業ツリーをローカルに複製する分散モデルなので、ファイルが数百万〜数千万個になるとgit status・clone・checkoutが手に負えなくなる。
これを解決するために次の技法が発展した。
第一に、部分クローン(partial clone)と疎なチェックアウト(sparse checkout)である。
git clone --filter=blob:noneでblobを遅延ロードし、作業に必要なディレクトリだけを作業ツリーに展開してローカルの負担を減らす。
MicrosoftはWindowsのソース(約300GB、350万以上のファイル)をGitへ移す際、VFS for Git(後のScalar)でファイルを要求時点に仮想ファイルシステムで受け取らせ、全クローンなしに作業できるようにした。
第二に、仮想ファイルシステムとファイルモニタである。 MetaはMercurialベースのモノレポでWatchman(ファイル変更監視)とEdenFS(要求時ロードの仮想ファイルシステム)、ビルドツールBuck2を結合し、数千万ファイルのリポジトリでも状態照会を定数時間に近く保つ。 Googleはそもそもgitを使わず、Piperという中央集中型VCSと仮想ファイルシステムCitC、ビルドシステムBlazeで、数十億行・二万人余りの開発者が同時に作業する単一リポジトリを運用する(2016年の公開基準で約86TB、一日に数万件のコミット)。
第三に、リモートキャッシュ・遠隔実行である。 先に説明したコンテンツアドレスキャッシュを組織全体で共有すれば、新規開発者が初めてビルドするときでさえ大半の成果物をキャッシュから受け取り、数十分かかるビルドを数分に減らす。 実測の事例として、Nx・Turborepoを導入した組織はリモートキャッシュ命中時にCI時間が50〜90%短縮される効果を報告する(変更範囲と命中率によって偏差が大きいため、断定よりは傾向として理解すべきである)。
これらの事例の共通の教訓は明確である — モノレポは戦略ではなく投資である。 専用ビルドシステム、仮想ファイルシステム、リモートキャッシュ基盤、所有権・可視性のガバナンスが共に整うときにのみ成立し、この基盤なしにリポジトリを合わせるだけではかえって生産性が急落する。
6. 考慮事項および示唆点(技術士の観点)
- 適用戦略(段階的採用): 最初から全社単一リポジトリを志向するより、密接に共に変更される凝集度の高いドメインをまず一つのモノレポに束ね、グラフベースのランナー(Nx・Turborepo)で影響分析とリモートキャッシュを導入した後、規模が大きくなれば密閉型ビルドと仮想ファイルシステムへ拡張する段階的な成熟ロードマップが安全である。「合わせること」より「境界をどう引くか」が先である。
- トレードオフ(可視性 vs 自律性・性能): モノレポは全体可視性・原子的変更・一貫したツールという価値を与えるが、チームごとの技術選択の自由を制約し、Git・CIの拡張コストを引き起こす。専用ツールへの投資余力がない小規模組織や、完全に独立したライフサイクルを持つ製品には、ポリレポのほうが合理的でありうる。正解は組織規模・結合度・規制要件によって変わる。
- セキュリティ・ガバナンス: 単一リポジトリは権限境界が広くなるため、
CODEOWNERSに基づくレビュー強制、ディレクトリ別の可視性ルール、疎なチェックアウトによるアクセス範囲の制限、そしてサプライチェーンセキュリティ(SBOM・コミット署名)をCIに結合して密結合のリスクを制御せねばならない。リポジトリ自体が最上位の攻撃対象かつ単一障害点となるため、バックアップ・アクセス制御・保護ブランチが必須である。 - 組織・文化: モノレポは「皆が一つのコードベースを共に責任を持つ」という協業文化の転換を要求する。共通のリント・テスト・バージョンポリシーを全社合意で樹立せねばならず、トランクベース開発(trunk-based development)・大規模な自動リファクタリング(codemod)文化と結合するときに効果が最大化される。
- 展望および連携: モノレポはプラットフォームエンジニアリング・DevSecOps・CI/CDの土台として定着しつつあり、遠隔実行・分散キャッシュはクラウドビルドサービスとして商品化されている。さらにAIコードアシスタントが全コードベースの文脈を一つのリポジトリから参照できるという点で、組織知識の単一の供給源としての価値が一層大きくなると展望される。
参考資料
- Google, "Why Google Stores Billions of Lines of Code in a Single Repository" (Communications of the ACM, 2016): https://cacm.acm.org/research/why-google-stores-billions-of-lines-of-code-in-a-single-repository/
- Microsoft, "Scalar: Enabling Git at Scale": https://github.com/microsoft/scalar
- Meta Engineering, "Scaling Mercurial at Facebook": https://engineering.fb.com/2014/01/07/core-infra/scaling-mercurial-at-facebook/
- Bazel公式ドキュメント: https://bazel.build/
- Nx公式ドキュメント, "What is a Monorepo": https://nx.dev/concepts/decisions/why-monorepos
一言まとめ: モノレポは複数のプロジェクトを単一リポジトリにソース依存で統合し、原子的変更・全体可視性・コード共有を得る戦略であり、影響ベースの選別ビルド・リモートキャッシュ・仮想ファイルシステムといった専用基盤が支えるときにのみ拡張が成立し、アクセス制御・チーム自律性・Git拡張コストというトレードオフを組織規模と結合度に合わせて設計せねばならない。