メインコンテンツまでスキップ

SDK実装パターン

SDKが内部で解決する共通課題と、その実装パターンを学びます。


なぜ実装パターンを知る必要があるのか

SDKを「使う側」であっても、内部でどのような処理が行われているかを理解することで:

  • トラブルシューティングが容易になる
  • 適切な設定ができるようになる
  • パフォーマンス特性を理解できる

1. 認証・認可の扱い

SDKが解決する課題

外部サービスにアクセスする際、ほぼ必ず「あなたは誰か」を証明する必要があります。

認証なしの世界:
誰でもデータにアクセスできる → 危険

認証ありの世界:
正当なユーザーのみアクセス可能 → 安全

日常生活での例え

会員制施設の入館を考えてみましょう:

┌─────────────────────────────────────────────┐
│ 会員制フィットネスジム │
├─────────────────────────────────────────────┤
│ │
│ 利用者が毎回やること: │
│ ・会員証を見せる │
│ ・有効期限を確認される │
│ ・入館許可を得る │
│ │
│ SDKがやってくれること: │
│ ・会員証を自動で提示 │
│ ・期限切れなら自動更新 │
│ ・更新手続きも代行 │
│ │
└─────────────────────────────────────────────┘

認証情報の種類

SDKが扱う主な認証方式:

方式特徴例え
APIキー固定の文字列合鍵
トークン有効期限付き入館証(毎日発行)
OAuth権限委譲代理人証明書

SDKが内部で行う処理

┌─────────────────────────────────────────────┐
│ SDKの認証処理フロー │
├─────────────────────────────────────────────┤
│ │
│ 1. 認証情報の保持 │
│ ├── 初期化時に受け取る │
│ └── 安全に保管 │
│ │
│ 2. リクエストへの自動付与 │
│ └── 毎回のAPIコールにヘッダー追加 │
│ │
│ 3. 有効期限の管理 │
│ ├── 期限切れを検知 │
│ └── 自動で再取得(リフレッシュ) │
│ │
│ 4. エラー時の対応 │
│ ├── 認証エラーを検知 │
│ └── 再認証を試行 │
│ │
└─────────────────────────────────────────────┘

利用者から見た体験

SDKなしの場合

1. トークンを取得するコードを書く
2. 毎回のリクエストにトークンを付ける
3. 期限切れを検知するコードを書く
4. 再取得するコードを書く
5. リトライするコードを書く

SDKありの場合

1. 初期化時に認証情報を渡す
2. あとはSDKが全部やってくれる

2. エラーハンドリング

SDKが解決する課題

ネットワーク通信は失敗することがあります。SDKは様々なエラーを整理し、利用者が適切に対処できるようにします。

エラーの分類

┌─────────────────────────────────────────────┐
│ エラーの種類と対処 │
├─────────────────────────────────────────────┤
│ │
│ 一時的なエラー(リトライ可能) │
│ ├── ネットワーク切断 │
│ ├── サーバー過負荷 │
│ └── タイムアウト │
│ │
│ 恒久的なエラー(リトライ不可) │
│ ├── 認証エラー(資格情報が間違い) │
│ ├── 権限エラー(アクセス権なし) │
│ ├── バリデーションエラー(入力が不正) │
│ └── リソース不存在(データがない) │
│ │
│ 設定エラー(SDKの使い方の問題) │
│ ├── 必須パラメータ不足 │
│ └── 不正な設定値 │
│ │
└─────────────────────────────────────────────┘

日常生活での例え

電話をかける場面で考えてみましょう:

エラーの種類電話での例え対処
一時的話し中しばらく待ってかけ直す
恒久的番号が存在しない番号を確認する
設定電話機の設定ミス設定を見直す

良いSDKのエラー設計

