EXERCISE 60分

ストーリー

佐藤CTO
理論は十分だ。ここからは実際のモノリスを分析してみよう
佐藤CTO
移行を提案するには、まず現状の問題を定量的に示す必要がある。感覚ではなくデータで語れるようになろう

ミッション概要

ミッションテーマ目安時間
Mission 1モノリスのアンチパターン特定15分
Mission 2技術的負債ヒートマップ作成15分
Mission 3モジュール間依存グラフの作成15分
Mission 4移行アセスメントレポート作成15分

前提シナリオ

あなたは大規模ECプラットフォーム「ShopMaster」のテックリードです。このシステムは5年前にRuby on Railsのモノリスとして構築され、現在以下の状況です:

  • コードベース: 約50万行
  • デプロイ頻度: 月2回(リリーストレイン方式)
  • チーム: 8チーム40名が同一リポジトリで開発
  • DB: 単一のPostgreSQLインスタンス(300テーブル以上)
  • 平均ビルド時間: 45分
  • テストスイート実行時間: 2時間
  • 障害時の平均復旧時間(MTTR): 4時間

Mission 1: モノリスのアンチパターン特定(15分)

要件

ShopMasterのコードベースから以下のアンチパターンを特定し、影響度と改善優先度を評価してください。

graph TD
    Root["ShopMaster/"] --> App["app/"]
    App --> Models["models/"]
    App --> Ctrl["controllers/"]
    App --> Svc["services/"]
    App --> Jobs["jobs/"]
    Models --> M1["order.rb\n2,800行 / 35メソッド"]
    Models --> M2["product.rb\n1,500行 / 22メソッド"]
    Models --> M3["user.rb\n1,200行 / 18メソッド"]
    Models --> M4["payment.rb\n900行 / Stripe API直接コール"]
    Ctrl --> API["api/v1/"]
    API --> C1["orders_controller.rb\n500行 / 在庫・決済・通知を直接呼出"]
    Svc --> S1["order_service.rb\n800行 / 他サービス直接参照"]
    Svc --> S2["payment_service.rb\n600行 / 循環依存あり"]
    Svc --> S3["notification_service.rb\n全サービスから直接呼出"]
    Jobs --> J1["order_sync_job.rb\n外部API / リトライロジック散在"]

    style Root fill:#1e293b,stroke:#475569,color:#f8fafc
    style App fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style Models fill:#f3e8ff,stroke:#7c3aed,color:#5b21b6
    style Ctrl fill:#f3e8ff,stroke:#7c3aed,color:#5b21b6
    style Svc fill:#f3e8ff,stroke:#7c3aed,color:#5b21b6
    style Jobs fill:#f3e8ff,stroke:#7c3aed,color:#5b21b6
    style API fill:#f3f4f6,stroke:#9ca3af,color:#374151
    style M1 fill:#fee2e2,stroke:#dc2626,color:#991b1b
    style M2 fill:#fef3c7,stroke:#d97706,color:#92400e
    style M3 fill:#d1fae5,stroke:#059669,color:#065f46
    style M4 fill:#fee2e2,stroke:#dc2626,color:#991b1b
    style C1 fill:#fee2e2,stroke:#dc2626,color:#991b1b
    style S1 fill:#fee2e2,stroke:#dc2626,color:#991b1b
    style S2 fill:#fee2e2,stroke:#dc2626,color:#991b1b
    style S3 fill:#fef3c7,stroke:#d97706,color:#92400e
    style J1 fill:#fef3c7,stroke:#d97706,color:#92400e
解答例
アンチパターン箇所影響度優先度
God Objectorder.rb(2,800行)1
循環依存order_service ↔ payment_service1
密結合orders_controller が在庫・決済・通知を直接呼出2
Shared DB依存300テーブルが単一DBに集中2
横断的関心事の散在notification_serviceが全箇所から直接呼出3
インフラ依存混入payment.rbにStripe APIコールが直接記述3
リトライロジック散在order_sync_jobにリトライが直書き4

