C++17 設計方針としての「例外禁止」有無レビュー|例外禁止ポリシー採否の判断軸とレビューアーが読み解く責務整理
この記事のポイント
- 「例外禁止」設計方針の是非をレビューアーが読み取る視点を体系整理
- 導入判断軸・責務整理・メリットデメリットをレビュー観点から整理可能にする
- 例外禁止方針を採るべきプロジェクトと採らないべきプロジェクトを読み分ける力を身につける
そもそも「例外禁止設計方針」とは
C++では本来例外機構をフル活用する前提で言語設計されているが、
一部プロジェクト・業界・設計文化では「例外禁止」を設計方針として採用する現場も存在する。
| 方針採否 | 典型導入理由 |
|---|---|
| 例外禁止 | 組込系、リアルタイム制御、全障害即Abort運用 |
| 例外許容 | サーバアプリ、Web API、業務系処理 |
レビューアーは「なぜこのプロジェクトが例外禁止方針を採っているのか?」を読み解くことがレビュー責任となる。
なぜこれをレビューするのか
- 方針自体は設計文化ではなく設計責務の固定化宣言である
- 方針採択の根拠が整理されていないと例外禁止が現場属人文化に固定化する
- 方針整理が曖昧なまま進行すると保守困難ゾーンに突入する
- レビューは「なぜ禁止なのか?」「どこまで禁止なのか?」を言語化支援する責務がある
レビューアー視点
- このプロジェクトが例外禁止を採った技術的・運用的背景は何か?
- 「例外禁止範囲」が正しくスコープ宣言されているか?
- 代替エラー制御構造が整備されているか?
- 全層共通方針なのか、層限定なのか?
- 移植性・将来性まで含めたレビュー説明可能性を持っているか?
開発者視点
- 例外禁止範囲は契約API公開範囲から逆引き固定する
- 障害検出・障害通知は別途Error Code / Status型で設計
- 例外封じ込めポイントは一箇所集中配置する
- noexcept運用方針は全統一設計と連動する
例外禁止設計が採用される典型領域
| 領域 | 禁止理由 |
|---|---|
| 組込ファームウェア | ヒープ無し、例外ランタイムコスト不可 |
| 制御系リアルタイム | 予測不可能分岐禁止 |
| 大規模金融系基盤 | 例外漏洩を契約違反化 |
| 自動運転・安全規格系 | 障害モード統一性要求 |
| Cインターフェース接続系 | 言語間例外互換性不可 |
レビューアーは技術的根拠/契約制約/運用制約を分類整理して読み取る。
良い設計例
例1:Error Code収束方針
エラーステータス運用
enum class SaveResult {
Success,
DBFailure,
ValidationFailure
};
SaveResult saveUser(const User& user) {
if (!isValid(user)) return SaveResult::ValidationFailure;
if (!db.save(user)) return SaveResult::DBFailure;
return SaveResult::Success;
}- 全分岐が戻り値で集約
- 呼出側は統一評価可能
例2:例外禁止宣言統一方針
全統一noexcept適用
class Repository {
public:
SaveResult saveUser(const User& user) noexcept;
};- noexcept宣言で例外漏洩ゼロ契約宣言
レビュー観点
- 技術的理由が設計資料で明文化されているか
- API全契約がError Code統一で整理されているか
- 代替通知構造(Error型)が可読性・拡張性を維持しているか
- 例外発生可能箇所(標準ライブラリ含む)への事前封じ込めが実装済みか
- テストケースで全エラーパス到達確認が整備されているか
良くない実装例: ケース1(例外禁止範囲曖昧)
混在設計型
SaveResult saveUser(const User& user) {
db.save(user); // ここで例外可能性あり
return SaveResult::Success;
}
@Reviewer例外禁止ポリシーならdb.save内の例外可能性も含め封じ込め層統一してください。曖昧禁止です。
改善例
改善例(封じ込め統一)
SaveResult saveUser(const User& user) {
try {
db.save(user);
} catch (...) {
return SaveResult::DBFailure;
}
return SaveResult::Success;
}良くない実装例: ケース2(通知設計未整理)
通知経路断絶
SaveResult saveUser(...) { return SaveResult::DBFailure; }
@Reviewer通知経路統合設計が不在です。監視通知連動層を整備してください。
改善例
改善例(通知統合)
if (result == SaveResult::DBFailure) {
monitoring.notify("SAVE_FAILURE");
}良くない実装例: ケース3(層適用崩壊)
層統一崩壊型
Repository::saveUser() noexcept;
Service::process() → 例外throw残存
@Reviewer全層統一方針が崩れています。例外禁止ポリシー採用なら全層再統一してください。
改善例
改善例(全層収束)
Service::process() noexcept;PlantUML:例外禁止責務整理フロー
封じ込めパターン設計整理
| 責務分類 | 設計パターン |
|---|---|
| 例外封じ込め層 | try-catch→Error Code変換 |
| 共通例外吸収層 | 全外部API例外変換責務 |
| 監視通知層 | エラー分類→通知統合 |
レビューアーは設計責務図解化可能な整理を訓練する。
例外禁止設計の代表的デメリット整理
| デメリット | 内容 |
|---|---|
| 保守性劣化 | 分岐評価肥大 |
| 表現力低下 | 契約違反表現困難化 |
| 再利用困難 | 標準ライブラリ適合低下 |
| コーディング負荷 | 毎回Error評価記述 |
レビューアーは現場文化依存か技術依存か分類整理を心掛ける。
逆に例外許容設計の実務的メリット
- 契約違反表現が可能(invalid_argument等)
- 透過伝播により責務粒度保持が容易
- 標準ライブラリ適合性維持
- 診断可能性向上(stack追跡)
レビューアーは設計レイヤー毎に採用可否を柔軟提案可能にする訓練を積む。
ロギング統合例
統合障害通知例
SaveResult result = service.saveUser(user);
if (result != SaveResult::Success) {
logger.error("SaveUser failed: {}", static_cast<int>(result));
monitoring.notify("USER_SAVE_FAILURE");
}- 通知経路は必ず統合構成
観点チェックリスト
まとめ
レビューアーが例外禁止方針レビューで常に問うべきは
「この禁止は誰のために、どの層まで徹底されているか?」
です。
- 責務固定宣言
- 設計文化宣言
- 運用負荷整理
- 保守コスト整理
レビュー現場では
「例外禁止方針の設計理由をレビュー説明できる技術者文化」
が現場品質を大きく決定づけます。
