目次を表示する

共通基盤の設計軸 2026 ─ 抽象・責務・非機能要件を設計する 15 章

進化と保守 ─ Versioning / Deprecation / Migration

進化と保守 ─ Versioning / Deprecation / Migration

共通基盤は 長く生きる。3 年後、5 年後、10 年後にも動いている前提で API を設計する必要がある。だが要件は変わるし、技術も古びる。変えながら壊さない 作法が要る。

この章では Stripe を主役に進化の 3 段階 ── Versioning / Deprecation / Migration ── を扱う。

Versioning:日付ベースか path ベースか

第 5 章でも触れた、API のバージョニング戦略。

Path ベース(一般的)

POST /v1/payments
POST /v2/payments  # 互換性 break するときに新版

pros: シンプル、URL で分かる cons: client が手動で /v2 に移行する必要、互換性のない 2 つの実装を保守

日付ベース(Stripe 流)

POST /payments
Stripe-Version: 2024-04-10

Stripe API Versioning の核心:

  • 各 version は backward-incompatible だが increment は 小さい
  • 初回 API call で 自動 pin される(client は明示しなくていい)
  • Compatibility Layer が version 間を変換する

Stripe の Compatibility Layer

Stripe Engineering “APIs as infrastructure” の解説:

内部のビジネスロジックは 常にモダンな format で書く。version 別の処理は entry/exit のレイヤーに隔離する。

graph TB
  C1[Client v2024-04-10]
  C2[Client v2024-08-01]
  C3[Client v2025-12-01]

  C1 --> R[Request Layer]
  C2 --> R
  C3 --> R

  R -->|変換: 古い → モダン| Core[Modern Core Logic]

  Core -->|変換: モダン → 古い| Resp[Response Layer]

  Resp --> C1
  Resp --> C2
  Resp --> C3

  style Core fill:#e1f5ff
  style R fill:#fff4e1
  style Resp fill:#fff4e1

これにより:

  • コアロジックは 1 つ、version の差分は薄いレイヤー
  • 新 version 追加は 薄いレイヤーを 1 枚足す だけ
  • 古い version の維持コストは増えるが、コアは綺麗

どちらを選ぶか

場面推奨
短命な API(数年)Path-based v1 / v2
長命な API(5 年〜)Date-based
内部基盤(社内利用)Path-based で十分
外部公開(Stripe / Twilio など)Date-based

後方互換性の “聖戦”

守るべきルール(再確認)

第 5 章で挙げたが、進化の文脈で再確認:

操作互換性
Optional field 追加OK
Required field 追加NG
Field 削除NG
型変更NG
Enum 値追加注意(client が unknown を扱える前提)
Enum 値削除NG
Endpoint 追加OK
Endpoint 削除段階的 deprecate

足すは OK、引くは NG」が原則。

Schema Registry の活用

Avro / Protobuf を使う基盤(Kafka 等)では Schema Registry で機械的に互換性を検証:

# Compatibility check
- BACKWARD: 新 schema で書いた message を古い schema で読める
- FORWARD: 古い schema で書いた message を新 schema で読める
- FULL: 両方

CI で互換性違反を検出して push 前に止める。

Deprecation の作法

機能を削除したいとき、いきなり消さない。段階的なプロセスを踏む。

業界標準のフロー

graph LR
  A[Stage 1: Deprecation 通知] --> B[Stage 2: 警告ヘッダー]
  B --> C[Stage 3: Brownout]
  C --> D[Stage 4: Sunset]

  Note1[最低 1 年は維持]

  style A fill:#e1ffe1
  style D fill:#ffe1e1

Stage 1: Deprecation 通知

HTTP/1.1 200 OK
Sunset: Sat, 31 Dec 2026 23:59:59 GMT
Deprecation: Sat, 9 May 2026 00:00:00 GMT
Link: <https://platform.example.com/docs/migration>; rel="deprecation"

Sunset / Deprecation ヘッダー(RFC 9745)で予告。

メール / Slack / 管理画面でも通知。気付かせる のが目的。

Stage 2: 警告ヘッダー(数ヶ月)

HTTP/1.1 200 OK
Warning: 299 - "This endpoint is deprecated, will be removed on 2026-12-31"

利用者の中で意識が広がる時期。

Stage 3: Brownout(一時停止)