影響分析:

  • God Object(order.rb): 変更のたびに予期しない副作用が発生。8チーム中6チームがこのファイルを日常的に変更し、マージコンフリクトが週平均12件発生。
  • 循環依存: テストの独立実行が不可能。order_serviceのテストにpayment_serviceのモックが必須で、テスト実行時間の30%を占める。
  • Shared DB: スキーマ変更が全チームに影響。カラム追加でも全チームの承認が必要で、リードタイム平均2週間。

Mission 2: 技術的負債ヒートマップ作成(15分)

要件

以下のメトリクスを使用して、ShopMasterの技術的負債ヒートマップを作成してください。

変更頻度(過去6ヶ月のコミット数):
  order.rb: 342
  product.rb: 156
  user.rb: 89
  payment.rb: 201
  orders_controller.rb: 178
  order_service.rb: 234
  payment_service.rb: 198

バグ発生数(過去6ヶ月):
  order.rb: 28
  product.rb: 8
  user.rb: 4
  payment.rb: 15
  orders_controller.rb: 12
  order_service.rb: 19
  payment_service.rb: 16

循環的複雑度(平均):
  order.rb: 45
  product.rb: 18
  user.rb: 12
  payment.rb: 32
  orders_controller.rb: 25
  order_service.rb: 38
  payment_service.rb: 29
解答例

技術的負債スコア = 変更頻度 × バグ率 × 複雑度係数

ファイル変更頻度バグ率複雑度係数負債スコアリスクレベル
order.rb3428.2%2.2563.1🔴 Critical
order_service.rb2348.1%1.9036.0🔴 Critical
payment_service.rb1988.1%1.4523.2🟠 High
payment.rb2017.5%1.6024.1🟠 High
orders_controller.rb1786.7%1.2514.9🟡 Medium
product.rb1565.1%0.907.2🟢 Low
user.rb894.5%0.602.4🟢 Low

ヒートマップの解釈:

graph TD
    subgraph HH["高バグ率 × 高変更頻度\n最優先で分割"]
        A1["order.rb\norder_svc"]
    end
    subgraph HL["高バグ率 × 低変更頻度"]
        A2["payment.rb\npayment_svc"]
    end
    subgraph LH["低バグ率 × 高変更頻度\n次フェーズで対応"]
        A3["orders_controller"]
    end
    subgraph LL["低バグ率 × 低変更頻度\n現状維持可"]
        A4["product.rb"]
        A5["user.rb"]
    end

    style HH fill:#fee2e2,stroke:#dc2626,stroke-width:3px,color:#991b1b
    style HL fill:#fef3c7,stroke:#d97706,stroke-width:2px,color:#92400e
    style LH fill:#fef3c7,stroke:#d97706,color:#92400e
    style LL fill:#d1fae5,stroke:#059669,color:#065f46
    style A1 fill:#fee2e2,stroke:#dc2626,color:#991b1b
    style A2 fill:#fef3c7,stroke:#d97706,color:#92400e
    style A3 fill:#fef3c7,stroke:#d97706,color:#92400e
    style A4 fill:#d1fae5,stroke:#059669,color:#065f46
    style A5 fill:#d1fae5,stroke:#059669,color:#065f46

推奨アクション: order.rb と order_service.rb を最優先で分割。この2ファイルだけでバグの47%、マージコンフリクトの60%を占めている。


Mission 3: モジュール間依存グラフの作成(15分)

要件

ShopMasterの主要モジュール間の依存関係を可視化し、結合度を評価してください。

解答例

依存グラフ:

