2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScriptにおけるモジュール分離と依存戦略:レイヤー設計、境界の定義、循環参照の防止構造

Posted at

概要

モジュールとは「機能をまとめる箱」ではない。
それは責務・依存・拡張性・再利用性を保証する、構造的な単位である。

JavaScriptでのモジュール設計は、その柔軟さから無秩序な依存・結合・循環を生みやすい。
それを制御し、壊れない構造・テスト可能な分離・変更に強い境界を設計することが不可欠になる。

本稿では、依存構造を制御するためのレイヤー分離、境界戦略、循環参照の防止技術を解説する。


1. モジュール構造は「責務」で分ける

src/
├─ features/
│   ├─ user/
│   │   ├─ index.ts
│   │   ├─ service.ts
│   │   └─ validator.ts
│   └─ auth/
│       ├─ login.ts
│       └─ session.ts
├─ libs/
│   ├─ api.ts
│   └─ storage.ts
  • 機能単位(Feature-Based) で分離
  • ✅ 機能間を直接依存させず、共通ライブラリ越しに橋渡す

2. レイヤー設計と依存方向の一方向化

UI → Application → Domain → Infrastructure
  • ✅ 上層から下層へは依存可能
  • ❌ 下層から上層への逆依存は禁止
  • ✅ 依存の方向性は「読みやすく」「テストしやすく」「循環を防ぐ」

3. 循環参照の検出と防止

✅ 循環参照の症状

  • undefinedが返ってくる
  • Cannot read property エラー
  • 静的解析エラー(ツールによっては)

✅ 対策

  • 明確な依存境界を引く(依存のハブを作らない)
  • index.ts の双方向import禁止
  • depcheck, madge, eslint-plugin-import などで検出

4. 共通ロジックは “低層に抽象化して” 橋渡す

features/
├─ user/
│   └─ useUser.ts → domain/user.ts + libs/api.ts を使う
  • ✅ 共通処理(ログ、バリデーション、変換)は libs 層で抽象化
  • ✅ features から直接他の features に依存しない

5. DI(依存注入)と Adapter層の活用

// domain/use-case.ts
export function createUserService({ userRepo }) {
  return {
    getUser: () => userRepo.find(),
  };
}
  • 依存を明示的に渡す構造で、テスト・差し替えが容易に
  • ✅ Adapter層で外部依存(API, DB)とのインターフェースを統一

6. index.ts は「公開窓口」であり、構造を隠す

// features/user/index.ts
export { createUserService } from './service';
  • ✅ 公開する機能だけを index.ts に定義
  • ✅ 内部構造は外部から見えないようにし、意図的に使わせる構造へ

設計判断フロー

① このファイルが他モジュールに依存していないか? → 依存構造を可視化

② 双方向のimportが発生していないか? → 共通化 or 分離構造へ

③ UIとロジックが同一モジュールにないか? → Presentation / Logic の分離

④ 共通ロジックがfeature配下に埋もれていないか? → libs層に抽出

⑤ テスト用モックが依存に組み込めているか? → DI構造へ移行

よくあるミスと対策

❌ features同士でimportし合って依存が複雑化

→ ✅ 共通処理はlibs層に抽象化して橋渡す


❌ index.ts が再帰的にindex.tsを読み込み循環参照

→ ✅ index.tsは1方向の“公開インターフェース”だけに使う


❌ APIやDBを直接サービスで呼び、テスト不能に

→ ✅ use-case + DI構造 + Adapter層で依存を外部化


結語

モジュールとは「コードを分けること」ではない。
それは**“意味・依存・責任を構造化し、破綻を防ぐための戦略単位”**である。

  • 機能でモジュールを切り
  • 依存は一方向に制御し
  • 外部はAdapterに抽象化し
  • 公開構造はindexで制御する

JavaScriptにおけるモジュール依存戦略とは、
“複雑さを壊さず拡張可能に保つための、構造的ガードレール”である。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?