第05章:境界(Boundary)の考え方 🚧😊
“内側(ルール)”と“外側(I/O)”を分けると、コードが一気に強くなるよ💪✨ この章では「境界ってなに?どう作るの?」を、ふわっと→しっかりの順でつかみます🧠🌸
5-1. まず「境界」ってなに?🤔🚧
境界(Boundary)は、ざっくり言うと……
-
内側:アプリの“ルール”や“判断” 🧠📦
- 例:税計算、割引判定、入力値チェック、期限判定、在庫の引当、料金計算…など
-
外側:アプリの“外の世界(I/O)” 🌍🔌
- 例:DB🗄️、ファイル🗂️、ネット🌐、時刻🕰️、乱数🎲、UI🖥️、メール📧 など
そして 境界は「内側と外側の接点」 です📦↔️🌍 この接点をちゃんと作ると、テストがめちゃ楽になります🧪✨
5-2. なんで境界を作ると嬉しいの?🎉
境界を作ると、こうなります👇
- 内側(ルール)が純粋に近づく 🌿✨ → テストが「速い・安定・簡単」⚡🧪
- 外側(I/O)を交換できる 🔁 → DBを本物→Fake、時間を本物→固定、APIを本物→Fake に差し替え可能🎭
- 変更に強い 🛡️ → “外の都合”が変わっても、内側は守られる🏰✨
境界がないと「I/Oが混ざってテストが揺れる」😵💫 境界があると「I/Oを差し替えてテストが固定できる」🎯✨
5-3. “境界がある世界”のイメージ図 🗺️✨
ポイントはこれ👇 「内側が外側に依存しない」(超だいじ!)🙌
- 内側:必要なものを「こういう機能がほしい」と宣言する(=インターフェース)🧩
- 外側:それを実装する(=本物I/O)🔌
- 組み立て:最後に接続する(後の章の Composition Root 🏗️)
イメージ:
-
内側(ルール)📦
IClock(今の時刻が欲しい)🕰️IUserRepository(ユーザー取得したい)🗄️
-
外側(I/O)🌍
SystemClock(DateTimeを読む)SqlUserRepository(DBに行く)
5-4. 境界は「インターフェース」で作るのが定番 🧩✨

ここでの主役が インターフェース です🧩💖 内側は「欲しい能力」を インターフェースとして定義 します✍️
例:時刻は I/O なので境界にする🕰️🚧
public interface IClock
{
DateTime Now { get; }
}
外側が本物実装:
public sealed class SystemClock : IClock
{
public DateTime Now => DateTime.Now;
}
内側は DateTime.Now を直接読まないで、IClock を使うようにするんだよ〜🙆♀️✨
5-5. “依存の向き”が超重要!🔁➡️
ここ、最初はピンと来なくてOKなんだけど…すごく大事なのでやさしく言うね😊🌸
- ❌ ダメになりがち:内側(ルール)が外側(DB/HTTP/ファイル)を直呼び → ルールが外の都合に縛られて、テストがつらい😵💫
- ✅ 目指す:内側(ルール)が「必要なもの」を インターフェースで要求 → 外側が後から実装して合わせに来る🚶♀️🔌
つまり…
内側は“どうやるか”を知らない 内側は“何が欲しいか”だけ言う 🧠✨
この状態ができると、テストで差し替えが効きます🎭🧪
5-6. ミニ例:境界があるとテストがラクになる🎉
内側(ルール)に「期限チェック」があるとします⏳
DateTime.Now を直読みするとテストが揺れます🌀
境界を使うとこう👇
public sealed class SubscriptionService
{
private readonly IClock _clock;
public SubscriptionService(IClock clock)
{
_clock = clock;
}
public bool IsExpired(DateTime expiresAt)
{
return _clock.Now > expiresAt;
}
}
テストでは FakeClock を使って「今」を固定できる🎯✨
public sealed class FakeClock : IClock
{
public DateTime Now { get; set; }
}
こうすると「今日がいつか」に関係なくテストが安定します🧪💖
5-7. 境界の作り方のコツ 🧠🧩
コツ①:境界は “欲しい能力” で切る ✂️✨
- ✅
IClock(時刻)🕰️ - ✅
IEmailSender(メール送信)📧 - ✅
IFileStore(ファイル保存)🗂️ - ✅
IExternalApiClient(外部API)🌐
「何をしたいか」で分けるのが気持ちいいです😊✨
コツ②:インターフェースは小さめが正義 🧩💎
でかい万能インターフェースは破綻しがち😵💫 最初は 1〜3メソッドくらいを目安に👍✨
コツ③:内側で “実装の都合” を漏らさない 🚫🫧
例えば DB を使うからって、内側に SqlConnection とか出すとアウト🙅♀️
内側に必要なのは 「ユーザーを取得したい」 みたいな要求だけでOK🙆♀️✨
5-8. よくある落とし穴(あるある)😇💥
-
境界を作ったのに、結局内側が外側の型に依存してる 😵
- 例:内側が
HttpResponseMessageを返す、DbContextを握る…など
- 例:内側が
-
境界を作りすぎて抽象が増えすぎる 🌪️
- なんでもかんでも
IWhateverにして迷子😵💫 - 対策:まずは「テストが困るI/O」からでOK🧪✨
- なんでもかんでも
5-9. 章末ミニまとめ 🧾✨
- 境界とは 内側(ルール)📦 と 外側(I/O)🌍 の接点🚧
- 境界を作ると 差し替えできてテストが安定 🎭🧪
- 境界はだいたい インターフェースで作るのが定番🧩
- 内側は「何が欲しいか」を言うだけ、外側が実装する🔁✨
※ちなみに本日時点では、.NET 10(LTS)は 2025/11/11 リリースでサポートは 2028/11/14 まで、C# は C# 14 が最新(.NET 10 対応)です🆕✨ (Microsoft)
5-10. 演習(ゆるめ)✍️😊
次のコードの「外側(I/O)」を探して、境界にできそうなものを丸してみてね✅✨
DateTime.Now🕰️Random.Shared🎲File.ReadAllText🗂️HttpClient.GetStringAsync🌐Console.ReadLine / WriteLine🖥️- DBアクセス系(EF/SQL)🗄️
「丸したもの=境界候補」だよ〜🚧💖
5-11. AI(Copilot/Codex)に手伝わせるプロンプト例 🤖💡
コピペでOK系👇✨
- 「このコードの I/O(外部依存)を列挙して、境界(インターフェース)案を出して」🔍🧩
- 「DateTime.Now を直接使ってる箇所を IClock に置き換えて」🕰️➡️🧩
- 「テストが安定するように Fake 実装も作って」🎭🧪
- 「この設計、内側が外側に依存してないかチェックして」👀✅
AIの提案は便利だけど、**“内側に外側の型が漏れてない?”**だけは毎回チェックね⚠️💖
次の第6章では、ここで作った境界の考え方を 最小サンプルで手を動かして体験していくよ🧪✨ 「分けると一瞬でテストできる」感覚、味わいにいこ〜!🎉🚀