第10章:低結合の入口 “import依存” を見える化👀🔗
この章でできるようになること🎯✨
- 「どこが結合強いか」を importの矢印 で発見できる👁️
- 依存の集中(ボトルネック) と 循環依存(circular deps) を見つけられる🕸️😱
- 手描き→ツールで自動化、の流れで「変更が伝染する場所」を潰せるようになる💪🔥
1) importの矢印は「変更が伝染する道」🗺️➡️

モジュールAがモジュールBをimportしてるなら、
A → B(AはBに依存) だよね🔗 この矢印が増えるほど…
- 変更の影響範囲が読めなくなる😵💫
- ちょい修正が「雪崩」になる💥
- リファクタが怖くて動けなくなる🥶
だからこの章は、まず 矢印を見える形にする のがゴールだよ〜👀✨
2) まずは手描きでOK!依存マップ作り✍️📌
ツールの前に、人間の目でも分かる地図 を1回作るのがめっちゃ効くよ🫶
手描き手順(超かんたん)🧸
-
箱(モジュール)を6〜10個だけ 選ぶ📦
- 例:UI / UseCase / Domain / Infra / 共通 みたいに
-
各箱の「入口ファイル」を決める🚪
- 例:
ui/index.ts、usecase/index.tsなど
- 例:
-
importを見て 矢印を引く(細かいファイル単位じゃなくてもOK)➡️
-
矢印に 目的メモ を添える📝
- 「型だけ」「API呼び出し」「表示整形」など
-
最後にチェック✅
- 矢印が集中してる箱(←ここが怖い)😨
- 双方向の矢印(←循環のにおい)🔁
- 境界を跨ぎまくる矢印(←混在のにおい)🍲
3) “ヤバい形” だけ先に覚えよ👃💦
3-1) 依存の集中(ボス箱)👑📦
「みんながそこをimportしてる」箱があると、そこが変更の震源地になる💥
「みんながそこをimportしてる」箱があると、そこが変更の震源地になる💥
- 直すと全体が揺れる
- テストしないと怖い
- 作業が詰まりやすい
3-2) 循環依存(circular deps)🕸️😱
AがBをimport、BがAをimport…みたいなループ🔁 これは “順番”の問題 が起きやすくて、実行時に値がundefinedっぽくなったり、開発体験が悪化したりするよ😵
特にVite開発中、循環依存があると HMRが効かずフルリロード になることがある(しかも直しにくい…!)😇 Vite公式のトラブルシュートでも「循環依存だとフルリロードになるからループを壊してね」と書かれてるよ。 (vitejs)
4) 自動で見える化①:dependency-cruiser 🚢✨
「依存の検査」も「図の生成」もできる、超強い道具だよ💪 TypeScript/JavaScriptの依存を解析して、ルール違反(循環とか)を検出できる系。 (GitHub)
4-1) 最短で動かすコマンド🛠️
npm i -D dependency-cruiser
npx depcruise --init
これで設定ファイルができるよ(まずはデフォルトでOK)✨
4-2) 循環依存があるかチェック🔍

npx depcruise src --config --output-type err-long
結果に “no-circular” みたいなのが出たら、そこがループの入口だよ🕸️
4-3) 依存グラフをSVGで出す🖼️✨
dependency-cruiserはDOT形式を出せるので、Graphvizの「dot」でSVGにできるよ🪄 (dotは標準入力から読めるからパイプで繋げられるやつ!) (Graphviz)
npx depcruise src --config --output-type dot | dot -Tsvg > deps.svg
deps.svgをブラウザで開くと、矢印の地獄が見えるよ😇
※ dot -Tsvg みたいな変換はGraphvizのコマンド仕様どおりだよ。 (Graphviz)
5) 自動で見える化②:madge 🐙📈
madgeは「依存グラフ作る」「循環依存見つける」専門の人気ツールだよ✨ READMEでも「視覚的グラフ」「循環依存の検出」って明言されてる。 (GitHub)
5-1) 循環依存だけ見たい(まずこれ)👀
npx madge --circular src
5-2) グラフ画像を出したい🖼️
Graphvizが入ってるとSVGも出せる(madge側もGraphvizが必要って書いてあるよ) (GitHub)
npx madge src --image madge.svg
5-3) tsconfigのパス別名を使ってる時🧩
madgeは tsConfig を渡せる(tsconfigで解決するため)って設定があるよ。 (GitHub)
npx madge src --ts-config tsconfig.json --circular
6) “循環依存” が起きやすい典型パターン🍲💥
初心者がハマりやすいの、だいたいこれ〜😭
パターンA:barrel(index.ts)経由でループ🔁
ui/index.tsが色々exportusecaseがui/index.tsをimport(通知とかトーストとか)uiがusecase/index.tsをimport → はい、ループ完成🕸️😇
パターンB:「型だけ」のつもりがループ🎭
「型だけだからOKでしょ〜」って気持ち、めっちゃ分かる…! でも 型importが結局依存の矢印になる から、境界を跨ぐと絡まりやすいよ🧶
7) 見つけた循環依存、どう壊す?(入口だけ)🔨✨
第11章(関数DI)で本格的にやるけど、ここでは“入口”だけね😉
壊し方の定番3つ🎀
-
共有物を中立地帯へ引っ越し 📦
- UIでもUseCaseでもない「shared(薄い)」へ
-
通知・ログ・時計などは“外から渡す” 🎁
- usecaseがUIを知らなくて済む
-
UIの都合(表示用整形)をusecaseに持ち込まない 🚫
- “表示のための関数”はUI側へ寄せる
8) ハンズオン🛠️:あなたのプロジェクトでやろう✅🎉
ステップ1:依存マップを手描き(10分)✍️
- 箱:
ui / usecase / domain / infra / shared(なければ近いのでOK) - 矢印を引く
- 「矢印が多い箱TOP1」を丸で囲む⭕
- 「双方向っぽい所」を赤丸🔴
ステップ2:ツールで答え合わせ(10分)🧪
npx madge --circular srcを実行npx depcruise src --config --output-type err-longを実行- それぞれで出た循環パスを、手描き地図に書き足す📝
ステップ3:1個だけループを壊す(15分)🔨
- いちばん短い循環から狙う🎯
- 「通知」「ログ」「整形」などを外に逃がす
- もう一回ツール実行して、循環が消えたら勝ち🏆✨
9) AIプロンプト🤖💬(この章はこれだけ!)
- 「この構造、循環依存が起きそうな点ある?疑わしい箇所を挙げて」🕸️🔍
(※できれば、あなたの
src構造ツリーと、怪しいimport数ファイルを貼ると精度UPだよ📎✨)
10) まとめ🎀
- 低結合の第一歩は importの矢印を見える化 👀🔗
- 手描き→ツール(dependency-cruiser / madge)で、依存の集中と循環を炙り出す🔥 (GitHub)
- 循環依存は開発体験も壊しやすい(ViteだとHMRがフルリロードになったり…)😇 (vitejs)
次の第11章は、見つけた結合をほどくための「引数で渡す(関数DI)」に突入だよ🎁✨