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

第2章 Dependency Ruleのコア:「中心(方針)」を「外側(詳細)」から守る🧭🎯

0) この章のゴール🏁

この章が終わったら、あなたがこう言えるようになるのがゴールだよ😊💕

  • 「Dependency Ruleって何?」→ 一言で説明できる
  • コードを見て「これは中心?外側?」って 仕分けできる🗂️
  • 「中心が外側に支配されてる事故」を 匂いで気づける🐶💡

(ちなみに最新のTypeScriptは 5.9.3 が安定版として出ていて、次の大きな節目として 6.0/7.0 系の話も進んでるよ〜!でもこの章のルールは、バージョンが進んでもずっと効く“設計の基本”🧡) (GitHub)


1) まず一言で言うと?📣✨

Dependency Rule を超ざっくり言うと…

**「変わりやすい外側(UI/DB/HTTP/ライブラリ)が、変えたくない中心(業務ルール)を支配しないようにするルール」**🛡️✨

これだけ覚えてOK!🙆‍♀️💕


2) 「中心」と「外側」ってなに?🧅💭

✅ 中心(方針 / Policy / コア)🧠💎

「アプリが提供したい価値」「業務ルール」「やりたいことの本体」だよ!

  • 例:ToDoなら

    • 「完了済みは編集できない」
    • 「締切が過ぎたら警告する」
    • 「タイトルは1〜50文字」 みたいな ルール📏✨

✅ 外側(詳細 / Details)🌍🧰

中心を動かすために必要だけど、入れ替わりやすい道具たち!

  • DB(SQLite/Postgres/ORMなど)🗄️
  • HTTP(fetch/axios/サーバーFW)🌐
  • UI(React/Vue/CLI)🖥️
  • SDK・外部API(決済、地図、認証)🔑
  • 便利ライブラリ(ログ、日付、バリデーション)📦

外側はね、「流行・都合・環境」でコロコロ変わるのが普通なの😵‍💫


3) なぜ「中心を守る」のが正義なの?💪✨(変更の波🌊)

外側って、こんな理由でよく変わるよね👇

  • UIを変えたい(デザイン刷新)🎨
  • DBを変えたい(性能/コスト)💸
  • API仕様が変わった(外部要因)📡
  • ライブラリのメジャーアップデートで壊れた(あるある)💥

ここで中心が外側にくっついてると…

  • DB変更しただけなのに、業務ルールまで修正…😱
  • UIの都合で、中心の型や設計が歪む…😵
  • 変更が怖くなって、開発速度が落ちる…🐢💦

だから 「中心は落ち着いてて、外側だけが付け替え可能」 が理想なんだ🧘‍♀️✨


4) 依存の“矢印”ルール➡️(ここがコア!)

Dependency Rule の超重要ポイントはこれ👇

依存(import)の矢印は、外側 → 中心 に向ける🧲✨ 中心 → 外側 に向けない🚫

イメージ図(ざっくり)👇

[ UI / HTTP / DB / Framework ]  ----->  [ Domain / UseCase / Policy ]
外側(変わりやすい) 中心(変えたくない)

中心が「外側の都合」に引っ張られた瞬間に、設計が崩れやすくなるよ〜!😵‍💫💥


5) よくある「事故の匂い」🐽💥(中心が汚染されてるサイン)

🚨 サインA:中心に “DBの型” が出てくる

例:「ドメインの中で Prisma の型を使ってる」みたいなやつ。

  • 中心がDBの都合を背負う → DB変更が地獄👿

🚨 サインB:中心が “fetch/axios” を直接呼んでる

  • 中心がHTTPの都合を背負う → API変更が地獄👿

🚨 サインC:中心の関数が「画面の都合の引数」を持ち始める

  • 例:isModalOpen とか selectedTab とか、UIの状態が中心に入ってくる → 中心がUIに引っ張られる😵

6) ちいさな例で体感しよ🧪✨(ダメ🙅‍♀️→OK🙆‍♀️)

