はじめに
「モノレポとマイクロサービスどっちがいいの?」
こういう質問したことありませんか?
私はあります。
しかしこの質問は、正しく成り立ちません。
「モノ」という接頭辞が共通しているせいで対立軸に見えてしまうのが混乱の原因です。
私自身もここが整理できていませんでした。
この記事では、まず2つを独立した軸として分解し、それぞれの軸でメリット・デメリットと判断基準を整理します。
2つの軸を分解する
正しい対応関係はこうです。
| 軸 | 選択肢 | 何を決めるか |
|---|---|---|
| リポジトリ戦略 | モノレポ ⇔ ポリレポ | コードをどこに置くか |
| アーキテクチャ | モノリス ⇔ マイクロサービス | コードをどう動かすか |
この2軸は独立しているので、組み合わせは4象限あります。
Google は世界最大級のモノレポで無数のサービスを動かしているし、逆に Amazon はポリレポ文化です。つまり「モノレポにしたからマイクロサービスにできない」も「マイクロサービスだからポリレポにすべき」も成り立ちません。2つの意思決定は別々にやる。これがこの記事の主張のすべてで、以下は各軸の各論です。
軸1: モノレポ vs ポリレポ
モノレポのメリット
アトミックな変更ができる。 これが最大の利点です。共有APIの破壊的変更と、その利用側すべての修正を1つのPRで完結できます。
ポリレポでこれをやると「ライブラリ側をリリース → バージョンを上げる → 利用側を修正 → リリース順序を調整」という多段リリースになり、中間状態で壊れるリスクを常に抱えます。
コード共有のコストが低い。
共通の型定義、lint設定、CI設定を1箇所に置けます。
TypeScript なら packages/shared の型をそのまま import でき、npm publish のような配布レイヤーが不要になります。
全体検索と一括リファクタリングが効く。
grep も LSP も全コードに届くので、「この関数、誰が使ってるんだっけ」が一発でわかります。
副次的な効果として、コーディングエージェント(Claude Code 等)との相性も良い。エージェントのコンテキストに関連コードがすべて収まるためです。
モノレポのデメリット
CIの重さと戦うことになる。
素朴に組むと1行の変更で全パッケージのビルド・テストが走ります。
影響範囲を解析して差分ビルドする仕組み(Turborepo / Nx / Bazel)の導入が実質必須で、これはツール整備コストとして先払いになります。
権限分離が難しい。
アクセス制御はリポジトリ単位が基本なので、「このチームにはこのディレクトリだけ見せたい」ができません。CODEOWNERS でレビュー必須化などの緩和はできますが、閲覧制限そのものは不可能です。
gitのスケール限界がいつか来る。
巨大化すると clone や status が遅くなります。
ただしこれは Google が独自VCSを作り、Meta が Sapling を開発したレベルの規模の話で、普通の組織が心配する段階ではないです。
ポリレポが勝つケース
権限分離が強く要求される場合(客先ごとにコードを隔離する受託、セキュリティ要件が厳しいコンポーネントの分離)と、プロダクト間に依存が本当に一切ない場合。
逆に言えばそれ以外でポリレポを積極的に選ぶ理由は薄くなっています。
軸2: モノリス vs マイクロサービス
まず両者の構造を概念図で対比します。
図の対比点は3つです。モノリスの境界はプロセス内のモジュール境界で、モジュール間は関数呼び出し(実線)。
マイクロサービスの境界はネットワークで、サービス間はRPCやメッセージング(点線、失敗しうる)。
DBはモノリスが共有DB1つに対し、マイクロサービスはサービスごとに所有します(database per service)。
この2つの違い——呼び出しの失敗可能性とDB所有——が、以下のメリット・デメリットのほぼすべてを生みます。
マイクロサービスのメリット
独立デプロイ。
サービスごとにリリースサイクルを分離できます。
チームが増えると「他チームのリリース待ちでデプロイできない」「誰かの変更でステージングが壊れて全員が止まる」という待ち行列が発生しますが、これが消えます。
障害隔離とスケーリングの粒度。
負荷の高いサービスだけスケールアウトでき、あるサービスの障害が(設計が正しければ)他に波及しません。
技術選定の自由。
サービスごとに最適な言語・DBを選べます。
CPUバウンドな処理だけ Go、管理画面は Rails、のような使い分けが可能です。
マイクロサービスのデメリット
分散システムの複雑さを丸ごと引き受ける。
概念図の点線部分の話です。
モノリスでは関数呼び出しだったものがネットワーク越しのRPCになります。
ネットワークは失敗するので、リトライ・冪等性・タイムアウト・サーキットブレーカーが全呼び出しで必須になります。
「関数呼び出しは失敗しない」という前提が消えるのがどれだけ痛いかは、経験しないとわかりにくい部分です。
トランザクション境界が崩壊する。 概念図のDB所有の帰結です。モノリスならDBトランザクション1つで済んだ処理が、サービスを跨ぐと使えなくなります。
このシーケンス図の「決済は成功したのか失敗したのかわからない」状態が分散システムの本質的な難しさで、Saga や Outbox パターンで対処することになりますが、実装・テスト・運用のコストはモノリスの比ではありません。
観測できないと運用できない。
障害調査で「どのサービスのどの呼び出しが遅いのか」を追うには分散トレーシング(OpenTelemetry 等)が前提になります。
ログを見れば済んだモノリスとは調査コストの桁が違います。
組織が小さいと純粋にオーバーヘッド。
システムの構造は組織のコミュニケーション構造を写し取る(コンウェイの法則)。
したがってチーム境界とズレたサービス境界は維持コストが高く、逆にサービス分割を活かしたいならチーム構造から設計する必要があります(逆コンウェイ戦略)。
チーム数よりサービス数が多い状態は、1チームが分散システムの複雑さだけを負担している状態です。
モジュラーモノリスという中間解
「モノリスの内部をモジュール境界で規律を持って分割し、モジュール間は定義されたインターフェース経由でのみ通信する」設計です。
デプロイは1つのままなので分散システムの複雑さを回避しつつ、境界が正しく引けていれば将来のサービス切り出しが現実的なコストでできます。
重要なのは、マイクロサービスで一番難しいのは境界設計であって、その難しさはモジュラーモノリスでも同じだという点です。
だったらネットワーク分断のない環境で境界設計の試行錯誤をして、境界が安定してから切り出すほうが手戻りが安い。
意思決定フローチャート
フローチャートに込めた判断基準を言語化しておきます
- リポジトリ戦略はモノレポがデフォルト。 ポリレポを選ぶのは権限分離という明確な理由があるときだけ
- アーキテクチャは痛み駆動。 マイクロサービスは組織のスケール問題(デプロイ競合、チーム間調整コスト)への解なので、その痛みが実際に発生してから導入する。予防的導入はコストの前払いにしかならない
- 切り出す前に境界を疑う。 チーム境界と一致しない切り出しは、分散システムの複雑さを追加するだけで痛みを解消しない
おわりに
「モノレポ vs マイクロサービス」という問いは、独立した2軸を混ぜた誤った問題設定でした。分解した結果を並べると:
- リポジトリ戦略: 迷ったらモノレポ。ツールの成熟でデメリットの多くは解消済み
- アーキテクチャ: 迷ったらモジュラーモノリス。マイクロサービスは組織問題の解であり、痛みの顕在化を待ってからで遅くない
そして概念図が示すとおり、マイクロサービスはモノリスの内部構造(モジュール分割)をネットワーク境界に昇格させたものです。
裏を返せば、モジュール境界がきちんと引けていないモノリスをサービスに切り出しても、密結合がネットワークを跨ぐだけで複雑さが増します。
組織やプロジェクトに合わせて、最適な構成を考える一助になれば幸いです。