mybook

アーキテクチャの比較と選定 — トレードオフを見極める

選定の日

プロジェクト開始から3ヶ月。βリリースまであと1週間。CTOから「最終アーキテクチャレビュー」の招集がかかった。

会議室にはCTO・テックリード・エンジニア6人が集まっている。カオリは自分が設計したアーキテクチャを説明する番だ。

「これまで多くのパターンを学んだ。なぜ今の設計を選んだか、何を捨てたか、何を将来に残したか、説明します」

INFO

アーキテクチャ選定は「最高の答え」を探すのではなく、「今の文脈で最も少ない問題を持つ答え」を選ぶことです。全てのトレードオフを言語化できることが、良いアーキテクトの条件です。

品質特性による比較

ソフトウェアアーキテクチャは、次の品質特性(Quality Attributes)に対してトレードオフを持つ。

性能・スケーラビリティ

アーキテクチャスループットレイテンシスケール難易度
モノリス中(垂直スケール)低(水平スケール可)
マイクロサービス高(機能別)中(ネットワーク遅延)
CQRS高(読み書き分離)低(読み最適化)
サーバーレス高(自動スケール)高(コールドスタート)低(自動)
イベント駆動高(非同期)中(非同期遅延)

開発・保守性

アーキテクチャ開発速度(初期)保守性(長期)テスト容易性チーム独立性
モノリス
レイヤード
クリーン/ヘキサゴナル
マイクロサービス
CQRS
イベント駆動

信頼性・可用性

アーキテクチャ障害の影響範囲復旧の複雑さデータ整合性
モノリス全体(単一障害点)高(ACID)
マイクロサービス部分的高(分散)中(結果整合性)
イベント駆動部分的(隔離)中(DLQ)中(結果整合性)
サーバーレス部分的低(自動復旧)中(冪等性必要)

チーム規模による選定

Loading diagram...

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に向けて、カオリは最終設計を説明した。

Loading diagram...

「現在のアーキテクチャはモジュラーモノリスを中心とし、イベント発行でLambda群と疎結合に連携します。将来、特定のモジュール(例: 在庫管理)がスケール限界に達した時点で、そのモジュールだけをマイクロサービスとして切り出す計画です」

「なぜマイクロサービスにしなかったのか?」CTOが聞いた。

「6人のチームに対して、マイクロサービスの運用コストは過剰でした。ただし将来の分割を意識して、モジュール間の依存関係を厳密にコントロールしています。Rails Engineとサービスオブジェクトの境界を越えた直接呼び出しは禁止しています」

「なぜクリーンアーキテクチャにしなかったのか?」

「3ヶ月でβリリースするには、全てのユースケースにClean Architectureを適用する時間がありませんでした。ただし、外部依存が多い決済・メール送信はヘキサゴナルアーキテクチャで実装し、テスト可能にしています。残りはシンプルなサービスオブジェクトパターンです」

CTOはうなずいた。「合理的だ。段階的な選択が見える」

INFO

アーキテクチャは一度決めたら変えられないものではありません。「今の文脈での最適解」を選び、見直しのタイミングを明示的に決めておくことが、長期的な成功の鍵です。

アンチパターン集

カオリが「絶対にやってはいけない」リスト。

❌ 憧れアーキテクチャ症候群
→ NetflixやGoogleが使っているから、という理由だけで採用
→ 文脈が全く違う。彼らが直面した問題を、あなたはまだ直面していない

❌ 最初からマイクロサービス
→ 「前提のないマイクロサービスは分散モノリスになる」
→ ドメイン境界が明確になってから分割するのが正解

❌ 共有ライブラリでの隠れた結合
→ マイクロサービスなのに全サービスが同じDBモデルライブラリに依存
→ これはマイクロサービスではなく、分散モノリスだ

❌ ドキュメントなしの「進化」
→ 「いつの間にかそうなっていた」
→ ADRで決定を記録する習慣がなければ、アーキテクチャは腐食する

❌ チームへの説明なし
→ アーキテクトだけが理解している設計
→ 全員が理解・議論できる設計だけが生き残る

次章(最終章)では、「アーキテクチャは進化する」というテーマで、段階的な移行と技術的負債の管理を学ぶ。カオリのプロジェクトがどう成長していくか、エピローグで見届けよう。