┌─────────────────────────────────────────────┐
│ エラー情報に含まれるべきもの │
├─────────────────────────────────────────────┤
│ │
│ 1. 何が起きたか │
│ └── 人間が読めるメッセージ │
│ │
│ 2. なぜ起きたか │
│ └── エラーコードや原因 │
│ │
│ 3. どうすればいいか │
│ └── 対処方法のヒント │
│ │
│ 4. リトライすべきか │
│ └── 一時的か恒久的かの判断材料 │
│ │
└─────────────────────────────────────────────┘

エラー階層の例

良いSDKはエラーを階層化して、適切な粒度で捕捉できるようにします:

SDKエラー(基底)
├── ネットワークエラー
│ ├── 接続エラー
│ ├── タイムアウトエラー
│ └── DNSエラー
├── APIエラー
│ ├── 認証エラー
│ ├── 権限エラー
│ ├── バリデーションエラー
│ └── レート制限エラー
└── 設定エラー
├── 必須パラメータ不足
└── 不正な設定値

利用者は必要に応じて:

  • 全てのエラーをまとめて捕捉
  • 特定のカテゴリのみ捕捉
  • 特定のエラーのみ捕捉

が選べます。


3. リトライとタイムアウト

SDKが解決する課題

ネットワーク通信は不安定です。一時的な問題で失敗しても、すぐに諦めずに再試行することで成功率を上げられます。

日常生活での例え

混雑したレストランに電話する場面:

┌─────────────────────────────────────────────┐
│ 素朴なリトライ │
├─────────────────────────────────────────────┤
│ │
│ 話し中 → すぐかけ直す → 話し中 → すぐ... │
│ │
│ 問題: 相手がずっと話し中になる │
│ │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ 賢いリトライ(指数バックオフ) │
├─────────────────────────────────────────────┤
│ │
│ 話し中 → 1分待つ → 話し中 → 2分待つ → │
│ 話し中 → 4分待つ → 繋がった! │
│ │
│ 利点: 相手に余裕を与える │
│ │
└─────────────────────────────────────────────┘

指数バックオフとは

リトライ間隔を徐々に長くする戦略:

1回目の失敗 → 1秒待つ
2回目の失敗 → 2秒待つ
3回目の失敗 → 4秒待つ
4回目の失敗 → 8秒待つ
5回目の失敗 → 諦める

なぜこれが良いのか:

  • サーバー保護: 過負荷時に追い打ちをかけない
  • 回復時間の確保: 問題が解決する時間を与える
  • リソース節約: 無駄なリクエストを減らす

ジッター(揺らぎ)の追加

多くのクライアントが同時にリトライすると、同じタイミングでサーバーに殺到します:

ジッターなし:
クライアントA: 失敗 → 1秒後 → 2秒後 → 4秒後
クライアントB: 失敗 → 1秒後 → 2秒後 → 4秒後
クライアントC: 失敗 → 1秒後 → 2秒後 → 4秒後
↑同時に殺到

ジッターあり:
クライアントA: 失敗 → 0.8秒後 → 2.3秒後 → 3.7秒後
クライアントB: 失敗 → 1.2秒後 → 1.8秒後 → 4.5秒後
クライアントC: 失敗 → 0.9秒後 → 2.1秒後 → 4.2秒後
↑分散される

タイムアウトの設計

┌─────────────────────────────────────────────┐
│ タイムアウトの種類 │
├─────────────────────────────────────────────┤
│ │
│ 接続タイムアウト │
│ └── サーバーに接続するまでの待ち時間 │
│ 例: 10秒以内に接続できなければ諦める │
│ │
│ 読み取りタイムアウト │
│ └── レスポンスを受け取るまでの待ち時間 │
│ 例: 30秒以内に応答がなければ諦める │
│ │
│ 全体タイムアウト │
│ └── 処理全体の制限時間 │
│ 例: リトライ含めて60秒まで │
│ │
└─────────────────────────────────────────────┘

4. ロギングとデバッグ支援

SDKが解決する課題

問題が発生したとき、「何が起きているのか」を把握する必要があります。SDKは適切なログ出力でデバッグを支援します。

