この記事のポイント

  • assert/contract設計のレビュー観点を体系整理
  • 事前条件保証・契約違反検出・設計責務分界をレビューアーが読み取る技術を整理
  • 開発支援系assert/本番系contractを整理分類しレビューで具体的に提案可能にする

そもそもassert/contract設計とは何か

C++におけるassert/contract系は「設計責務を実行時・開発時に自動検査する仕組み」である。
例外やエラーハンドリングとは別軸の設計契約保証レイヤーとなる。

種類 用途 典型利用フェーズ
assert 開発中設計確認 デバッグ時
contract 事前条件契約保証 運用時含む

レビューアーは「誰がどの責務を保証するためのassert/contractか?」を読み取る視点が求められる。

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

  • 契約違反の設計責務がレビュー段階で曖昧になりやすい
  • 事前条件チェックが責務整理されず拡散する
  • 開発時のみ検査・本番は別制御 → 設計切り分け整理が困難化
  • 保守時に誰が何を保証すべき契約か説明不能化

レビュー段階で設計契約の見える化をレビュー技術で支援できると保守品質が飛躍的に向上する。

レビューアー視点

  • 設計契約条件が明文化されているか?
  • assertとcontractの使い分け基準が整理されているか?
  • 契約違反を事前検出可能にしているか?
  • 副作用影響の無い場所でのみassert系が使われているか?
  • 保守者が契約責務を読み取れる構造になっているか?

開発者視点

  • 契約条件=関数引数成立条件は極力明文化
  • 設計初期で契約式テンプレート化を準備
  • assertは開発支援専用(NDEBUG切替可能想定)
  • contractは本番でも契約違反通知可能経路設計
  • 契約違反 → 設計バグ → 原則例外通知不要

assertの基本構造

assert条件設計
#include <cassert>

void saveUser(int id) {
    assert(id > 0);
    // 処理本体
}
  • 開発時にのみ検査有効
  • 運用時には原則除去(NDEBUG)

contract設計の基本概念(C++20準拠)

C++17標準にはcontractは無いが、設計思想レベルではC++17でも事前契約は導入可能である。

疑似contract例
void saveUser(int id) {
    if (id <= 0) {
        std::terminate();  // 契約違反=設計破綻即停止
    }
    // 処理
}
  • 契約破綻は例外でなくプロセス設計責務
  • 原則復旧不要 → 設計者検査責務

レビューアーはassert/contract適用境界線を読み取れる力が必要となる。

レビュー観点

  • 設計契約が関数入口設計で整理されているか
  • assertは副作用無い領域限定で適用されているか
  • contract破綻時の即停止責務を整理認識できているか
  • 設計バグ系(内部不整合)と運用障害系(外部異常)を切り分けているか
  • ログ・通知設計は運用障害系に統合されているか

良くない実装例: ケース1(契約定義曖昧)

条件責務不明確
void saveUser(int id) {
    if (id <= 0) {
        // FIXME: 条件整理必要
    }
    // 処理
}
@Reviewer
設計契約条件が整理されていません。id > 0条件を設計責務で明文化してください。

改善例

改善例(契約明文化)
void saveUser(int id) {
    assert(id > 0);
}

良くない実装例: ケース2(副作用区別不在)

副作用持ちassert
void openAndSave(int id) {
    auto conn = db.open();
    assert(id > 0);
@Reviewer
副作用(db.open)実行後のassertは不適切です。契約確認は副作用前に移動してください。
}

改善例

改善例(副作用前検査)
void openAndSave(int id) {
    assert(id > 0);
    auto conn = db.open();
}

良くない実装例: ケース3(例外代用濫用)

契約違反例外投げ型
void saveUser(int id) {
    if (id <= 0) {
        throw std::invalid_argument("id must be positive");
@Reviewer
設計契約違反は原則例外不要です。設計契約破綻はassert/terminateに整理してください。
} }

改善例

改善例(契約統一)
void saveUser(int id) {
    assert(id > 0);
}

PlantUML:契約責務整理フロー

UML Diagram

contract適用範囲整理表

責務層 推奨適用法 理由
ライブラリ公開API contract前提 呼び出し側契約宣言
内部業務API assert支援 開発バグ早期検知
非公開ユーティリティ assert限定 自己責務内確認用
外部APIバリデーション 通常if+例外 運用障害扱い

レビューアーは責務層毎の契約適用境界を設計支援できることが理想。

ロギング統合例(契約違反検出時)

contract破綻ログ通知
void saveUser(int id) {
    if (id <= 0) {
        logger.fatal("Contract violation: id={}", id);
        std::terminate();
    }
}
  • 設計者責務系は強制通知文化形成

典型的レビュー支援用質問集

質問例 意図
この条件は呼び出し側が守る契約ですか? 契約責務位置確認
この契約違反は設計バグですか?運用障害ですか? 例外有無分離判断
副作用発生前に契約確認が行えますか? 検査順序最適化

レビューアーは契約設計討議支援文化を作る役割が求められる。

観点チェックリスト

まとめ

レビューアーがassert/contract設計レビューで常に問うべきは
「この契約責務は誰が保証し、誰が破綻検出すべきか?」
です。

  • 設計契約 → 設計責務明文化
  • 運用障害 → 通常エラーパス分離
  • 副作用排除 → assert配置最適化
  • 統一契約文化 → 設計ドキュメント連動

レビュー現場では
「契約責務をレビューで見える化して保守文化を築く」
技術文化が設計安定性を長期支えます。