アーキテクチャの比較と選定 — トレードオフを見極める
選定の日
プロジェクト開始から3ヶ月。βリリースまであと1週間。CTOから「最終アーキテクチャレビュー」の招集がかかった。
会議室にはCTO・テックリード・エンジニア6人が集まっている。カオリは自分が設計したアーキテクチャを説明する番だ。
「これまで多くのパターンを学んだ。なぜ今の設計を選んだか、何を捨てたか、何を将来に残したか、説明します」
INFO
アーキテクチャ選定は「最高の答え」を探すのではなく、「今の文脈で最も少ない問題を持つ答え」を選ぶことです。全てのトレードオフを言語化できることが、良いアーキテクトの条件です。
品質特性による比較
ソフトウェアアーキテクチャは、次の品質特性(Quality Attributes)に対してトレードオフを持つ。
性能・スケーラビリティ
| アーキテクチャ | スループット | レイテンシ | スケール難易度 |
|---|---|---|---|
| モノリス | 中(垂直スケール) | 低 | 低(水平スケール可) |
| マイクロサービス | 高(機能別) | 中(ネットワーク遅延) | 高 |
| CQRS | 高(読み書き分離) | 低(読み最適化) | 中 |
| サーバーレス | 高(自動スケール) | 高(コールドスタート) | 低(自動) |
| イベント駆動 | 高(非同期) | 中(非同期遅延) | 中 |
開発・保守性
| アーキテクチャ | 開発速度(初期) | 保守性(長期) | テスト容易性 | チーム独立性 |
|---|---|---|---|---|
| モノリス | 高 | 中 | 高 | 低 |
| レイヤード | 中 | 高 | 高 | 低 |
| クリーン/ヘキサゴナル | 低 | 高 | 高 | 中 |
| マイクロサービス | 低 | 中 | 中 | 高 |
| CQRS | 中 | 中 | 高 | 中 |
| イベント駆動 | 中 | 中 | 中 | 高 |
信頼性・可用性
| アーキテクチャ | 障害の影響範囲 | 復旧の複雑さ | データ整合性 |
|---|---|---|---|
| モノリス | 全体(単一障害点) | 低 | 高(ACID) |
| マイクロサービス | 部分的 | 高(分散) | 中(結果整合性) |
| イベント駆動 | 部分的(隔離) | 中(DLQ) | 中(結果整合性) |
| サーバーレス | 部分的 | 低(自動復旧) | 中(冪等性必要) |
チーム規模による選定
1-5人チーム
推奨: モノリス + レイヤードアーキテクチャ
理由:
- 全員がコードベース全体を把握できる
- デプロイパイプラインがシンプル
- コミュニケーションコストが低い
- 機能のPivotが容易
避けるべき:
- マイクロサービス(運用コストが開発コストを上回る)
- 過度なクリーンアーキテクチャ(オーバーエンジニアリング)
5-20人チーム
推奨: モジュラーモノリス + ヘキサゴナルアーキテクチャ
外部連携系はサーバーレス・イベント駆動を部分採用
理由:
- 機能ドメインごとのチーム分割が始まる
- 単一デプロイは維持したい
- テスト自動化の重要性が増す
移行の目安:
- デプロイが週1回以上になる
- コードレビューがボトルネックになる
20-50人チーム
推奨: ドメイン境界でのサービス分割
CQRS(高トラフィック機能)
イベント駆動(サービス間連携)
理由:
- チームがドメインオーナーシップを持つ
- 独立したデプロイが必要
- パフォーマンス要件が厳しくなる
50人以上
推奨: フルマイクロサービス or セルアーキテクチャ
プラットフォームチームが必要
注意:
- Conway's Law: 組織構造がアーキテクチャを決める
- Platform Engineering への投資が必須
ドメイン特性による選定
複雑さの評価マトリクス
# アーキテクチャ選定のヒューリスティック
class ArchitectureSelector
CRITERIA = {
team_size: {
small: (1..10),
medium: (10..50),
large: (50..)
},
domain_complexity: [:simple, :moderate, :complex],
scale_requirement: [:low, :medium, :high],
reliability_requirement: [:standard, :high, :critical]
}
def recommend(team_size:, domain_complexity:, scale:, reliability:)
score = {}
score[:monolith] = score_monolith(team_size, domain_complexity, scale)
score[:modular_monolith] = score_modular_monolith(team_size, domain_complexity)
score[:microservices] = score_microservices(team_size, scale, reliability)
score[:event_driven] = score_event_driven(reliability, scale)
score.max_by { |_, v| v }.first
end
private
def score_monolith(team_size, domain_complexity, scale)
score = 0
score += 30 if team_size <= 10
score += 20 if domain_complexity == :simple
score -= 20 if scale == :high
score -= 10 if domain_complexity == :complex
score
end
# ... 他のスコアリング
end実践的な選定フレームワーク
カオリが作成した「アーキテクチャ選定チェックリスト」。
ステップ1: 要求の整理
□ 機能要件: 何をするシステムか
□ 非機能要件: 性能・可用性・スケール
□ チーム規模と習熟度
□ 運用の能力(DevOpsチームの有無)
□ タイムラインと予算
ステップ2: 制約の確認
□ 既存システムとの統合要件
□ コンプライアンス・セキュリティ要件
□ データ整合性の要件(ACID vs 結果整合性)
□ デプロイ頻度の要件
ステップ3: 候補の選定
□ 現在の文脈で最もシンプルな選択肢は何か
□ 将来の要件変化にどう対応するか
□ 廃棄コストはどのくらいか(間違えたとき)
ステップ4: トレードオフの評価
□ 各候補のメリット・デメリットを列挙
□ チームが理解・運用できるか
□ 監視・デバッグの難易度
ステップ5: 決定と記録
□ ADRに選定理由を記録する
□ 検討したが却下した選択肢も記録する
□ 見直しのタイミングを設定する
ADR(アーキテクチャ決定記録)
カオリが書いたADRの実例。
# ADR-001: アーキテクチャをモジュラーモノリスにする
## ステータス
採用済み(2024-01-15)
## 文脈
新規ECプラットフォームの立ち上げ。
チーム: 6名(フロントエンド2名、バックエンド3名、インフラ1名)
タイムライン: 3ヶ月でβリリース
初年度目標: 10万ユーザー、3年後: 100万ユーザー
## 検討した選択肢
### 選択肢A: 純粋なモノリス
- 開発速度が最高
- スケール限界が早い
- 将来の分割が困難
### 選択肢B: モジュラーモノリス(採用)
- 開発速度が高い(単一デプロイ)
- 将来のサービス分割のための境界を維持
- Rails Enginesでモジュール境界を強制
### 選択肢C: マイクロサービス
- 6人チームには運用コストが高すぎる
- インフラの複雑さがプロダクト開発を圧迫する
## 決定
選択肢Bを採用する。
## 理由
- 現在のチーム規模(6名)にはモノリスが適切
- 3ヶ月のタイムラインにはシンプルな構成が必要
- ただし純粋なモノリスでは将来の分割が困難になるため、
Rails Enginesでモジュール境界を強制するモジュラーモノリスを採用
- 初年度10万ユーザーはモノリスで十分対応可能
## 見直しのトリガー
以下のいずれかが発生した場合、マイクロサービスへの移行を検討する:
- チームが15名を超えた
- 月間アクティブユーザーが50万を超えた
- 特定のモジュールが他と著しく異なるスケール要件を持つようになった
- デプロイ頻度が週10回を超え、モジュール間の衝突が問題になった
## 結果(記入予定)
6ヶ月後に振り返る。カオリの選択
CTOに向けて、カオリは最終設計を説明した。
「現在のアーキテクチャはモジュラーモノリスを中心とし、イベント発行でLambda群と疎結合に連携します。将来、特定のモジュール(例: 在庫管理)がスケール限界に達した時点で、そのモジュールだけをマイクロサービスとして切り出す計画です」
「なぜマイクロサービスにしなかったのか?」CTOが聞いた。
「6人のチームに対して、マイクロサービスの運用コストは過剰でした。ただし将来の分割を意識して、モジュール間の依存関係を厳密にコントロールしています。Rails Engineとサービスオブジェクトの境界を越えた直接呼び出しは禁止しています」
「なぜクリーンアーキテクチャにしなかったのか?」
「3ヶ月でβリリースするには、全てのユースケースにClean Architectureを適用する時間がありませんでした。ただし、外部依存が多い決済・メール送信はヘキサゴナルアーキテクチャで実装し、テスト可能にしています。残りはシンプルなサービスオブジェクトパターンです」
CTOはうなずいた。「合理的だ。段階的な選択が見える」
INFO
アーキテクチャは一度決めたら変えられないものではありません。「今の文脈での最適解」を選び、見直しのタイミングを明示的に決めておくことが、長期的な成功の鍵です。
アンチパターン集
カオリが「絶対にやってはいけない」リスト。
❌ 憧れアーキテクチャ症候群
→ NetflixやGoogleが使っているから、という理由だけで採用
→ 文脈が全く違う。彼らが直面した問題を、あなたはまだ直面していない
❌ 最初からマイクロサービス
→ 「前提のないマイクロサービスは分散モノリスになる」
→ ドメイン境界が明確になってから分割するのが正解
❌ 共有ライブラリでの隠れた結合
→ マイクロサービスなのに全サービスが同じDBモデルライブラリに依存
→ これはマイクロサービスではなく、分散モノリスだ
❌ ドキュメントなしの「進化」
→ 「いつの間にかそうなっていた」
→ ADRで決定を記録する習慣がなければ、アーキテクチャは腐食する
❌ チームへの説明なし
→ アーキテクトだけが理解している設計
→ 全員が理解・議論できる設計だけが生き残る
次章(最終章)では、「アーキテクチャは進化する」というテーマで、段階的な移行と技術的負債の管理を学ぶ。カオリのプロジェクトがどう成長していくか、エピローグで見届けよう。