概要
モジュール化とは「ファイルを分けること」ではない。
それは**“依存関係を明示し、責務と再利用性の境界線を構造として定義する設計行為”**である。
JavaScript(特にESModules)では import/export
を使ってコードをモジュール化するが、
その背後には設計レベルでのスコープ管理、責務分離、依存方向の制御が存在する。
本稿では、モジュールスコープの設計原則と、import/exportによる依存制御の構造戦略を整理する。
1. モジュールとは「名前空間 + スコープ + 依存」の集合体
// utils/calc.js
export function add(a, b) {
return a + b;
}
// main.js
import { add } from './utils/calc.js';
- ✅ 関数名や変数がグローバルに漏れない
- ✅ 必要な関数だけを取り込むことで、意図が明示される
2. exportの種類と構造戦略
// Named export(推奨)
export function parse() {}
export const VERSION = '1.0';
// Default export(避けるべき)
export default function parse() {}
- ✅ Named export は複数同時出力・明示的importに強い
- ❌ Default export はリネーム自由のため依存が曖昧になる
// Good
import { parse } from './parser.js';
// Bad
import something from './parser.js'; // 「何をimportしてるか不明」
3. スコープレベルと公開範囲の管理
// util/logger.js
function format() { ... } // ローカル専用
export function log(msg) {
console.log(format(msg));
}
- ✅ 外部に公開するのは必要最小限に
- ✅ **「exportする = 公共インターフェース」**という認識を持つ
4. 依存の分離と逆流防止(依存方向の正規化)
[ UI層 ] → [ アプリケーション層 ] → [ ドメイン層 ]
- ✅ 依存関係は「一方向」に流す
- ❌ UI層からドメイン層が
import
される構造は正しく、逆は原則禁止 - ✅ 共通utilは汎用モジュールとして分離し、上下からアクセス可能にする
5. Barrel設計でモジュール境界を整理する
// index.js(Barrel)
export * from './parse.js';
export * from './format.js';
// consumer側
import { parse, format } from './utils';
- ✅ 複数モジュールの集約ポイントを設けて整理
- ✅ 複雑なパスや多重importの負債を軽減
設計判断フロー
① exportしている関数は「他から使われるべき」ものか?
② default exportは使っていないか?(import先で曖昧になる)
③ モジュール間の依存関係は一方向に流れているか?
④ 汎用関数・共通定義はutil層として分離されているか?
⑤ モジュールを集約するBarrel設計(index.jsなど)は導入されているか?
よくあるミスと対策
❌ default exportを多用し、何が何か分からなくなる
→ ✅ Named export + 明示的importで構造の透明性を確保
❌ ドメイン層がUI側をimportしていて依存が逆流
→ ✅ ドメイン → アプリケーション → UI の一方向依存を徹底
❌ utilや型定義が各モジュールに分散している
→ ✅ 共通モジュール(lib, utils, types)として分離・集約
結語
モジュール設計とは「ファイルを分けてコードを短くする」ことではない。
それは**“依存関係と責務を設計的に明示し、再利用性・保守性・拡張性を備えた構造を築くための戦略”**である。
- exportは「設計上の公開インターフェース」
- importは「依存関係の明示」であり、「構造の一方向性」を反映
- モジュールとはスコープ・責務・流れをコントロールするための単位である
JavaScriptにおけるモジュール設計とは、
“スコープと依存の責任を構造として可視化するための設計戦略”である。