第3章 不変条件はどこで守る?“境界”の話🚪🧱✨
この章のゴール🎯

- 「境界(きょうかい)」=入力が入ってくる入口だって説明できる🙂
- UI / API / DB / 外部I/O が、ぜんぶ「境界」になりうるって分かる🌐🗄️📩
- 自分のアプリで「境界マップ(入口一覧)」を作れる🗺️✨
1) まず“境界”ってなに?🚪
ひとことでいうと…
境界=“外の世界”と“中の世界”の接点👭🌍🏛️
- 外の世界:ユーザー入力、HTTP、DB、外部サービス、ファイル、環境変数… → **何が来るか分からない(信用できない)**😵💫
- 中の世界:あなたが設計するドメイン(業務ルールの中心) → 信用できる状態にしてから扱いたい🛡️✨
つまり境界は、**「危険なものが入ってくる玄関」**なのね🏠💥 ここでちゃんと止めると、家の中(ドメイン)が平和になります🕊️
2) なんで“境界”で守るの?🧠🛡️
不変条件(絶対守る約束)を守る場所がバラバラだと、こうなるよ👇😭
- あっちでチェック、こっちでチェック… 抜け漏れが出る🕳️
- どの画面から来た入力なのかで挙動が変わる😇😈
- 直したつもりが別ルートから壊れる(バグ無限ループ)♾️💥
だから基本方針はこれ👇
✅ 境界で「怪しいデータ」を受け止めて ✅ 検証して(Validation) ✅ 中で使える形に変換して(Convert) ✅ 失敗は外向けの言葉に翻訳して返す(Translate)
この4点セットが超大事だよ〜!✨
3) 境界になりやすい“4大入口” remind🧱
この章のキーワードにもなってるやつ👇 (ぜんぶ不変条件が壊れやすい入口!)💣
① UI(画面・フォーム・CLI)🎀⌨️
- テキストボックス、選択肢、ファイルアップロード
- “空文字”や“桁数オーバー”が簡単に来る😇
② API(HTTPの入口)🌐🚪
- Controller / Minimal API のエンドポイント
- クライアントが何送ってくるか分からない😵💫
③ DB(読み書き)🗄️🔁
- DBから読み出した値が 想定とズレてる こともある
- レガシー、手作業更新、移行ミス…あるある💥
④ 外部I/O(外部サービス・ファイル・メッセージ)📩💳📦
- 決済、メール、外部API、S3、Queue、Webhook
- “相手都合の仕様”が混ざる🌀
4) 境界を見つける“超かんたん質問”4つ👀✨
自分のアプリを思い浮かべて、これを順番に聞いてみてね🙂
-
どこからデータが入ってくる?(入力経路)🚪
-
どこへデータを出す?(外部へ返す/渡す)📤
-
どこに保存・復元する?(DB/ファイル)🗄️
-
誰のルールに従う?(外部API/他チーム/他社)🤝
-
誰のルールに従う?(外部API/他チーム/他社)🤝
ここで出てきた場所が、だいたい境界候補だよ🗺️✨
5) 境界でやる仕事は“3つ+おまけ”🧰💖
A. 検証(Validation)🛡️
- 形式チェック(空/長さ/範囲/必須)
- 組み合わせチェック(AならB必須、など)
- “できない入力”を早めに止める🙅♀️
B. 変換(Convert)🔁
- string → int
- string → DateTime
- DTO → 内部モデル(この教材だと、後半で VO を作る💎)
C. 翻訳(Translate)🗣️
- 内部のエラーを、UI/API向けの分かる形にして返す
- 例:画面なら「この項目がダメだよ」
- APIなら HTTP 400 + 説明、みたいに📣
おまけ:ログ・観測(Log/Trace)👀🧾
- 境界は事故現場になりやすいので、ログがあると神🙏✨
- ただし入力を丸ごとログに残すのは危険な場合もあるから注意ね🔐
6) ミニ題材で境界マップを作ってみよ🗺️🎀
題材:会員登録+サブスク課金💳✨
ざっくりデータの流れ(イメージ)🌊
- 画面(フォーム)🎀 → API(登録エンドポイント)🌐 → アプリ処理(登録ユースケース)🧠 → DB(会員保存)🗄️ → 外部決済(サブスク作成)💳 → メール送信(歓迎メール)📩
ここで境界はどれ?っていうと… UI / API / DB / 決済API / メール がぜんぶ境界だよ〜!🚪🚪🚪
境界マップ(テンプレ)📋✨
下みたいに「入口台帳」を作ると、抜けが一気に減るよ😊
| 境界 | 入ってくるもの | “怪しい”ポイント | ここで守ること(例) |
|---|---|---|---|
| UIフォーム🎀 | 文字列だらけ | 空白/全角/長すぎ | 必須・長さ・見た目の整形 |
| APIエンドポイント🌐 | JSON | 形式・型違い | 400返す、エラー形を統一 |
| DB読み込み🗄️ | 既存データ | 変な値が混ざる | 変換時に検知・修復方針 |
| 決済API💳 | 外部仕様 | エラー/タイムアウト | リトライ方針・失敗の翻訳 |
| メール送信📩 | 外部仕様 | 送れない/遅延 | キュー化・失敗時の扱い |
7) 境界の“外向けエラー”を整える(API例)🌐🧱✨
API境界って「失敗の見せ方」も超大事なのね🙂
ASP.NET Core では Problem Details(RFC 7807) でエラーを返す設計が一般的になってるよ📣
さらに .NET 10 の ASP.NET Core では、Minimal API の検証(validation)と、そのエラー応答のカスタマイズに IProblemDetailsService を使える流れが用意されてるよ🧩✨ (Microsoft Learn)
例(雰囲気だけつかめればOK😊)👇
using System.ComponentModel.DataAnnotations;
var builder = WebApplication.CreateBuilder(args);
// 400(Validation)などのProblemDetailsを統一して整える✨
builder.Services.AddProblemDetails(options =>
{
options.CustomizeProblemDetails = context =>
{
if (context.ProblemDetails.Status == 400)
{
context.ProblemDetails.Title = "入力にまちがいがあるよ🥺";
context.ProblemDetails.Extensions["hint"] = "入力欄の赤いところを見てね🎀";
context.ProblemDetails.Extensions["traceId"] = Guid.NewGuid().ToString();
}
};
});
var app = builder.Build();
app.MapPost("/register", ([Required, EmailAddress] string email) =>
{
// ここは“境界”だから、受けたら検証→変換→中へ渡すのが基本🛡️🔁
return Results.Ok(new { message = "登録OK🎉", email });
});
app.Run();
ポイントはこれ👇
- 境界では「外向けのエラー形式」を揃える🧱✨
- 中の処理は「業務の本質」に集中できるようになる🎯
(ちなみに .NET 10 は 2025年11月11日リリースのLTSで、今ど真ん中の現役ラインだよ🧡)(Microsoft for Developers)
8) 演習:あなたのアプリで“境界マップ”を作ろう🗺️🖊️✨
Step 1️⃣ 境界を10個まで列挙してOK🙆♀️
例の型でメモしてみてね👇
- UI:画面A、画面B、管理画面…🎀
- API:POST /xxx、GET /yyy…🌐
- DB:Usersテーブル、Ordersテーブル…🗄️
- 外部:決済、通知、ファイル、Webhook…📩
Step 2️⃣ 各境界に「怪しいポイント」を書く💣
- 空/負数/範囲外/null/文字種/組み合わせズレ…🧨
Step 3️⃣ 「ここで止める」or「中で守る」を分ける🧱
- 境界:止める(入力の質を上げる)🛡️
- 中:絶対に壊さない(後の章で型・設計で固める)💎
9) AI活用コーナー🤖💞(境界探しが爆速になるよ)
そのままコピペで使えるやつ置いとくね✨
✅ 境界候補の洗い出し
- 「このアプリの概要は〇〇です。画面/UI、API、DB、外部サービス、バッチ、ファイル入出力の観点で“境界候補”を箇条書きで列挙して。漏れがちな境界も一緒に。」
✅ 境界ごとの“壊れ方”レビュー
- 「境界A(例:会員登録API)で起きうる“壊れた入力”を20個出して。空/長さ/範囲/組み合わせ/悪意ある入力も混ぜて。」
✅ 境界マップの抜けチェック
- 「この境界マップに抜けがないかレビューして。特に“非同期(キュー/バッチ)”と“DB読み込み時”の境界をチェックして。」
まとめ🎀✨
- 境界は 外の世界と中の世界の接点🚪
- UI / API / DB / 外部I/O は全部、事故が入りやすい入口💥
- 境界では 検証→変換→翻訳(+ログ) をやると強い🛡️🔁🗣️
- .NET 10(LTS)では Minimal API の検証まわりと ProblemDetails の整え方も公式に整理されてるよ📚✨ (Microsoft Learn)
次の章(第4章)は、いよいよ **入口を守る具体技:ガード節(Guard Clauses)**🛡️💨 「境界で止める」コードを、読みやすくスッキリ作る練習に入ろ〜😊🎀