第11章:Infrastructure層の考え方🚪(外側に押し出す)
この章は「DB・HTTP・ファイル・外部サービスみたいな、変わりやすいものを “端っこ(Infrastructure)に追い出す” 感覚」をつかむ回だよ〜!😊🌸 次章(第12章)で「実際にDBアクセスをどこに置く?」をやる前に、まず 頭の地図🗺️ を作ろうね✨
0. まず結論:Infrastructureは「外の世界との接点」🌍🔌

Infrastructure層はひとことで言うと👇
- 外部の仕組み(DB / Web API / ファイル / メール / 時刻 / OS / ネットワーク) と話すところ📮
- “詳細” はここに閉じ込めて、内側(Domain / Application)を守る🛡️
そして超大事な合言葉はこれ👇 「変わりやすいものは端っこに」 🧊➡️📦
1. 2026年のC#開発目線で「外側に追い出す」って超現実的💡
2026時点の最新の土台としては、.NET 10 が LTS で、パッチも継続提供されてるよ〜(例:10.0.2 が 2026-01-13 に提供)🧰✨ (Microsoft) EF Core も EF Core 10 が .NET 10 世代の LTS で、サポートも長め(〜2028-11-10)📚🗄️ (Microsoft Learn) Visual Studio も .NET 10 世代に合わせたリリースがあり、C#の新しめ機能サポートも進んでるよ🤖✨ (Microsoft for Developers)
…つまり何が言いたいかというと👇 外部ライブラリや仕組みは進化が早い → だから Domainに混ぜるとしんどい 😵💫 → Infrastructureに隔離すると、内側の設計が安定する✨
2. Infrastructure層に入るもの/入らないもの(超重要)✅🙅♀️
✅ Infrastructureに入るもの(外部と話す“手”🖐️)
- DB(EF Core / Dapper / ADO.NET など)🗄️
- Web API 呼び出し(HttpClient など)🌐
- ファイルI/O(CSV/JSON/画像/ログ/ストレージ)📁
- メール送信・通知(SMTP / Push / Slack)📨
- メッセージング(Queue / PubSub)📦➡️📦
- OS依存(環境変数、時刻、乱数、GUID発番など)🕰️🎲
🙅♀️ Infrastructureに入れないもの(内側の“方針”🧠)
- 業務ルール(割引の計算、状態遷移、禁止事項など)💎
- ユースケースの手順(登録→検証→保存→通知…の並び)📋
- “画面都合” のデータ形(第10章のDTOの話)📦
コツ:「それって外の仕組みが変わったら一緒に変わる?」 YESなら Infrastructure の可能性大!💡
3. 「Policy(方針)と Detail(詳細)」で分ける🧠✨
レイヤードを気持ちよくする考え方👇
- Policy(方針)=Domain / Application 例:「未完了ToDoは最大20件まで」など💎
- Detail(詳細)=Infrastructure 例:「保存先はSQL Server」「APIはREST」など🧩
Policyは “プロダクトの価値” で、Detailは “入れ替え可能な実装” だよ😊 Detailを内側に入れると、方針まで一緒に揺れるのが事故ポイント💥
4. 依存の形:内側は「欲しいこと」を宣言、外側が「やり方」を担当📣🛠️
イメージ図(言葉で)🧱
- Domain / Application: 「保存してね」「現在時刻ちょうだい」「外部API呼んでね」と “お願い(契約)” を定義する📜
- Infrastructure: そのお願いを EF Core で実装したり、HttpClient で実装したりする🛠️
ここで効いてくるのが DI(第15章〜第17章で本格的にやるやつ)🧩 .NET は DI が標準で用意されてるので、このスタイルがやりやすいよ✨ (Microsoft Learn)
5. 例1:時刻(DateTime.Now)をDomainに直書きしない🕰️🙅♀️
ありがち事故💥
DomainやApplicationで DateTime.Now を使うと…
- テストがしんどい(時間が固定できない)😵
- タイムゾーンや仕様変更で地獄👹
解決:IClock(“時刻ポート”)を作る⌚✨
内側(例:Application)にインターフェースを置く👇
public interface IClock
{
DateTimeOffset Now { get; }
}
外側(Infrastructure)で実装する👇
public sealed class SystemClock : IClock
{
public DateTimeOffset Now => DateTimeOffset.Now;
}
これでテストでは FakeClock に差し替えられる🎁✨
(「差し替え」こそ、Infrastructure分離のご褒美🍰)
6. 例2:外部API(HttpClient)をApplicationに直書きしない🌐🙅♀️
ありがち事故💥
ApplicationのUseCaseに new HttpClient() が出てくると…
- リトライ/タイムアウト/ログ/認証が散らばる😵💫
- テストがしんどい(ネットワークが絡む)🌩️
“おすすめの型”:IHttpClientFactory を使う🧰✨
.NET では IHttpClientFactory を使うのが推奨されていて、Typed client も推されてるよ👍 (Microsoft Learn)
ここでも考え方は同じ👇
- 内側:
IWeatherApiみたいな 契約 を置く📜 - 外側:HttpClient(IHttpClientFactory)で 実装 する🛠️
(実装の具体例は、章のテーマ的に “次章以降でやろう” でOKだよ😊)
7. 例3:DBも同じ(EF CoreをDomainへ漏らさない)🗄️🙅♀️
EF Core 10 は .NET 10 世代で LTS だよ〜📚 (Microsoft Learn) でも、どれだけ安定でも「DB方式」や「テーブル設計」や「ORMの都合」は Detail(詳細)。
だから基本方針👇
- Domain/Applicationは “保存したい” を表現(Repositoryのインターフェースなど)📜
- Infrastructureが EF Coreで実装🛠️
例(内側:インターフェース)👇
public interface ITodoRepository
{
Task<Todo?> FindAsync(TodoId id, CancellationToken ct);
Task SaveAsync(Todo todo, CancellationToken ct);
}
外側(Infrastructure:EF Core 実装)👇
public sealed class EfTodoRepository : ITodoRepository
{
private readonly AppDbContext _db;
public EfTodoRepository(AppDbContext db) => _db = db;
public async Task<Todo?> FindAsync(TodoId id, CancellationToken ct)
=> await _db.Todos.FirstOrDefaultAsync(x => x.Id == id, ct);
public async Task SaveAsync(Todo todo, CancellationToken ct)
{
_db.Update(todo);
await _db.SaveChangesAsync(ct);
}
}
注意:このコードは“雰囲気”の例だよ😊 Domain設計(Entity/VO)とEFのエンティティ設計を同一にするかは、方針次第で変わる!(第12〜14章で丁寧にやる✨)
8. “漏れてる”サイン(においチェック)👃💥
次が見えたら「Infrastructureが内側に漏れてる」可能性大👇
- Applicationのクラスが
DbContextを受け取ってる🗄️😱 - Domainが EF Core 属性(
[Key]みたいな)を持ってる🏷️😱 - Applicationで
File.ReadAllTextとかが普通に出てくる📁😱 - UseCaseの中に
HttpClient設定がベタ書きされてる🌐😱 - “外部サービスの戻り値DTO” が Domain にそのまま入ってくる📦😱
この章のゴールは、これらを 「うわ、漏れてる!」って嗅ぎ分けられるようになることだよ🐶✨
9. じゃあInfrastructureってどんなフォルダ構成が多い?📁✨
よくある “わかりやすい” 分け方👇
-
Infrastructure
- Persistence(DB)🗄️
- ExternalServices(外部API/メール/通知)🌐📨
- FileStorage(ファイル/クラウドストレージ)📁
- System(時刻/環境変数/OS依存)🕰️🪟
ポイントは「外部の種類で分ける」こと。 初心者ほど “機能で混ぜる” とゴチャりやすいから、外部ごとに分けると楽だよ😊🎀
10. 章末ミニ課題(手を動かす)✍️🧪
課題A:時刻の直書きを追放しよう⌚🔥
- どこかのUseCaseに
DateTimeOffset.Nowを入れる IClockを作って差し替える- テストで
FakeClockにして、固定時刻でテストが通るのを確認🎉
課題B:ファイル読み書きの漏れを止めよう📁🧯
- Applicationに
File.ReadAllText(...)を書いちゃう ITextFileReaderを内側に置く- Infrastructureで
SystemTextFileReader実装 - テストでは
InMemoryTextFileReaderに差し替え✨
11. チェックリスト✅(この章の合格ライン🎓✨)
- 「外部の仕組み」はInfrastructureに寄せる感覚がある🌍📦
- 内側は “欲しいこと(契約)” だけを宣言できる📜
-
DbContext/HttpClient/Fileが内側に侵入してたら気づける👀💥 - “差し替え可能” がテストのご褒美だと理解できた🍰✨
12. AIに手伝ってもらうプロンプト例🤖💡(コピペOK)
※そのまま貼って使える感じで書くね😊✨
- 「このプロジェクトで Infrastructureに置くべき依存 を列挙して、漏れてる箇所があれば指摘して」🔍
- 「このUseCaseから
DbContext/HttpClient/Fileを追い出して、ポート(interface)設計案 を出して」🧩 - 「Domainに混ざってる “詳細(Detail)” を見つけて、Infrastructureへ隔離するリファクタ案を出して」🧹✨
- 「依存の向き(上位→下位)を壊してる参照がないか、プロジェクト構成からチェックして」➡️✅
次章予告🎬✨
次は 「DBアクセス、結局どこに書くの?」問題 を、ちゃんと “置き場所のルール” として解決するよ〜!🗄️🔥 この章で作った “外側に押し出す感覚” が、そのまま効いてくるからね😊👍