LESSON 40分

ストーリー

佐藤CTO
System Contextが描けた。次は内部のサービス分解だ。C4 Level 2のContainer Diagramを作る

佐藤CTOが続けます。

佐藤CTO
NexPayの最大のアーキテクチャ判断は、どのサービスをどう分割するかだ。分割が粗すぎればモノリスの問題が再発する。細かすぎれば分散システムの複雑性に溺れる。DDDの境界づけられたコンテキストを軸に、チーム構成と整合する分割を設計する

DDDベースのサービス分解

ドメインイベントストーミング結果

イベントストーミングで洗い出したドメインイベントから、サービス境界を導出します。

決済ドメイン:                    送金ドメイン:
  決済リクエスト受信               送金リクエスト受信
  与信確認完了                    送金元残高確認完了
  決済承認完了                    送金実行完了
  売上確定完了                    送金受取通知送信
  加盟店入金完了                   銀行API送金完了
  ポイント付与完了

投資ドメイン:                    アカウントドメイン:
  注文受付完了                    ユーザー登録完了
  約定完了                       KYC審査完了
  ポートフォリオ更新完了             残高更新完了
  配当受取完了                    ポイント残高更新完了
  つみたて実行完了                 出金リクエスト受信

サービス一覧

サービス名境界づけられたコンテキスト責務担当チーム
Payment Service決済コンテキストQR/NFC/オンライン決済の処理決済チーム(12名)
Settlement Service精算コンテキスト加盟店精算、入金管理決済チーム
Transfer Service送金コンテキストP2P送金、銀行振込送金チーム(8名)
Investment Service投資コンテキスト株式/投信の注文・約定投資チーム(8名)
Account Serviceアカウントコンテキストユーザー管理、残高管理共通基盤チーム(8名)
KYC Service本人確認コンテキストKYC/AML処理共通基盤チーム
Notification Service通知コンテキストプッシュ通知、メール、SMS共通基盤チーム
API Gateway外部公開コンテキスト認証、ルーティング、レート制限SREチーム(6名)

C4 Level 2: Container Diagram

graph TD
    subgraph Clients["クライアント"]
        MOB["Mobile App<br/>(iOS/Android)"]
        WEB["Merchant Dashboard<br/>(Web)"]
    end

    MOB --> GW["API Gateway<br/>(Kong/Envoy)"]
    WEB --> GW

    subgraph Mesh["Service Mesh (Istio/Linkerd)"]
        PAY["Payment<br/>Service"] <--> ACC["Account<br/>Service"]
        ACC <--> TRF["Transfer<br/>Service"]
        SET["Settlement<br/>Service"]
        KYC["KYC<br/>Service"]
        INV["Investment<br/>Service"]
    end

    GW --> Mesh
    NOTIF["Notification<br/>Service"]

    subgraph EventBus["Event Bus (Kafka)"]
        KAFKA["Kafka"]
    end

    subgraph DataStores["データストア"]
        PDB["Payment DB<br/>(Aurora)"]
        ADB["Account DB<br/>(Aurora)"]
        TDB["Transfer DB<br/>(Aurora)"]
        IDB["Invest DB<br/>(Aurora)"]
    end

    PAY --> PDB
    ACC --> ADB
    TRF --> TDB
    INV --> IDB

    classDef client fill:#9b59b6,stroke:#8e44ad,color:#fff
    classDef gateway fill:#e67e22,stroke:#d35400,color:#fff
    classDef service fill:#3498db,stroke:#2980b9,color:#fff
    classDef infra fill:#27ae60,stroke:#1e8449,color:#fff
    classDef db fill:#2c3e50,stroke:#1a252f,color:#fff
    class MOB,WEB client
    class GW gateway
    class PAY,ACC,TRF,SET,KYC,INV,NOTIF service
    class KAFKA infra
    class PDB,ADB,TDB,IDB db

サービス間通信の設計

同期 vs 非同期の判断基準

通信パターン採用基準NexPayでの適用例
同期(REST/gRPC)リアルタイム応答が必要、強整合性決済処理、残高照会、KYC確認
非同期(イベント)結果整合性で十分、デカップリングポイント付与、通知送信、精算処理
コレオグラフィサービス間の疎結合が重要決済完了→ポイント付与→通知
オーケストレーション複雑なワークフロー管理送金フロー(KYC→残高確認→送金→通知)

決済フローの詳細設計

// 決済フロー: 同期 + 非同期のハイブリッド
interface PaymentFlow {
  // Phase 1: 同期処理(ユーザー待機)
  synchronousPhase: {
    step1: "API Gateway → Payment Service: 決済リクエスト受信";
    step2: "Payment Service → Account Service: 残高/与信確認(gRPC、50ms以内)";
    step3: "Payment Service → Card Network: 与信承認(ISO 8583、200ms以内)";
    step4: "Payment Service → Account Service: 残高引落(gRPC、50ms以内)";
    step5: "Payment Service → API Gateway: 決済完了レスポンス";
    totalLatency: "p99 < 800ms";
  };

