第9章:バグ(不変条件違反)とFail Fast⚡🧱
この章はね、「ここに来たらおかしい」をハッキリさせて、バグを早く見つけて早く直すための回だよ〜😊🔍✨ (本日時点では .NET 10 が LTS で、最新パッチは 10.0.2(2026-01-13) だよ📅🧩 (Microsoft) )
1) まず整理!「想定内の失敗」vs「バグ」🚦💥
ここ、超大事ポイントだよ🫶✨
✅ 想定内の失敗(=仕様の範囲内)
- ユーザーの入力ミス(数量が0、メール形式が違う、など)✍️
- 業務ルール違反(在庫不足、期限切れ、など)📦
- 一時的な通信失敗(タイムアウト等)🌩️
➡️ アプリは“普通に起きる”ものとして扱う ➡️ 後で Result 型で扱う(この先の章でやるよ🎁)
❌ バグ(=不変条件違反 / ここに来たらおかしい)
- 「絶対に起きない前提」を破った状態😱
- 例:在庫がマイナス、合計金額が負、nullが来ないはずなのに来た、など
➡️ **Fail Fast(すぐ止めて気づく)**の対象⚡ ➡️ “隠さない”のが正解🙅♀️
2) 不変条件(Invariant)ってなに?🧱✨
不変条件は「そのオブジェクト(や処理)が正しいなら、常に成立してる条件」だよ✅
たとえば「推し活グッズ購入管理🛍️💖」なら…
- 予算(Budget)は 0以上 💰
- 購入数量は 1以上 🔢
- 在庫は 0以上 📦
- 合計金額 = 単価×数量 は 0以上 🧾
こういうのが「崩れたらバグ」になりやすいの😊
3) Fail Fast ってなに?⚡🚨
Fail Fast は、ざっくり言うと
おかしい状態を見つけたら、早めに大きく転ぶ(=気づけるようにする)
だよ💥 「よく分からんけど進めちゃえ〜」が一番危ない😵💫
実際、エラーモデルの文脈でも「プログラミングバグは fail-fast」みたいに扱う考え方があるよ🧠 (ジョー・ダフィーのブログ)
4) Fail Fast の実装パターン3つ(超よく使う)🧰✨
パターンA:ガード節(Guard Clauses)で入口で落とす🚪🛑

「この引数おかしいよ?」を最初に止めるやつ!
public static void GuardPositive(int value, string paramName)
{
if (value <= 0) throw new ArgumentOutOfRangeException(paramName, "1以上である必要があります");
}
- これは「呼び出し側が間違えた」系に強い💪
- 例外のベストプラクティス的にも「通常フローに例外を使わない」は基本方針だよ📌 (Microsoft Learn)
パターンB:不変条件はコンストラクタで守る(“常に正しい”モデル)🧱💎
「作れた時点で正しい」を目指すと、バグ激減するよ😊
public readonly record struct Budget(decimal Amount)
{
public Budget(decimal amount) : this()
{
if (amount < 0) throw new InvalidOperationException("Invariant violated: Budget must be >= 0");
Amount = amount;
}
}
ポイント👇
- これは「ユーザーが悪い」じゃなくて、コード(設計/実装)が悪いのサイン💥
- だから Fail FastでOK⚡
パターンC:アサーション(Debug.Assert / Trace.Assert)で“ここ絶対おかしい”を明示する🧨🧠
「ここ通ったらバグだよ!」の旗を立てるやつ🚩
using System.Diagnostics;
Debug.Assert(total >= 0, "total should never be negative");
- Debug.Assert は基本的にデバッグビルドでのみ動くよ🧪 (Microsoft Learn)
- リリースでも検査したいときは Trace.Assert(トレース有効前提)って選択肢もあるよ📌 (Microsoft Learn)
5) 「ユーザー表示」と「ログ」を分ける考え方🫶🧾🔎
Fail Fast って「ユーザーに怖いエラーを見せる」って意味じゃないよ🙅♀️💦
- ユーザーに見せる: **「問題が発生しました。もう一度お試しください」**みたいに優しく🎀
- 開発者が見る: stack trace / 相関ID / 状態(どのIDで何が起きた)をログにガッツリ🔎🧵
例外を扱うときも「状態を復元」「適切に再throw」などベストプラクティスがあるよ📚 (Microsoft Learn)
6) ミニ演習①:「不変条件」3つ決めよう📝💗
題材はこの先のミニPJと合わせて「推し活グッズ購入管理🛍️💖」にしよっ😊
ステップ
-
まず “常に正しい状態” を3つ書く✍️ 例:
- 予算は0以上
- 在庫は0以上
- 購入数量は1以上
-
それぞれ「破ったらどうする?」を書く🧠
- 例外でFail Fast(InvalidOperationException など)⚡
- そのときログに残したい情報も1つ書く(商品IDとか)🔎
7) ミニ演習②:Fail Fast をコードに入れてみよう🔧✨
例:購入処理(まだResult型は出てきてないので超簡単に)
public sealed class PurchaseService
{
public void Purchase(int quantity, Budget budget, int stock, decimal unitPrice)
{
// 入力・引数の“おかしさ”は入口で落とす(呼び出し側ミス)
if (quantity <= 0) throw new ArgumentOutOfRangeException(nameof(quantity));
if (unitPrice < 0) throw new ArgumentOutOfRangeException(nameof(unitPrice));
// 不変条件(ここが壊れてたらバグ)
if (stock < 0) throw new InvalidOperationException("Invariant violated: stock must be >= 0");
var total = unitPrice * quantity;
// ここも不変条件(負になるのはバグ)
if (total < 0) throw new InvalidOperationException("Invariant violated: total must be >= 0");
// この先:想定内の失敗(予算不足、在庫不足)は Result型で扱う予定🎁
// 今は章の目的が「バグ検知」なのでここまででOK😊
}
}
✅ やること
- quantity=0 / stock=-1 などで呼び出して、落ち方の違いを観察👀✨
- 「どれが想定内」「どれがバグ」か言語化してみてね🗣️💕
8) AI活用(Copilot / Codex)テンプレ🤖💬✨
✅ 不変条件の洗い出し
- 「このクラスの不変条件候補を10個出して。業務ルールと不変条件を分けて」🧠
✅ Fail Fast のチェックポイント
- 「このメソッドで Fail Fast を入れるべき箇所を指摘して。例外型も提案して」🔍
✅ “ユーザー表示”と“ログ情報”の分離案
- 「ユーザー向けメッセージは優しく、ログ向けは調査に必要な項目を提案して」🧾🔎
(AIの案は便利だけど、最後の判断は自分でね😊🫶)
9) まとめ🎓✨(この章で身につけたこと)
- バグ(不変条件違反)は Fail Fast で早期発見⚡🧱
- Guard / コンストラクタ防衛 / Assert の3点セットが強い🧰✨
- ユーザー表示は優しく🎀、開発者向けはログで濃く🔎🧵
次の章で「例外境界🚪」に入ると、**“落ちてもアプリ全体が綺麗に扱える”**ようになってさらに気持ちよくなるよ〜😊📚✨