ストーリー
シナリオ
あなたはフードデリバリーサービス「QuickBite」のテックリードに任命されました。
現状:
- Ruby on Rails モノリス(4年目、30万行)
- チーム: 6チーム30名
- 月間アクティブユーザー: 50万人(年間2倍成長中)
- デプロイ頻度: 月1回
- 平均レスポンスタイム: 800ms(目標: 200ms)
- 注文ピーク時にDB接続プール枯渇で障害頻発
主要機能: レストラン管理、メニュー管理、注文処理、決済、配達員マッチング、リアルタイム追跡、レビュー、プロモーション
Part 1: モノリス分析と移行戦略(20分)
要件
現状のモノリスを分析し、移行の必要性とアプローチを定義してください。
解答例
問題の定量分析:
| 指標 | 現状 | 目標 | ビジネスインパクト |
|---|---|---|---|
| デプロイ頻度 | 月1回 | 週2回 | 新機能リリース遅延で競合に負ける |
| レスポンス | 800ms | 200ms | 注文完了率が15%低下 |
| MTTR | 3時間 | 15分 | ピーク障害で時間あたり500万円損失 |
| スケーラビリティ | 全体スケール | 機能別 | インフラコスト3倍超過 |
移行アプローチ: Strangler Fig + Domain-First
- APIゲートウェイを前段に配置
- ドメイン分析でサービス境界を特定
- 最もペインが大きいサービスから順に分離
- 15ヶ月計画(3フェーズ)
Part 2: DDDによるサービス境界設計(20分)
要件
QuickBiteのBounded Contextを特定し、Context Mapを作成してください。
解答例
Bounded Context:
| Context | サブドメイン | 責務 |
|---|---|---|
| Restaurant | Supporting | レストラン・メニュー管理 |
| Order | Core | 注文ライフサイクル管理 |
| Payment | Generic | 決済処理(Stripe) |
| Delivery | Core | 配達員マッチング・追跡 |
| Customer | Generic | 顧客認証・プロフィール |
| Review | Supporting | レビュー・評価 |
| Promotion | Core | クーポン・キャンペーン |
| Notification | Generic | プッシュ・SMS・メール |
Context Map:
graph TD
Rest["Restaurant"] -->|"OHS/PL"| Ord["Order"]
Ord <-->|"Partnership"| Del["Delivery"]
Ord -->|"ACL"| Pay["Payment"]
Del -->|"C/S"| Not["Notification"]
Ord <-->|"Partnership"| Pro["Promotion"]
Cust["Customer"] -->|"OHS"| All["全サービス"]
Rev["Review"] -->|"Conformist"| Rest
Core(最優先): Order, Delivery, Promotion → 配達員マッチングアルゴリズムとプロモーションが競争優位
Part 3: イベント駆動アーキテクチャ設計(20分)
要件
注文フロー(注文作成→決済→配達員マッチング→配達→完了)をイベント駆動で設計してください。
解答例
イベントフロー:
graph TD
C["Customer"] -->|"注文リクエスト"| OS["Order Service"]
OS -->|"order.created"| K1["Kafka"]
K1 --> PS["Payment Service"]
PS -->|"payment.completed"| K2["Kafka"]
K2 --> DS["Delivery Service"]
DS -->|"delivery.driver.assigned"| K3["Kafka"]
K3 --> OS2["Order Service<br/>ステータス更新"]
K3 --> N1["Notification<br/>顧客に通知"]
DS -->|"delivery.picked.up"| K4["Kafka"]
K4 --> N2["Notification<br/>料理を受け取りました"]
DS -->|"delivery.completed"| K5["Kafka"]
K5 --> OS3["Order Service<br/>注文完了"]
K5 --> P2["Payment<br/>配達員への支払い確定"]
K5 --> N3["Notification<br/>配達完了"]
Saga設計(Orchestration):
const orderSaga = {
steps: [
{ name: 'createOrder', type: 'COMPENSATABLE', compensate: 'cancelOrder' },
{ name: 'chargePayment', type: 'PIVOT' },
{ name: 'assignDriver', type: 'RETRIABLE', timeout: '5min' },
{ name: 'notifyCustomer', type: 'RETRIABLE' },
],
};
Part 4: 分散トランザクション戦略(15分)
要件
QuickBiteのデータ整合性戦略を設計してください。Outboxパターンの適用箇所も示してください。
解答例
整合性戦略:
| データ | 整合性モデル | 理由 |
|---|---|---|
| 注文状態 | 強整合性 | 顧客に正確な状態を表示 |
| 在庫(メニュー品切れ) | 結果整合性 | 数秒の遅延は許容 |
| 決済 | 強整合性(Outbox) | 二重課金防止 |
| 配達員位置 | 結果整合性 | リアルタイム追跡は近似で可 |
| レビュー | 結果整合性 | 即時反映不要 |
Outbox適用箇所:
- Order Service: 注文作成/更新時(order.created, order.updated)
- Payment Service: 決済完了時(payment.completed)
- Delivery Service: 配達員アサイン時(delivery.driver.assigned)
Part 5: 移行ロードマップ(15分)
要件
15ヶ月の移行ロードマップをフェーズごとに作成してください。
解答例
Phase 1(Month 1-4): 基盤構築
- APIゲートウェイ(Kong/Envoy)導入
- Kafka クラスタ構築
- CI/CDパイプライン整備(サービス別)
- Notification Service を最初に分離(依存少・リスク低)
- Customer Service 分離(認証基盤の独立)
Phase 2(Month 5-10): コアサービス分離
- Order Service 分離(Outboxパターン適用)
- Payment Service 分離(ACL + Stripe統合)
- Delivery Service 分離(リアルタイム追跡基盤)
- 各サービスのDB分離(CDC同期)
- サービスメッシュ(Istio)導入
Phase 3(Month 11-15): 完全移行
- Restaurant/Review/Promotion Service 分離
- モノリスの段階的縮小・廃止
- パフォーマンス最適化・チューニング
- SREプラクティス確立
- 全チーム移行完了
マイルストーン:
| Month | 成果 | 成功指標 |
|---|---|---|
| 4 | 基盤完成 | 2サービスが独立デプロイ |
| 7 | コア分離開始 | デプロイ頻度が週1回に |
| 10 | コア分離完了 | レスポンス200ms達成 |
| 15 | 完全移行 | モノリス廃止 |
まとめ
この演習で月2の全トピックを統合しました:
| Part | 活用した知識 |
|---|---|
| 1 | モノリス分析、移行判断 |
| 2 | DDD、Bounded Context、Context Mapping |
| 3 | イベント駆動、Saga |
| 4 | 分散トランザクション、Outbox |
| 5 | 移行戦略、Strangler Fig |
チェックリスト
- モノリスの問題を定量的に分析できた
- DDDでサービス境界を設計できた
- イベント駆動のフローとSagaを設計できた
- データ整合性戦略を決定できた
- 実行可能な移行ロードマップを策定できた
次のステップへ
次は月2の卒業クイズに挑戦しましょう。
推定読了時間: 90分