Day 1: 1 分間だけ 410 Gone を返す
Week 2: 1 時間だけ 410
Week 4: 1 日だけ 410
最終週: 半分の時間 410

完全停止前に “予告停電” を入れる。利用者が「あ、ヤバい、移行しなきゃ」と気付く効果。Stripe / GitHub が実際に使う手法。

Stage 4: Sunset(停止)

HTTP/1.1 410 Gone
{
  "error": {
    "type": "endpoint_removed",
    "code": "ENDPOINT_REMOVED",
    "message": "This endpoint was removed on 2026-12-31. Migration: ..."
  }
}

完全停止。それでも一定期間は 410 Gone を返す ことで、利用者が原因を分かるようにする。

Deprecation 期間の目安

利用者規模期間
内部利用(10 サービス未満)3-6 ヶ月
内部基盤(数十サービス)6 ヶ月-1 年
外部公開(数千 client)1-2 年
Critical(金融など)2-3 年

「短すぎる」と利用者が間に合わない。「長すぎる」と保守コストが膨らむ。バランスは利用者の規模で決まる。

Migration の Heroic Effort

自動移行」が理想だが、現実は難しい。

自動移行できる場合

Brandur “Why Doesn’t Stripe Automatically Upgrade API Versions?” の論点:

利用者が呼んでいる endpoint と、新 version で変わる endpoint が 完全に重ならない 場合は、自動的に上げて良い。

例:「v2 では /payments/refund が変わるが、利用者は /payments しか叩いていない」→ 自動的に v2 に pin する。

自動移行できない場合

ほとんどの基盤は client コードの 書き換えが必要。これを支援するツール:

  • Codemod(jscodeshift など):自動コード書き換え
  • Migration guide:step-by-step ドキュメント
  • Migration Office Hours:チャット / 会議で支援
  • Lint rule:旧 API を warning で検知

Stripe の “Migration Tool”

Stripe API upgrades は Web UI 上で:

  • 自分が pin している version
  • 最新 version との差分
  • 各差分が自分のコードに影響するか
  • 推奨 migration step

機械的に決まることは機械にやらせる」のが共通基盤の責任。

Sunset Policy ─ 何年で消すか

# Stripe の例(実際)
- Stripe-Version より古い 1 つは維持
- 1 年以上経つと automatic upgrade を提案
- 数年で完全 sunset

# 内部基盤の例
- 旧 version は最低 1 年維持
- 利用者数 < 5 なら個別に migrate 支援
- > 100 利用者がいれば 2 年維持

Sunset policy は文書化 して公開する。利用者が長期計画を立てられるようにする。

進化のアンチパターン

❌ Big Bang Rewrite

「v2 で全部作り直す」と決める → 利用者の移行が間に合わない / 新版にもバグ → 1-2 年で破綻

❌ Forever Backward Compat

「絶対互換性を保つ」と決める → 進化できない / コードが負債で埋まる / 新規利用者が辛い

❌ Silent Removal

通知なく機能削除 → 利用者の信頼を失う

❌ 説明のない Deprecation

「これは deprecated です」とだけ書いて代替を示さない → 利用者が困惑

進化のチェックリスト

graph TB
  Q1[Versioning 戦略] --> Q2[後方互換ルール]
  Q2 --> Q3[Schema 自動検証]
  Q3 --> Q4[Deprecation プロセス]
  Q4 --> Q5[Migration 支援]
  Q5 --> Q6[Sunset Policy 文書化]
  Q6 --> OK[進化を続けられる]

  style OK fill:#e1ffe1

この章の要点

  • Versioning:日付ベース(Stripe 流)vs path ベース、長命なら日付
  • Stripe の Compatibility Layer:内部はモダン、変換は entry/exit に隔離
  • 後方互換性:足すは OK、引くは NG
  • Schema Registry で機械的に互換性検証
  • Deprecation は 4 段階:通知 / 警告ヘッダー / Brownout / Sunset
  • 期間目安:内部 3-6 ヶ月、外部 1-2 年
  • Migration 支援:codemod / guide / office hours / lint
  • Sunset Policy を文書化、信頼の根拠
  • アンチパターン:Big Bang / Forever Compat / Silent Removal / 説明なし Deprecate

次章への問いかけ

進化を支えるのは 利用者の協力。だが利用者は文書を読まない、移行を後回しにする。

次章で 利用者の認知負荷を下げる ── Golden Path / SDK / Self-service / Documentation。