モジュラーモノリス

英語名 Modular Monolith Pattern
読み方 モジュラー モノリス パターン
難易度
所要時間 30分〜1時間
提唱者 Simon Brown / DDD コミュニティ
目次

ひとことで言うと
#

単一のデプロイユニット(モノリス)を維持しつつ、内部をドメインごとのモジュールに分割し、モジュール間の依存を明示的なインターフェースで制御するアーキテクチャパターン。

押さえておきたい用語
#

押さえておきたい用語
Modular Monolith(モジュラー モノリス)
単一デプロイでありながら内部がモジュール単位で分離されたアーキテクチャを指す。
Module Boundary(モジュール境界)
モジュール間の依存を制御する境界線を指す。パッケージ・名前空間・プロジェクト分割で実現する。
Public API(パブリック API)
モジュールが外部に公開する唯一のアクセスポイント。内部実装を隠蔽するためのインターフェース。
Big Ball of Mud(ビッグ ボール オブ マッド)
モジュール境界がない無秩序なモノリス。どこからでも何でも参照できる状態である。
Internal Event(インターナル イベント)
モジュール間を疎結合に連携させるためのイベント通知。直接呼び出しを避ける手法。

モジュラーモノリスの全体像
#

モジュラーモノリス:単一デプロイ内でモジュール境界を維持する
単一デプロイユニット注文モジュールPublic APIDomain ModelRepositoryDB Schema内部は非公開在庫モジュールPublic APIDomain ModelRepositoryDB Schema内部は非公開ユーザーモジュールPublic APIDomain ModelRepositoryDB Schema内部は非公開モジュール間はPublic APIのみで通信。直接のDB参照は禁止将来マイクロサービスに分離する際の境界がそのまま使える
モジュラーモノリス構築の進め方フロー
1
ドメイン分析
ビジネスドメインを整理しモジュール候補を特定
2
境界の設計
Public API/内部実装の分離ルールを定義する
3
段階的な分離
既存コードをモジュール単位にリファクタリング
境界の維持
ArchUnitなどで境界違反を自動検出する

こんな悩みに効く
#

  • モノリスが無秩序に育ってしまい、どこを変更しても想定外の箇所に影響が出る
  • マイクロサービスに移行したいが、分散システムの複雑さを扱えるチーム体制ではない
  • モジュール境界を決めたいが、どこで切ればいいかわからない

基本の使い方
#

ビジネスドメインを分析してモジュール候補を特定する
DDDの境界づけられたコンテキストをベースに、ビジネスの関心事ごとにモジュールを定義する。「注文」「在庫」「ユーザー」「決済」のように、それぞれが独立した責務を持つ単位にする。
モジュール間の通信ルールを定義する
各モジュールはPublic API(インターフェース)のみを外部に公開し、内部のドメインモデル・リポジトリ・DBスキーマは非公開にする。モジュール間のDB直接参照は禁止。非同期連携にはInternal Eventを使う。
境界違反を自動検出する仕組みを入れる
ArchUnit(Java)、NetArchTest(.NET)、eslintルール(TypeScript)などで、モジュール間の不正な依存をCIで検出する。境界を手動で守るのは限界があるため、自動化が必須。

具体例
#

例1:EC企業がBig Ball of Mudをモジュラーモノリスに再構築する

エンジニア50名のEC企業。10年かけて育った30万行のモノリスは、注文処理のコードから在庫テーブルを直接参照するなど依存が絡み合い、1機能の修正に平均 4チーム の調整が必要だった。

6つのモジュール(注文・在庫・ユーザー・決済・配送・商品)に分離。各モジュールにPublic APIを定義し、CIでモジュール境界違反を自動検出する仕組みを導入。

リファクタリングに6ヶ月かけた結果、1機能の修正に必要なチーム数が 4 → 1.2 に減少。デプロイ起因のバグが 月12件 → 月3件 に減った。

例2:スタートアップが最初からモジュラーモノリスで始める

エンジニア8名のシリーズAスタートアップ。「将来はマイクロサービスにする」前提で、最初からモジュラーモノリスで設計。

3モジュール(テナント管理・課金・コア機能)でスタートし、各モジュールはGoのinternal packageで境界を実現。モジュール間はインターフェース経由でのみ通信。

シリーズBで20名に拡大した時点でも、モジュール境界が明確なためチーム分割がスムーズ。各チームが独立してモジュールを開発できる体制になるまで 2週間 で移行完了。マイクロサービス化は規模が50名を超えてからの判断に先送りした。

例3:金融機関がマイクロサービスからモジュラーモノリスに戻す

エンジニア30名の証券系スタートアップ。「モダンにやろう」と初期から12個のマイクロサービスで構築したが、分散トランザクションの複雑さ・サービス間通信の遅延・運用コストが許容範囲を超えた。

12サービスを4モジュールのモジュラーモノリスに統合。インフラコストが 月額180万円 → 65万円 に削減。分散トランザクションが不要になったことで、決済処理の整合性バグがゼロに。デプロイパイプラインも12本→1本に集約され、運用負荷が激減した。

やりがちな失敗パターン
#

  1. モジュール境界を決めてもCIで強制しない — ルールだけ作っても、忙しいときに「ちょっとだけ直接参照」が発生し、半年で境界が崩壊する。自動検出を必ず入れる
  2. モジュールを細かく分けすぎる — 3〜8モジュール程度が管理しやすい。20モジュールは分割しすぎで、マイクロサービスと同じ複雑さが生まれる
  3. 共有データベースを1つのスキーマで使う — モジュールごとにスキーマを分離するか、少なくともテーブルの所有モジュールを明確にする
  4. 「いずれマイクロサービスに」を理由に過剰設計する — モジュラーモノリスで十分な規模なのに、メッセージキューやサービスディスカバリを導入する必要はない

まとめ
#

モジュラーモノリスは単一デプロイの利便性を保ちながら、内部をドメインごとのモジュールに分離して秩序を維持するアーキテクチャパターン。モジュール間はPublic APIのみで通信し、内部実装を隠蔽するルールをCIで自動的に強制する。マイクロサービスの分散システム複雑性を回避しつつ、将来の分離に備えた境界設計を実現できるため、多くのチームにとって現実的な選択肢になる