要点: Microservicesは組織と運用の選択肢であり、大規模システムの必須目標ではありません。
この記事の用語: Modular Monolith:一アプリケーション内を明確なモジュールへ分ける設計。サービス境界:サービスの責任範囲。
現場の課題
技術レイヤーごとに分割すると、一つの要求が多数のサービスを通ります。リリース調整は残ったまま、ネットワーク障害と分散トランザクションだけが増えます。
単純な対策だけでは不十分な理由
サービス境界の価値は、チームが独立して所有、リリース、スケールできることです。Modular Monolithなら、ネットワークと分散トランザクションのコストを払う前に境界を安く検証できます。
処理フロー
所有権と不変条件→モジュラーモノリス
境界の強制→抽出ポイント
契約とデータ→マイクロサービス
独立運用
アーキテクチャ上の判断
ビジネス機能による分割
同一の不変条件を保護するルールとデータを1か所に保持します。ユーザーサービスやDBサービスといった技術レイヤーでの分割は避けます。
同期呼び出しの限定
呼び出し元が即座に結果を必要とする場合にのみ同期処理を使用し、それ以外はイベントによる非同期反応を採用します。
運用ライフサイクルの所有
サービスの抽出には、単にコードを移動するだけでなく、オンコール体制、ダッシュボード、デプロイ、セキュリティ、キャパシティ管理の所有が含まれます。
さらに深く考える
データ所有権こそが最も堅牢な境界
サービスはリードモデルやイベント、APIを公開できますが、他のサービスがそのテーブルへ直接書き込むことは禁止されます。一時的な複製には所有者と削除期日を設定します。
ストラングラー移行におけるデータ照合
移行期間中は新旧の実行結果を比較照合し、少数のコホート(ユーザー群)から段階的に切替え、データ同等性が確認されるまで迅速な切り戻しルートを維持します。
実装手順
- 業務能力、データの不変条件、変更を所有するチームを整理します。
- Modular Monolith内でモジュールAPIと依存ルールを強制します。
- 一つの業務能力を、API契約、データ移行、ロールバック手順と一緒に分離します。
コード例: 抽出前の依存関係ルール定義
module Orders exposes OrdersApi
module Billing exposes BillingApi
Orders may call BillingApi
Orders must not import BillingRepository
architectureTest.assertNoInternalDependencyLeaks()自動化されたアーキテクチャテストにより、意図したモジュールグラフをビルド時の制約として適用します。
想定しておく障害
- 共有データベースにより、サービスが契約をバイパスしてしまう。
- 細かすぎる境界定義により、分散N+1問題が発生する。
- 2つのチームが同一の不変条件を所有していると誤認する。
監視すべきこと
| 指標 | 何が分かるか |
|---|---|
| モジュール間変更頻度 | 一括リリースを必要とする依存関係が残存しているかを示します。 |
| 1ジャーニーあたりのリモート呼び出し数 | 過度な細粒度化とそれによる遅延の増加を示します。 |
| デプロイおよびインシデントの独立性 | 抽出によって真の自律性が得られたかを検証します。 |
設計の検証方法
- CI環境で不正な内部モジュールのインポートを遮断します。
- 抽出予定の境界に対して事前に遅延や障害を注入して検証します。
- 新旧両方のパスで同一インプットを実行し、出力結果を照合します。
本番導入の進め方
アーキテクチャテストと担当者が明確なモジュールから始めます。読み取り、書き込み、データの順に分離し、運用上の利益が分散コストを上回るときだけ独立サービスへ移します。
本番前チェックリスト
- 各サービスが自身のデータと業務判断を完全に所有していること。
- サービス間呼び出しにレイテンシー、タイムアウト、障害予算が設定されていること。
- プラットフォーム全体で全サービスを統一的にデプロイ、監視、保護できること。
まとめ
良いサービス境界はチーム間の調整を減らし、悪い境界は関数呼び出しをネットワーク呼び出しへ変えるだけです。