graph TD
    OM["Order<br/>Model"] --> OS["OrderService"]
    OS --> PS["PaymentSvc<br/>(循環依存!)"]
    PS --> OS
    OM --> NS["NotificationService<br/>(全サービスから直接依存)"]
    OS --> IS["InventorySvc"]
    OS --> NS
    IS --> NS
    PS --> NS
    OM --> DB["PostgreSQL(単一DB)<br/>300テーブル、全モジュールが共有"]
    OS --> DB
    IS --> DB
    PS --> DB
    NS --> DB

    classDef danger fill:#fee,stroke:#c33,color:#333
    classDef warning fill:#fff3cd,stroke:#f0ad4e,color:#333
    classDef db fill:#e8f4fd,stroke:#2196f3,color:#333
    class PS danger
    class NS warning
    class DB db

結合度メトリクス:

モジュールペア結合タイプ結合度問題点
OrderSvc ↔ PaymentSvc循環依存極高テスト・デプロイが独立不可
全モジュール → NotificationSvcスタンプ結合通知変更が全体に波及
全モジュール → PostgreSQL共有DB結合スキーマ変更の影響大
Order → Inventoryデータ結合在庫確認のためのSQL JOIN

凝集度評価:

モジュール凝集度理由
Order低(論理的凝集)注文・カート・返品・レビューが混在
Payment中(機能的凝集)決済処理に集中だがStripe直結
User高(機能的凝集)ユーザー管理に集中

Mission 4: 移行アセスメントレポート作成(15分)

要件

上記の分析結果をもとに、マイクロサービス移行のアセスメントレポートを作成してください。

解答例
# ShopMaster マイクロサービス移行アセスメントレポート

## 1. エグゼクティブサマリー

ShopMasterは5年間の成長により、モノリスの限界に達している。
デプロイ頻度(月2回)がビジネス要求(週次リリース)に追いつかず、
障害復旧時間(4時間)がSLO(30分)を大幅に超過している。

移行推奨度: ★★★★☆(強く推奨)

## 2. 現状の問題(定量データ)

| 指標 | 現状 | 目標 | ギャップ |
|------|------|------|---------|
| デプロイ頻度 | 月2回 | 週1回以上 | 2倍以上 |
| ビルド時間 | 45分 | 10分以内 | 4.5倍 |
| テスト時間 | 2時間 | 20分以内 | 6倍 |
| MTTR | 4時間 | 30分 | 8倍 |
| マージコンフリクト | 週12件 | 週2件以下 | 6倍 |

## 3. 移行の推奨フェーズ

### Phase 1(3ヶ月): Strangler Fig開始
- NotificationServiceをイベント駆動に分離
- APIゲートウェイの導入
- CI/CDパイプラインの分離準備

### Phase 2(6ヶ月): コアサービス分離
- Order/Payment の循環依存解消
- Orderサービスの独立(DB分離含む)
- Paymentサービスの独立

### Phase 3(6ヶ月): 完全移行
- 残りモジュールの段階的分離
- 共有DBの完全分離
- モノリスの廃止

## 4. リスク評価

| リスク | 影響度 | 発生確率 | 対策 |
|--------|--------|---------|------|
| データ整合性の喪失 | 高 | 中 | Sagaパターン導入 |
| 運用複雑度の増大 | 中 | 高 | SREチーム組成 |
| チームスキル不足 | 中 | 中 | 段階的研修 |

## 5. 必要リソース

- 専任移行チーム: 5名 × 15ヶ月
- インフラ追加コスト: 月額約50万円増
- 研修コスト: 約200万円

まとめ

ポイント内容
アンチパターン定量データで問題を特定する
ヒートマップ変更頻度×バグ率×複雑度で優先度を決める
依存グラフ結合度と凝集度を可視化する
アセスメント現状・目標・ギャップを定量的に示す

チェックリスト

  • モノリスのアンチパターンを3つ以上特定できた
  • 技術的負債ヒートマップを作成できた
  • モジュール間の依存関係を図示できた
  • 移行アセスメントレポートを作成できた

次のステップへ

次はチェックポイントクイズでモノリス分析の理解度を確認します。


推定読了時間: 60分