❌ ダメ例:中心(domain)が外側(fetch)を知ってる😱

// src/domain/todoPolicy.ts (中心のつもり…なのに外側に依存してる😭)
export async function canEditTodo(todoId: string): Promise<boolean> {
const res = await fetch(`/api/todos/${todoId}`); // ← 外側(HTTP)に依存!😱
const todo = await res.json();
return !todo.completed;
}

これだと、APIのURL変えたら中心が壊れるし、テストもやりにくいよ〜🥺💦

✅ OK例:中心は「ルール」だけ、外側は「取りに行く」だけ🏆

// src/domain/todoPolicy.ts(中心:純粋にルールだけ✨)
export type Todo = { id: string; completed: boolean };

export function canEdit(todo: Todo): boolean {
return !todo.completed;
}
// src/adapters/todoApi.ts(外側:HTTPで取ってくる役🌐)
import type { Todo } from "../domain/todoPolicy";

export async function fetchTodo(todoId: string): Promise<Todo> {
const res = await fetch(`/api/todos/${todoId}`);
return await res.json();
}
// src/app/checkEditable.ts(手順:つなぐ役🔗)
import { canEdit } from "../domain/todoPolicy";
import { fetchTodo } from "../adapters/todoApi";

export async function checkEditable(todoId: string): Promise<boolean> {
const todo = await fetchTodo(todoId);
return canEdit(todo);
}

この形だと、HTTPの都合が変わっても 直すのは adapters 側だけになりやすい✨ 中心は “ルールのまま” で落ち着いていられる🧘‍♀️💕


7) ミニ演習:中心/外側を色分けしてみよ🎨📝(超だいじ!)

次の要素を「中心」「外側」に仕分けしてみてね👇(頭の中でOK!)

  • A. Todo 型(タイトル・完了フラグ)
  • B. 「完了済みは編集不可」ルール
  • C. fetch("/api/todos")
  • D. DBのテーブル設計(カラム名とか)
  • E. 画面のボタン配置
  • F. 「締切を過ぎたら警告」ルール
  • G. 外部APIのレスポンスJSON

✅ 答え(ざっくり)

  • 中心:A, B, F
  • 外側:C, D, E, G

ポイントは「中心は価値・ルール」「外側は入れ替わる道具」だよ😊✨


8) 今日から使えるチェックリスト✅🧡

コード見た瞬間に確認するやつ👇

  • 中心(domainっぽい場所)で fetch/axios/DB/SDK を import してない?🚫
  • 中心の型に DBカラム名やAPIレスポンスの都合が混ざってない?🧼
  • UIの状態(タブ、モーダル等)が中心に侵入してない?🖥️🚫
  • 「ルール(中心)」と「手順(つなぐ)」と「外部I/O(外側)」が分かれてる?🧅✨

9) AI🤖に頼むと超はかどるプロンプト集💌✨

(CopilotでもCodex系でも、だいたい効くよ!)

🧭 分類してもらう

  • 「このファイル一覧を“中心/外側”に分類して、理由も一行ずつ書いて」📌

🕵️‍♀️ 依存の違反を見つけてもらう

  • 「domain 配下から外部I/O(fetch/DB/SDK)に依存してる import を指摘して」🔎

🔧 修正案を出してもらう

  • 「中心にある外側依存を adapters に移すリファクタ案を、手順で出して」🛠️

まとめ💐✨

  • 中心(業務ルール)を、外側(UI/DB/HTTP/SDK)から守るのが Dependency Rule🛡️
  • import の矢印は 外側 → 中心 が基本➡️
  • 事故の匂いは「中心にfetch/DB/UI都合が入ってくる」こと😱
  • この章ができると、次の「境界を作る(フォルダ分け)」がめちゃ楽になるよ📁✨

次章は「まずはフォルダ境界でOK!」ってやつに進むよ〜😊📦🧱