メインコンテンツまでスキップ

第04章:「中心(ロジック)」と「外側(I/O)」モデル🏠➡️🌍

testable_ts_study_004_core_donut.png

この章はね、頭の中に“設計の地図”を作る回だよ🗺️✨ ここがスッ…と入ると、あとで I/O を外に押し出す作業(分離)がめちゃラクになる😊💕


1) 今日のゴール🎯✨

章が終わったら、こんなことができるようになるよ👇

  • どんな処理でも「中心(ロジック)」と「外側(I/O)」に分けて考えられる🧠✨
  • 「境界(インターフェース)」って何かを説明できる📌
  • コードを見て「これは中心?外側?」をラベル付けできる🏷️
  • “矢印(依存の向き)”のルールが分かる➡️✅

2) まずは超ざっくり地図🗺

️🏠➡️🌍### ✅ 2つに分けるだけで世界が変わる🌈* **中心(ロジック)

🏠**:計算・判断・ルール(= 仕様のコア)

  • 例:料金計算、割引、在庫チェック、入力の整形、判定ロジック…

  • 外側(I/O)🌍:外の世界とのやりとり(= 変わりやすいもの)

    • 例:HTTP、DB、ファイル、時刻、乱数、環境変数、ログ…

イメージはこんな感じ👇

  🌍 外側(I/Oの世界)         🏠 中心(ロジック)
┌──────────────────┐ ┌──────────────────┐
│ fetch / DB / FS │ ---> │ 料金計算・判定 │
│ Date / Random │ │ 文字列整形 etc │
│ process.env / log │ │ (できれば純粋) │
└──────────────────┘ └──────────────────┘
↑ ↑
変更が多い😵‍💫 変更は仕様だけ😊

3) “境界”ってなに?🚪

📌(ここが超重要!)中心と外側の間には、境界線があるよ✂️✨ この境界をまたぐときに使うのが interface(最小の約束) 💍

✅ 境界(インターフェース)

の役割* 中心から見ると「外側の都合」を知らなくていい🙈✨

  • 外側は「中心が欲しい形」に合わせて頑張る💪😆
  • テストでは、外側を“ニセモノ”に差し替えられる🧸🧪

4) 依存の向き(矢印ルール)

➡️✅ここ、1回で覚えちゃおう😆✨

✅ ルール:矢印は“中心に向かう”🏠* 中心は外側の具体を知らないfetch とか Date とか触らない)

🙅‍♀️

  • 外側が中心に合わせる(アダプタが頑張る)🔧
  OK✅: 外側 ---> 境界(interface) ---> 中心
NG❌: 中心 ---> fetch / DB / Date / process.env

5) 例で体感しよ🍩💰

(中心と外側を分ける)題材:クーポン付きの合計金額🧾✨

🏠 中心(純粋ロジック)

例* 入力:商品リスト、クーポン情報

  • 出力:合計金額
  • 外部に触れない(I/Oなし)✅
type Item = { name: string; price: number; qty: number };
type Coupon = { type: "percent" | "yen"; value: number } | null;

export function calcTotal(items: Item[], coupon: Coupon): number {
const subtotal = items.reduce((sum, it) => sum + it.price * it.qty, 0);

if (!coupon) return subtotal;

if (coupon.type === "percent") {
return Math.floor(subtotal * (1 - coupon.value / 100));
}
return Math.max(0, subtotal - coupon.value);
}

↑ これ、テストが超ラクになる予感しない?😆🧪✨ 「中心」はこういう データ入れて→結果が返る が理想だよ🍰💕


🌍 外側(I/O)

側の例(ここが変わりやすい)* クーポンをAPIから取る

  • 商品をDBから取る
  • 結果を画面やログに出す

この章では“実装”よりも、ここが外側だって気づけるのが大事だよ👀✨


6) ハンズオン:図を描く練習🖊️

🗺️(超だいじ!)### ステップ1:題材を1つ選ぶ🎲✨

どれでもOK👇

  • ログイン判定(期限切れチェック)🔐
  • 文字列整形(名前の整形、郵便番号の整形)📝
  • 料金計算(割引、送料、税)💰

ステップ2:中心と外側を箱で描く📦テンプレ👇(まずはコピペして埋めるだけでOK!

【中心🏠】(ルール・計算・判断)
- 例:____________________________________

【外側🌍】(I/O・外部依存)
- 例:____________________________________
- 例:____________________________________

【境界🚪】(中心が欲しい“最小の約束”)
- 例:____________________________________

ステップ3:「I/Oっぽい単語」を見つけたら外側に置く👃

💨見つけたら即外側!🚨

  • fetch / HTTP / API
  • DB / SQL
  • ファイル読み書き
  • Date / 時刻
  • 乱数
  • process.env
  • ログ出力

7) “境界”の作り方の感覚(最小でOK)

✂️📜境界はね、欲張ると一気に崩れるの🥺💦 コツはこれ👇

  • 中心が本当に必要な操作だけにする
  • ✅ 返す型は「中心が扱いやすい形」を意識する
  • ✅ 外側の都合(HTTPレスポンスそのまま等)を漏らさない

8) AI活用ミニコーナー🤖🎀(境界の練習に最高!

)AIにお願いする時は、「中心/外側/境界」を言葉で縛ると良いよ✨

👍 良いプロンプト例* 「次の仕様を、中心(純粋ロジック)

と外側(I/O)に分けて、境界(interface)案も出して。中心は fetch/Date/env/log を触らないで」

👎 ダメになりがち例* 「実装全部作って」

→ だいたい中心がI/Oまみれになって戻ってくる😇💥


9) 最新事情メモ🆕📝

(この章の“背景”になる現実)設計の考え方自体は普遍なんだけど、外側(I/O)は特に変化が速いのがポイントだよ🌀 たとえば最近だとこんな動きがある👇

  • TypeScript は 5.9 のリリースノートが 2026-01-12 に更新されてるよ🧠✨ (TypeScript)
  • Node.js は v24 系が Active LTSとして扱われていて、セキュリティリリースも継続的に出てるよ🔒🛡️ (Node.js)
  • テスト周りだと Vitest 4.0 が 2025-10 に登場して、移行ガイドも更新されてるよ🧪⚡ (Vitest)
  • TypeScript は **ネイティブ化(TypeScript 7 “native preview” など)**の話も進んでて、速度改善が大きいテーマになってるよ🚀 (Microsoft Developer)

だからこそ、変わりやすい外側を中心から隔離しておくと、変更が怖くなくなるんだよね😊✨


10) まとめ🍀

✨(今日の合言葉)* 🏠 中心=ルール(なるべく純粋)

  • 🌍 外側=I/O(変わりやすい)
  • 🚪 境界=interface(最小の約束)
  • ➡️ 依存の矢印は中心へ向ける

次の章(第5章)で、いよいよ「この地図をそのままフォルダ構成・最小プロジェクト」に落としていくよ📁✨ その前に、今日のハンズオンの「箱3つテンプレ」、1個だけでも埋めてみてね〜😆🖊️💕