この記事のポイント

  • サードパーティ呼び出しでの例外監視設計をレビューアーが読み解く技術を整理
  • 外部依存ポイントの障害封じ込め設計をレビューで指摘できるようになる
  • モニタリング連携・復旧可能性判断を設計レベルでレビュー支援できるようにする

そもそも「サードパーティ呼び出し時の例外監視」とは

C++開発現場では、多くの外部依存を持ったライブラリ/API/SDKを利用する。

  • OSSライブラリ(Boost、gRPC、OpenSSL など)
  • 商用SDK(AWS SDK、DB Driver など)
  • Cライブラリラップ(libcurl、libxml、SQLite など)

これらは内部実装詳細がブラックボックス化している一方で、
障害発生時に自プロセスへ例外通知を流入させる設計が多い。

レビューアーは「どのような例外が流入してくるか」を明確に読み取り、
外部依存ポイントの封じ込め設計をレビューする責任を持つ。

なぜこれをレビューするのか

  • 外部ライブラリ例外が未監視状態で内部層に伝播しやすい
  • API契約が脆弱で想定外障害がシステム全体を停止させ得る
  • ログ/監視/通知がサードパーティ障害を捉えられずサイレント障害化
  • ライブラリバージョン差異で新例外種が流入する可能性

レビュー段階で外部境界設計を「監視ポイント化」しておくことで
障害検出性・診断性・隔離性を大きく向上できる。

レビューアー視点

  • この外部呼び出しは何をthrowする可能性があるのか?
  • 呼び出し契約に明示されていない障害流入が存在しないか?
  • ログ統合設計に含まれているか?
  • 復旧可能性を内部層へ強制転嫁していないか?
  • 監視設計(アラート・通知)が外部障害対応を前提にしているか?

開発者視点

  • サードパーティ例外は内部層に直接流さない
  • 専用封じ込め層で責務分離する
  • 契約破綻/外部障害/ネット障害を例外分類として整理
  • 発生元ログを常に外部API名義で明示化

良い実装例

封じ込め用Facade層パターン

外部API呼び出し封じ込め
#include <stdexcept>
#include <string>

class PaymentGateway {
public:
    void charge(int amount) {
        try {
            sdk_.callCharge(amount);
        } catch (const ThirdPartySdkException& e) {
            throw PaymentGatewayException("Payment failure: " + std::string(e.what()));
        }
    }

private:
    ThirdPartySdk sdk_;
};
  • SDK例外 → 内部専用カスタム例外に変換
  • 内部層にサードパーティ型流入させない

監視情報を埋め込む統合設計

ログ出力統合型
try {
    gateway.charge(5000);
} catch (const PaymentGatewayException& e) {
    logger.error("Payment subsystem failure: {}", e.what());
    monitoring.notify("PAYMENT_FAILURE", e.what());
}
  • サブシステム単位での障害監視責務を可視化

レビュー観点

  • サードパーティ型の例外を内部API契約で直透過していないか
  • 封じ込め層(Facade/Adapter層)設計が導入されているか
  • カスタム例外型に明示変換しドメイン責務表現が行われているか
  • 監視設計・ログ設計がサブシステム単位で整理されているか
  • ライブラリアップデート時の例外追加影響検討が想定されているか

良くない実装例: ケース1(直透過型)

サードパーティ型を直接透過
class PaymentService {
public:
    void charge(int amount) {
        sdk_.callCharge(amount); // ThirdPartySdkException流入
@Reviewer
外部SDK例外型が透過しています。内部契約用に専用カスタム例外へ変換し封じ込めてください。
} private: ThirdPartySdk sdk_; };

改善例

改善例(封じ込め層導入)
class PaymentService {
public:
    void charge(int amount) {
        try {
            sdk_.callCharge(amount);
        } catch (const ThirdPartySdkException& e) {
            throw PaymentGatewayException("Charge failed: " + std::string(e.what()));
        }
    }
private:
    ThirdPartySdk sdk_;
};

良くない実装例: ケース2(監視責務分離不足)

監視統合されていない障害放流
void processOrder() {
    payment.charge(1000);
@Reviewer
サードパーティ呼び出しは障害監視対象です。ログ統合とアラート通知を組み込んでください。
}

改善例

改善例(障害検知統合)
void processOrder() {
    try {
        payment.charge(1000);
    } catch (const PaymentGatewayException& e) {
        logger.error("Payment failure: {}", e.what());
        monitoring.notify("PAYMENT_SUBSYSTEM_FAILURE", e.what());
    }
}

良くない実装例: ケース3(複数ライブラリ障害未整理)

多重サードパーティ流入混在
void process() {
    a.callA();
    b.callB();
@Reviewer
各ライブラリ障害分類が統合されていません。封じ込め統合層で障害分類を整理してください。
}

改善例

改善例(統一封じ込め層設計)
class ThirdPartyFacade {
public:
    void callA() {
        try { sdkA.call(); }
        catch (const ThirdPartyAException& e) { throw SubsystemAFailure(e.what()); }
    }
    void callB() {
        try { sdkB.call(); }
        catch (const ThirdPartyBException& e) { throw SubsystemBFailure(e.what()); }
    }
private:
    ThirdPartyA sdkA;
    ThirdPartyB sdkB;
};

PlantUML:外部依存障害封じ込め構造

UML Diagram

封じ込め層命名統一指針

層名 役割
XXXAdapter ライブラリAPIラッパ層
XXXFacade 複数ライブラリ統合層
XXXClient 外部依存インフラ層
XXXGateway 外部SaaS/業務外部依存層

レビューアーは命名規約統一設計が守られているかも確認対象に含める。

API契約設計例

外部依存透過契約禁止例
// BADパターン
void charge(int amount) throws ThirdPartySdkException;

// GOODパターン
void charge(int amount) throws PaymentGatewayException;
  • 外部例外種を契約上漏洩させない

ロギング統合例

ログ統合例
try {
    payment.charge(5000);
} catch (const PaymentGatewayException& e) {
    logger.error("Payment subsystem failure: {}", e.what());
    monitoring.notify("PAYMENT_FAILURE", e.what());
}
  • 障害情報は必ずログ/監視とセット

観点チェックリスト

まとめ

レビューアーがサードパーティ例外監視設計で常に問うべきは
「この障害が内部へどう流入し、どの層で止まる設計か?」
です。

  • 外部依存は封じ込め層責務設計で吸収
  • 監視通知は障害種類分類で整理統合
  • API契約は外部例外型透過禁止で守る

レビュー現場では
「このライブラリ障害流入はどの層で捕まえますか?」
と粘り強く設計議論を促せるレビュー文化が品質を大きく左右します。