ログレベルの設計

┌─────────────────────────────────────────────┐
│ ログレベルと用途 │
├─────────────────────────────────────────────┤
│ │
│ ERROR(エラー) │
│ └── 処理が失敗した重大な問題 │
│ 例: 認証失敗、サーバーエラー │
│ │
│ WARN(警告) │
│ └── 問題はあるが処理は継続できる │
│ 例: リトライ発生、非推奨機能の使用 │
│ │
│ INFO(情報) │
│ └── 正常な動作の記録 │
│ 例: API呼び出し完了、接続確立 │
│ │
│ DEBUG(デバッグ) │
│ └── 開発時に必要な詳細情報 │
│ 例: リクエスト内容、レスポンス内容 │
│ │
│ TRACE(トレース) │
│ └── 非常に詳細な情報 │
│ 例: 内部状態、メモリ使用量 │
│ │
└─────────────────────────────────────────────┘

本番環境とデバッグ環境

本番環境: ERROR, WARN のみ
→ パフォーマンスを優先
→ 重要な問題のみ記録

開発環境: DEBUG まで有効
→ 問題の詳細を把握
→ リクエスト/レスポンスの中身を確認

センシティブ情報の扱い

良いSDKは、ログに機密情報を出力しないように設計されています:

悪い例:
DEBUG: リクエスト送信 Authorization: Bearer abc123xyz...

良い例:
DEBUG: リクエスト送信 Authorization: Bearer [REDACTED]

5. 接続管理とリソース効率

SDKが解決する課題

HTTPリクエストのたびに接続を確立すると、オーバーヘッドが大きくなります。SDKは接続を再利用して効率化します。

接続プールの概念

┌─────────────────────────────────────────────┐
│ 接続プールなし │
├─────────────────────────────────────────────┤
│ │
│ リクエスト1: 接続→送信→応答→切断 │
│ リクエスト2: 接続→送信→応答→切断 │
│ リクエスト3: 接続→送信→応答→切断 │
│ │
│ 問題: 毎回接続のオーバーヘッドが発生 │
│ │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ 接続プールあり │
├─────────────────────────────────────────────┤
│ │
│ 初回: 接続確立(プールに保管) │
│ リクエスト1: 送信→応答 │
│ リクエスト2: 送信→応答 │
│ リクエスト3: 送信→応答 │
│ 終了時: 切断 │
│ │
│ 利点: 接続のオーバーヘッドを削減 │
│ │
└─────────────────────────────────────────────┘

日常生活での例え

タクシー vs カーシェア

方式特徴SDKでの例え
毎回タクシー乗るたびに呼ぶ毎回接続確立
カーシェア車を借りっぱなし接続プール

6. 設定の外部化

SDKが解決する課題

環境(開発、本番など)によって設定を変えたい場合があります。SDKは柔軟な設定方法を提供します。

設定の優先順位

多くのSDKは以下の優先順位で設定を読み込みます:

高い ↑  コードで明示的に指定
│ 環境変数
│ 設定ファイル
低い ↓ デフォルト値

なぜこの順番か

デフォルト値:
└── 多くの場合に適切な値

設定ファイル:
└── プロジェクト固有の設定を記述

環境変数:
└── 環境(開発/本番)ごとに変える値

コード指定:
└── 特定の処理だけ変えたい場合

まとめ

SDKが内部で解決する主な課題:

パターン解決する課題
認証・認可毎回の認証処理、トークン更新
エラーハンドリングエラーの分類と適切な対処
リトライ一時的な障害からの回復
ロギング問題発生時のデバッグ支援
接続管理通信の効率化
設定の外部化環境ごとの設定変更

これらを自分で実装する必要がないことが、SDKを使う大きなメリットです。


次のステップ

  • SDK入門 に戻って基礎を確認
  • SDK設計原則 で設計思想を学ぶ
  • 実際のSDKのソースコードを読んでみる