ソフトウェアアーキテクチャの基礎とは

アーキテクチャに関する最高峰の本です。
今回は、本書の2部で紹介されたアーキテクチャを紐解いていきましょう!
結論:全アーキテクチャ比較表
| スタイル | 複雑度 | スケーラビリティ | 開発速度 | 運用コスト | 適用場面 |
|---|---|---|---|---|---|
| レイヤード | ★☆☆ | ★☆☆ | ★★★ | ★☆☆ | 小〜中規模の業務アプリ |
| モジュラーモノリス | ★★☆ | ★★☆ | ★★★ | ★☆☆ | 将来の分割を見据えた設計 |
| パイプライン | ★☆☆ | ★☆☆ | ★★★ | ★☆☆ | データ変換・ETL処理 |
| マイクロカーネル | ★★☆ | ★★☆ | ★★☆ | ★★☆ | プラグイン機構が必要 |
| サービスベース | ★★☆ | ★★★ | ★★☆ | ★★☆ | 中規模、部分的スケール |
| イベント駆動 | ★★★ | ★★★ | ★★☆ | ★★★ | 非同期処理、リアルタイム |
| スペースベース | ★★★ | ★★★ | ★☆☆ | ★★★ | 超高負荷、瞬間的スパイク |
| SOA | ★★★ | ★★☆ | ★★☆ | ★★★ | エンタープライズ、統制重視 |
| マイクロサービス | ★★★ | ★★★ | ★☆☆ | ★★★ | 大規模、完全分散 |
記号: ★多い = 高い/速い/重い
トレードオフの観点で選ぶので、アーキテクチャ自体に優劣はないことだけ頭に入れておけばOK!
なぜアーキテクチャスタイルを知る必要があるのか
「とりあえずマイクロサービス」「みんな使ってるから React + Firebase」
──このような流行ベースの選択は、トレードオフを理解していないために起こる。
各スタイルには明確な 得意領域と不得意領域 がある。本記事では、『ソフトウェアアーキテクチャの基礎 第2版』で紹介される9つの主要スタイルを、トレードオフの観点から解説する。
本記事の目的
- 各スタイルの メリット・デメリット を理解する
- 自分のプロジェクトに 最適なスタイルを選べる ようになる
- 「なぜこのスタイルを選んだか」を 説明できる ようになる
スタイル選択の2軸
アーキテクチャスタイルは以下の2軸で大別できる。
軸1:モノリス ←→ 分散
モノリス ハイブリッド 完全分散
│ │ │
レイヤード ─ モジュラーモノリス ─ サービスベース ─ マイクロサービス
軸2:同期 ←→ 非同期
同期的 非同期的
│ │
レイヤード/SOA ──────────────────────────── イベント駆動
重要: どちらが優れているかではなく、状況に応じて選ぶ。
1. レイヤードアーキテクチャ
一言で: 機能を水平レイヤーに分割する古典的スタイル
設計思想:関心の分離と依存方向の制御
核心: UI・ビジネスロジック・データアクセスという異なる責務を、水平に層として分離する。
狙い: 依存方向を 上から下への一方向 に制限することで、下層の変更が上層に影響しないようにする(理想的には)。
歴史的背景: データベース駆動設計の時代(1990年代)から続く、最も基本的なパターン。「データベーススキーマを中心に設計し、その上にロジック・UIを重ねる」という発想。
構造図
図から読み解く強みと弱み
構造的特徴1: 垂直の層構造 → シンプルさ
- 各層の役割が明確(UI/ロジック/データ)
- 新人でも理解しやすい
- しかし: 層を跨ぐ変更(例: DB列追加)が全層に波及しがち
構造的特徴2: 一方向依存(上→下)→ 依存の明確化
- 下層は上層を知らない → 下層の再利用が可能(理想)
- しかし: 実際は下層(DBスキーマ)の変更が上層まで伝播することが多い
構造的特徴3: すべてが単一のデプロイ単位 → 運用シンプル
- デプロイが1回で済む
- しかし: 部分的なスケールができない(全体を一緒にスケール)
トレードオフの本質
なぜシンプルか?: 全てが1つのアプリケーション、1つのデータベースに収まるから。
なぜスケールしないか?: まさにその「1つ」という構造が、部分的な拡張を阻む。
これがレイヤードの本質的ジレンマ。
トレードオフ表
| 項目 | 評価 | 説明 |
|---|---|---|
| 学習コスト | ◎ 低い | 最もシンプルで理解しやすい |
| 開発速度 | ◎ 速い | 小規模チームで素早く開発可能 |
| スケーラビリティ | × 低い | 全体を一緒にスケールするしかない |
| デプロイ容易性 | △ 普通 | モノリシックなので単一デプロイ |
| 変更の影響範囲 | × 広い | レイヤー間の依存で変更が伝播 |
| テスト容易性 | △ 普通 | レイヤー分離されていれば可 |
使うべき時
- 小〜中規模の業務アプリケーション
- チームが小さい(5名以下)
- スケール要件が低い
- 素早くMVPを作りたい
使うべきでない時
- 部分的に高負荷になる機能がある
- チームが大きい(10名以上)
- 独立したデプロイサイクルが必要
- 段階的なスケールが必要
実例
- 小〜中規模のWebアプリ(管理画面、社内ツール)
- Ruby on Rails / Laravel / Django の標準的な構成
2. モジュラーモノリス(第2版で追加)
一言で: モノリスだが内部をドメインでモジュール化したスタイル
設計思想:シンプルさとモジュール性の両立
核心: 「デプロイは1つ、設計は分割」という発想。モノリスの運用シンプルさを保ちながら、内部をドメイン境界で明確に分割する。
狙い: 将来のマイクロサービス化への準備をしつつ、今は運用コストを抑える。段階的移行のスタート地点として最適。
DDD(ドメイン駆動設計)との親和性: 境界づけられたコンテキストをモジュールとして実装する。
構造図
図から読み解く強みと弱み
構造的特徴1: 単一のデプロイ単位 → 運用シンプル
- サーバー1台、DB1つで動く
- デプロイパイプラインが1つ
- しかし: 部分的なスケールは不可
構造的特徴2: 明確なモジュール境界(点線) → 将来の分割容易
- モジュール間の依存が可視化されている
- 境界を尊重すれば、あとでマイクロサービス化しやすい
- しかし: 境界の維持には規律が必要(コードレビュー、アーキテクチャテストなど)
構造的特徴3: 共有DB → データアクセスは速い
- JOIN が使える、トランザクション境界が明確
- しかし: DBがモジュール間の結合ポイントになりがち(スキーマの共有による結合)
トレードオフの本質
なぜ「いいとこ取り」なのか?: モノリスの運用シンプルさ + マイクロサービスへの準備
なぜ「規律が必要」か?: 境界が論理的(コード上の分離)であって物理的(別プロセス)ではないため、破られやすい。
Shopify や GitHub が長く採用してきた理由がここにある。
トレードオフ表
| 項目 | 評価 | 説明 |
|---|---|---|
| モジュール性 | ◎ 高い | 内部がドメインで明確に分割 |
| 将来の分割 | ◎ 容易 | マイクロサービス化の準備になる |
| 開発速度 | ○ 速い | モノリスの利点を保ちつつ整理 |
| 運用コスト | ◎ 低い | 単一アプリなので運用シンプル |
| 境界の維持 | △ 難しい | 規律がないと境界が曖昧に |
| 部分スケール | × 不可 | モノリスなので全体スケールのみ |
使うべき時
- 現在はモノリスだが将来の分割を見据えている
- チームが成長する予定
- ドメインが明確に分かれている
- 運用コストは抑えたい
使うべきでない時
- 既に部分的な高負荷が発生している
- 独立したスケールが今すぐ必要
- チームが地理的に分散している
実例
- Shopify の初期アーキテクチャ
- GitHub の Monolith(2020年頃まで)
3. パイプラインアーキテクチャ
一言で: データをフィルタで段階的に変換していくスタイル
設計思想:単一責任と変換の連鎖
核心: UNIX哲学「1つのことをうまくやる」をアーキテクチャレベルで実現。各フィルタは1つの変換に特化し、パイプで繋ぐ。
狙い: 複雑なデータ処理を、シンプルな変換ステップの連鎖に分解する。各ステップを独立してテスト・再利用可能にする。
歴史: UNIX パイプ(1970年代)から続く、データ処理の基本パターン。ETL、データパイプライン、CI/CDなど広く応用される。
構造図
入力データ → [フィルタ1] → [フィルタ2] → [フィルタ3] → 出力データ
変換 集約 整形
例: CSV → [パース] → [フィルタリング] → [集計] → [JSON出力]
図から読み解く強みと弱み
構造的特徴1: 一方向の流れ → 理解が容易
- データの流れが左から右への一直線
- デバッグ時に「どのステップで壊れたか」が特定しやすい
- しかし: 分岐・ループなど複雑なフローには不向き
構造的特徴2: フィルタの独立性 → 再利用・テストが容易
- 各フィルタは入力を受け取り、出力を返すだけ(副作用なし)
- 単体テストが書きやすい
- しかし: フィルタ間で状態を共有できない
構造的特徴3: 直列処理 → 並列化困難
- 前のフィルタが終わらないと次が始まらない
- しかし: 最近のフレームワーク(Apache Beam など)は並列化をサポート
トレードオフの本質
なぜシンプルか?: データが一方向に流れるだけだから。
なぜ柔軟性がないか?: まさにその「一方向」という制約が、分岐・条件処理を難しくする。
バッチ処理やETLには最適だが、インタラクティブなアプリには不向き。
トレードオフ表
| 項目 | 評価 | 説明 |
|---|---|---|
| シンプルさ | ◎ 高い | 処理の流れが一直線で理解しやすい |
| 再利用性 | ○ 高い | フィルタを他のパイプラインで再利用可 |
| 並列処理 | × 困難 | 基本的に順次処理 |
| 柔軟性 | × 低い | パイプラインの順序変更が困難 |
| デプロイ | ◎ 容易 | 単一の実行可能ファイル |
| エラー処理 | △ 普通 | フィルタ単位で処理可能 |
使うべき時
- ETL(Extract, Transform, Load)処理
- データ変換・加工パイプライン
- バッチ処理
- シェルスクリプト的な処理
使うべきでない時
- インタラクティブなアプリケーション
- 複雑な分岐処理が必要
- 状態管理が必要
- リアルタイム処理
実例
- UNIX パイプ(
cat file.txt | grep "error" | sort | uniq) - データ処理フレームワーク(Apache Beam, Luigi)
- CI/CD パイプライン
4. マイクロカーネルアーキテクチャ
一言で: コア機能 + プラグインで拡張性を実現するスタイル
設計思想:最小コアと無限の拡張性
核心: コアシステムを最小限に保ち、機能をプラグインとして外付けする。プロダクトの多様なニーズに1つのコードベースで対応する。
狙い: 全ユーザーに全機能を提供するのではなく、各ユーザーが必要な機能だけを選択できるようにする。
Eclipse や VS Code の成功: この思想により、IDE という複雑な製品が成立している。
構造図
図から読み解く強みと弱み
構造的特徴1: コアが小さい → 安定性
- コアは最小限の機能のみ(エディタなら「テキスト編集」だけ)
- コアが安定していれば、プラグインが壊れても本体は動く
- しかし: コアのAPI設計が重要(変更すると全プラグインに影響)
構造的特徴2: プラグインの独立性 → 無限の拡張
- プラグイン同士は独立(緑のボックスが繋がっていない)
- ユーザーが自由に組み合わせ可能
- しかし: プラグイン間の連携が必要な場合に困る
構造的特徴3: 動的なロード → カスタマイズ性
- 実行時にプラグインを追加・削除できる(点線の矢印)
- しかし: バージョン管理が複雑(プラグインA v1.0 が コア v2.0 で動くか?)
トレードオフの本質
なぜ拡張性が高いか?: コアとプラグインが分離しているから。
なぜ管理が複雑か?: まさにその「分離」が、バージョン互換性の問題を生む。
VS Code の成功は、プラグイン管理の UX を磨いたことにある。
トレードオフ表
| 項目 | 評価 | 説明 |
|---|---|---|
| 拡張性 | ◎ 非常に高い | プラグインで無限に機能追加可 |
| カスタマイズ性 | ◎ 高い | ユーザーが必要な機能だけ有効化 |
| コア安定性 | ○ 高い | コアは小さく安定 |
| プラグイン品質 | △ 管理困難 | サードパーティ製の品質保証難しい |
| バージョン管理 | × 複雑 | プラグイン間の依存関係 |
| デプロイ | △ やや複雑 | プラグインのインストール管理 |
使うべき時
- プロダクトを多様なユーザーに提供する
- 機能をモジュール化して販売したい
- サードパーティの拡張を許可したい
- カスタマイズ要件が多様
使うべきでない時
- すべてのユーザーが同じ機能を使う
- 拡張性が不要
- プラグインの品質保証ができない
実例
- IDE(VS Code, IntelliJ IDEA)
- ブラウザ(Chrome, Firefox)
- WordPress
- Jenkins
5. サービスベースアーキテクチャ
一言で: 3〜5個の粗粒度サービスに分割する中間的スタイル
設計思想:実用主義的な分散
核心: 「マイクロサービスほど細かく分けなくていい」という実用主義。ドメインを大きめの単位(3〜5個)で分割し、運用コストと柔軟性のバランスを取る。
狙い: モノリスの限界を超えつつ、マイクロサービスの複雑さは回避する。中規模チーム(10〜30名)に最適化。
第2版での注目: モジュラーモノリスとマイクロサービスの「間」を埋めるスタイルとして再評価されている。
構造図
図から読み解く強みと弱み
構造的特徴1: サービス数が少ない(3〜5個)→ 運用可能
- デプロイパイプラインが5本程度で済む
- 監視対象が限定的
- しかし: マイクロサービスほどの細かいスケールは不可
構造的特徴2: 粗粒度の分割 → チーム編成しやすい
- 各サービスに2〜6名のチームを割り当て可能
- サービス間の調整が少なくて済む
- しかし: サービス境界の引き方が難しい(粗すぎると変更が伝播、細かすぎるとマイクロサービスに)
構造的特徴3: DBは共有でも分離でも可 → 柔軟性
- 最初は共有DB、徐々に分離することも可能
- しかし: 共有DBだとサービスの独立性が下がる
トレードオフの本質
なぜ「ちょうどいい」か?: モノリスの運用シンプルさと、マイクロサービスの柔軟性の中間点だから。
なぜ境界が難しいか?: 「どこまで粗くていいか」に明確な答えがないから。
多くの企業が「マイクロサービスを試して失敗→サービスベースに戻す」を経験している。
トレードオフ表
| 項目 | 評価 | 説明 |
|---|---|---|
| 部分スケール | ○ 可能 | サービス単位でスケール可 |
| 開発速度 | ○ 速い | マイクロサービスより簡単 |
| 運用コスト | ○ 中程度 | マイクロサービスより低い |
| デプロイ独立性 | ○ あり | サービスごとに独立デプロイ |
| チーム分割 | ○ 可能 | サービスごとにチーム編成可 |
| 粒度の最適化 | △ 難しい | サービス境界の見極めが重要 |
使うべき時
- マイクロサービスほどの複雑性は不要
- 部分的なスケールが必要
- チームが10〜30名程度
- ドメインが3〜5個に分けられる
使うべきでない時
- 極めて高いスケーラビリティが必要
- 技術スタックを多様化したい
- 小規模(5名以下)で運用コストを抑えたい
実例
- 中規模ECサイト(ユーザー/商品/注文/決済で分割)
- SaaS アプリケーション(認証/テナント管理/コア機能で分割)
6. イベント駆動アーキテクチャ
一言で: 非同期メッセージングで疎結合を実現するスタイル
設計思想:リアクティブと疎結合
核心: 「何かが起きたら通知する」という発想。コンポーネント間をイベントで繋ぎ、送信側は受信側を知らない(疎結合)。
狙い: システム間の結合を最小化し、高いスケーラビリティとリアルタイム性を実現する。「注文が確定した」というイベント1つから、在庫更新・決済・発送準備が並列に走る。
2つのパターン:
ブローカー型(中央ブローカー経由)vs メディエーター型(中央調停者が制御)
メディエーター型は、8. オーケストレーション駆動SOAと同じなので割愛
構造図(ブローカー型)
図から読み解く強みと弱み
構造的特徴1: Producer と Consumer が直接繋がっていない → 疎結合
- Producer は「誰が受け取るか」を知らない
- Consumer を追加しても Producer は無影響
- しかし: 処理の流れ全体が見えない(デバッグ困難)
構造的特徴2: 非同期メッセージング → スケーラビリティ
- Consumer を増やすだけで処理能力が上がる
- ブローカーがキューイング→負荷を平準化
- しかし: 即座の応答は不可(結果が返るまで時間差)
構造的特徴3: イベントが中心 → リアルタイム性
- イベント発生と同時に全 Consumer が反応
- しかし: データ整合性は結果整合性のみ(トランザクション境界なし)
トレードオフの本質
なぜ疎結合か?: コンポーネント間にブローカーが挟まるから。
なぜデバッグが困難か?: まさにその「間接性」が、処理の流れを不透明にする。
「注文→在庫減→決済→発送」の流れをデバッグするには、各イベントを追跡するツールが必須。
トレードオフ表
| 項目 | 評価 | 説明 |
|---|---|---|
| 疎結合 | ◎ 非常に高い | Producer/Consumer が独立 |
| スケーラビリティ | ◎ 非常に高い | Consumer を増やして負荷分散 |
| リアルタイム性 | ◎ 高い | イベント駆動でリアクティブ |
| デバッグ困難 | × 非常に困難 | 処理の流れが追いにくい |
| データ整合性 | × 困難 | 結果整合性のみ保証 |
| 運用コスト | × 高い | メッセージブローカーの管理 |
使うべき時
- リアルタイム処理が必要
- 高いスケーラビリティが必要
- システム間の疎結合を実現したい
- 非同期処理が主体
使うべきでない時
- トランザクション整合性が必須
- 処理の流れを明確にしたい
- デバッグ容易性を重視
- 小規模で運用コストを抑えたい
実例
- リアルタイム通知システム
- IoT データ処理
- ストリーム処理(Apache Kafka, AWS Kinesis)
- 注文処理システム(在庫更新、決済、発送を非同期化)
7. スペースベースアーキテクチャ
一言で: インメモリデータグリッドで超高負荷に対応するスタイル
設計思想:データベースのボトルネック排除
核心: 「DBが遅い」という根本問題を、DBを使わないことで解決する。データをインメモリに置き、処理ユニットを動的に増減させて瞬間的な高負荷に対応。
狙い: チケット販売やセールなど、予測不能な瞬間スパイクに耐える。負荷が10倍になっても、処理ユニットを10個追加すれば対応可能。
名前の由来: タプルスペース(分散共有メモリ)から。
構造図
図から読み解く強みと弱み
構造的特徴1: 各ユニットがアプリ+キャッシュを持つ → 独立性
- 処理ユニットが完全に独立(水平に複製可能)
- 1台落ちても他が稼働し続ける
- しかし: 各ユニットのデータを同期する必要(データグリッドの役割)
構造的特徴2: データグリッド(インメモリ)→ 超高速
- DB へのアクセスがない(読み書きは全てメモリ)
- しかし: メモリは揮発性→データグリッドの冗長化が必須
構造的特徴3: DBへの書き込みは非同期(点線)→ スパイク耐性
- リクエストのピーク時もDBがボトルネックにならない
- しかし: DBとメモリのズレが発生(結果整合性)
データグリットって何?
結論:データを“中央に集めず”、分散したまま共有・連携する仕組み
| 観点 | 従来(データレイク) | データグリッド |
|---|---|---|
| データの場所 | 中央に集約 | 各ドメインに分散 |
| 管理 | データ基盤チーム | 各チームが責任持つ |
| スケール | 中央がボトルネック | チーム単位でスケール |
| 柔軟性 | 低め | 高い |
トレードオフの本質
なぜ超高速か?: DBを経由せず、全てメモリで完結するから。
なぜ複雑か?: まさにその「DBを使わない」戦略が、データ同期・整合性・障害時復旧を難しくする。
年に数回のセールで数百万人が同時アクセスする EC サイトには最適。普段使いには過剰。
トレードオフ表
| 項目 | 評価 | 説明 |
|---|---|---|
| 瞬間スパイク対応 | ◎ 非常に高い | 動的にユニット追加 |
| スケーラビリティ | ◎ ほぼ無限 | 水平スケール容易 |
| レスポンス速度 | ◎ 非常に速い | インメモリ処理 |
| 実装複雑度 | × 非常に高い | データ同期が複雑 |
| データ整合性 | × 困難 | 結果整合性 |
| コスト | × 非常に高い | インメモリグリッドのライセンス |
使うべき時
- 瞬間的な高負荷(チケット販売、セール)
- レスポンス速度が最重要
- 負荷が予測不能
- 予算が潤沢
使うべきでない時
- トランザクション整合性が必須
- 予算制約が厳しい
- 負荷が安定している
- 小〜中規模のアプリ
実例
- オンラインチケット販売(コンサート、スポーツ)
- オークションサイト
- ゲームサーバー(同時接続数が変動)
8. オーケストレーション駆動SOA
一言で: 中央オーケストレーターがサービス間の調整を行うスタイル
設計思想:中央統制と再利用
核心: ビジネスプロセスを中央のオーケストレーター(ESB/BPM)が管理する。各サービスは「部品」に徹し、オーケストレーターが組み合わせて複雑なフローを実現。
狙い: エンタープライズ環境でのガバナンス(統制)。「誰がどのサービスを呼んでいるか」を中央で把握・制御する。
歴史: 2000年代に流行したが、マイクロサービスの台頭で衰退。しかし統制が必要な環境では今も有効。
構造図
図から読み解く強みと弱み
構造的特徴1: 全ての矢印がオーケストレーターを経由 → 可視化
- ビジネスフローが1箇所(オーケストレーター)に集約
- 「注文処理は、サービス1→2→3の順で呼ぶ」が明確
- しかし: オーケストレーターが単一障害点(落ちると全停止)
構造的特徴2: サービス同士が直接通信しない → 統制しやすい
- サービスが勝手に他サービスを呼ぶことはない
- 中央で「誰が誰を呼べるか」を管理可能
- しかし: オーケストレーターがボトルネック(全リクエストを経由)
構造的特徴3: サービスは「呼ばれる」だけ → 再利用性
- 同じサービスを複数のフローで使い回せる
- しかし: サービスの変更がオーケストレーター側の修正を引き起こす
オーケストレーターの語源は?
「オーケストラ(楽団)」の指揮者から来てる
バイオリン 🎻
ドラム 🥁
ピアノ 🎹
全員がバラバラに演奏したらカオスなので、指揮者が「今ここ!次これ!」とまとめる
トレードオフの本質
なぜ統制が効くか?: 全てがオーケストレーターを通るから。
なぜスケールしないか?: まさにその「1箇所を通る」構造が、ボトルネックと単一障害点を生む。
金融機関など「何が起きているか全て把握したい」環境では今も現役。
トレードオフ表
| 項目 | 評価 | 説明 |
|---|---|---|
| 統制 | ◎ 非常に高い | 中央で全体を管理 |
| ビジネスフロー可視化 | ◎ 高い | オーケストレーターで一元管理 |
| 再利用性 | ○ 高い | サービスを組み合わせて利用 |
| 単一障害点 | × あり | オーケストレーターが落ちると全停止 |
| スケーラビリティ | × 低い | オーケストレーターがボトルネック |
| 運用コスト | × 高い | ESB/BPM 製品のライセンス・運用 |
使うべき時
- エンタープライズ環境で統制が必要
- 複雑なビジネスフローを可視化したい
- レガシーシステムとの統合
- ガバナンスが重要
使うべきでない時
- 高いスケーラビリティが必要
- スタートアップ・アジャイル開発
- 単一障害点を許容できない
- 運用コストを抑えたい
実例
- 大企業の基幹システム統合
- 金融機関のシステム連携
- IBM WebSphere, Oracle SOA Suite 利用環境
9. マイクロサービスアーキテクチャ
一言で: 細粒度の独立したサービスに完全分散するスタイル
設計思想:完全な自律性と境界づけられたコンテキスト
核心: 「各サービスは完全に独立した製品」という発想。DB、デプロイ、チーム、技術スタックまで全てが分離。Conway の法則(システム構造は組織構造を反映する)を積極的に活用。
狙い: 大規模組織(100名以上)で、チームが互いにブロックせずに並列開発・デプロイできるようにする。
DDD との関係: 各マイクロサービスは「境界づけられたコンテキスト」に対応。ドメインの境界 = サービスの境界。
構造図
図から読み解く強みと弱み
構造的特徴1: 各サービスが独自のDBを持つ → 完全な独立性
- サービスAのDB変更がサービスBに影響しない
- 各サービスで異なるDB技術を選択可能(PostgreSQL, MongoDB, Redis など)
- しかし: データの整合性が困難(JOIN 不可、分散トランザクション問題)
構造的特徴2: サービス間通信は API/メッセージング → 疎結合
- サービスAの内部実装をサービスBは知らない
- 各サービスを異なる言語で実装可能(Go, Python, Java など)
- しかし: ネットワーク経由の通信は遅く不安定(分散コンピューティングの8つの誤信)
構造的特徴3: サービス数が多い(10個以上)→ 並列開発
- 各チームが独立してデプロイ可能
- チーム間の調整コストが最小化
- しかし: 運用が極めて複雑(監視、ログ集約、分散トレーシング、デプロイパイプライン × サービス数)
トレードオフの本質
なぜスケールするか?: 各サービスが物理的に分離しているから。
なぜ複雑か?: まさにその「分離」が、データ整合性・ネットワーク障害・運用複雑度という新たな問題を生む。
Netflix(数百のマイクロサービス)の成功は、その複雑さを管理する仕組み(Hystrix, Eureka など)を作り上げたから。
トレードオフ表
| 項目 | 評価 | 説明 |
|---|---|---|
| スケーラビリティ | ◎ 非常に高い | サービスごとに独立スケール |
| 技術選択の自由 | ◎ 完全自由 | サービスごとに異なる技術可 |
| デプロイ独立性 | ◎ 完全独立 | サービスごとに独立デプロイ |
| チーム独立性 | ◎ 高い | サービスごとに完全に分離 |
| 運用複雑度 | × 非常に高い | 監視・デプロイ・デバッグが複雑 |
| 開発速度(初期) | × 遅い | 分散システムの構築に時間 |
| データ整合性 | × 困難 | 分散トランザクション問題 |
| ネットワーク依存 | × 高い | 分散コンピューティングの8つの誤信 |
使うべき時
- 大規模(100名以上)チーム
- 極めて高いスケーラビリティが必要
- サービスごとに技術スタックを変えたい
- 独立したデプロイサイクルが必須
使うべきでない時
- 小〜中規模チーム(30名以下)
- 運用リソースが限られている
- 開発速度を最優先したい
- トランザクション整合性が必須
実例
- Netflix(数百のマイクロサービス)
- Amazon(サービスごとにチーム)
- Uber, Airbnb
スタイル選択フローチャート
まとめ:スタイル選択のチェックリスト
ステップ1: 制約を確認
- チームサイズは?(5名以下 / 6-30名 / 31名以上)
- 予算制約は?(運用コストをどこまで許容できるか)
- 技術スキルは?(分散システムの経験があるか)
ステップ2: 要件を確認
- スケーラビリティ要件は?(低 / 中 / 高)
- 負荷の特性は?(安定 / 変動 / 瞬間スパイク)
- 整合性要件は?(強整合 / 結果整合で可)
- レスポンス速度要件は?(数秒 / 数百ms / 数十ms)
ステップ3: トレードオフを評価
各候補スタイルについて以下を確認:
- 得るもの を3つ挙げられるか?
- 失うもの を3つ挙げられるか?
- トレードオフを 受け入れられるか?
ステップ4: 段階的移行を考慮
最初から完璧なスタイルを選ぶ必要はない。
Phase 1: レイヤード/モジュラーモノリスで開始
↓
Phase 2: 負荷が高い部分をサービス化
↓
Phase 3: さらに必要に応じて分割
重要: スタイルは「進化させるもの」であり、「最初に決め切るもの」ではない。
参考文献
- 書名: ソフトウェアアーキテクチャの基礎 第2版
- 著者: Mark Richards、Neal Ford
- 出版: オライリー・ジャパン