  // Phase 2: 非同期処理(バックグラウンド)
  asynchronousPhase: {
    event1: "PaymentCompleted → PointService: ポイント付与";
    event2: "PaymentCompleted → NotificationService: 決済通知送信";
    event3: "PaymentCompleted → SettlementService: 精算データ蓄積";
    event4: "PaymentCompleted → AnalyticsService: 分析データ送信";
    event5: "PaymentCompleted → AMLMonitor: 不正検知チェック";
  };
}

Saga パターンによる送金フロー

graph LR
    KYC["1. KYC確認"] --> BAL["2. 残高確認"]
    BAL --> TRF["3. 送金実行"]
    TRF --> NTF["4. 通知送信"]
    KYC -- "失敗" --> REJ1["送金拒否
理由通知"] BAL -- "失敗" --> REJ2["送金拒否
残高不足通知"] TRF -- "失敗" --> COMP["補償TX
残高戻し"] style KYC fill:#dbeafe,stroke:#2563eb,stroke-width:2px,color:#1e40af style BAL fill:#dbeafe,stroke:#2563eb,stroke-width:2px,color:#1e40af style TRF fill:#dbeafe,stroke:#2563eb,stroke-width:2px,color:#1e40af style NTF fill:#d1fae5,stroke:#059669,color:#065f46 style REJ1 fill:#fee2e2,stroke:#dc2626,color:#991b1b style REJ2 fill:#fee2e2,stroke:#dc2626,color:#991b1b style COMP fill:#fef3c7,stroke:#d97706,stroke-width:2px,color:#92400e

サービスのAPI設計

API設計原則

API設計原則:
  バージョニング: URLパスベース(/v1/payments)
  認証: OAuth 2.0 + JWT(内部はサービスメッシュのmTLS)
  レート制限: サービスごとに個別設定
  冪等性: すべての書き込みAPIに冪等性キーを要求
  エラーレスポンス: RFC 7807(Problem Details)準拠
  ページネーション: カーソルベース(大量データ対応)

主要APIのインターフェース

// Payment API
interface PaymentAPI {
  // 決済作成(冪等性キー必須)
  createPayment(request: {
    idempotencyKey: string;
    merchantId: string;
    amount: Money;
    paymentMethod: PaymentMethod;
    metadata?: Record<string, string>;
  }): Promise<PaymentResponse>;

  // 決済照会
  getPayment(paymentId: string): Promise<Payment>;

  // 決済取消(冪等性キー必須)
  cancelPayment(paymentId: string, request: {
    idempotencyKey: string;
    reason: CancelReason;
  }): Promise<CancelResponse>;
}

// 冪等性の実装
class IdempotencyGuard {
  async execute<T>(
    key: string,
    operation: () => Promise<T>,
  ): Promise<T> {
    const existing = await this.cache.get(key);
    if (existing) {
      return existing as T; // 同じレスポンスを返す
    }

    const result = await operation();
    await this.cache.set(key, result, { ttl: 86400 }); // 24h保持
    return result;
  }
}

「決済APIの冪等性は絶対に妥協できない。ネットワーク障害でリトライされた場合に二重決済が発生したら、ユーザーの信頼を完全に失う。すべての書き込みAPIに冪等性キーを要求する設計にしろ」 — 佐藤CTO


チーム構成とサービスの整合(逆コンウェイ)

チーム-サービスマッピング

コンウェイの法則を意識し、チーム構成とサービス境界を整合させます。

チーム担当サービスオーナーシップ認知負荷
決済チーム(12名)Payment, SettlementFull ownership
送金チーム(8名)TransferFull ownership
投資チーム(8名)InvestmentFull ownership
共通基盤チーム(8名)Account, KYC, NotificationFull ownership
SREチーム(6名)API Gateway, Event Bus, InfraPlatform team
共通基盤チームの認知負荷対策

共通基盤チームは3サービスを担当しており認知負荷が高いため、以下の対策を実施します。

  1. Account Serviceを最優先に開発(他チームの依存先)
  2. KYC Serviceは外部サービスのラッパーとして薄く実装
  3. Notification Serviceはイベント駆動で疎結合に設計し、メンテナンス負荷を最小化
  4. チーム拡大時(60名規模)にNotification Serviceを独立チームに移管

まとめ

ポイント内容
サービス分解DDDの境界づけられたコンテキストに基づく8サービス
通信設計同期(リアルタイム処理)+ 非同期(イベント駆動)のハイブリッド
Saga送金フローはオーケストレーション型Sagaで整合性を担保
API設計冪等性キー必須、OAuth 2.0、RFC 7807エラー形式
チーム整合逆コンウェイの法則でチームとサービス境界を一致

チェックリスト

  • 8サービスの責務と境界を理解した
  • 同期/非同期の使い分け判断基準を把握した
  • 決済フローの同期+非同期ハイブリッド設計を理解した
  • Sagaパターンによる分散トランザクション管理を理解した
  • チーム構成とサービス境界の整合を確認した

次のステップへ

次は「データアーキテクチャ設計」に進みます。各サービスのデータベース選定、イベントソーシング、CQRSの適用を設計しましょう。


推定読了時間: 40分