概要
ユーティリティとは「便利な関数」ではない。
それは再利用される前提で、構造的に責任を持たされた小さな設計単位である。
本稿では、ユーティリティ関数/モジュールを「共通化」「抽象化」「責務明示」の3軸で再定義し、合理的かつ破綻しない共通機能の構築法を解説する。
1. ユーティリティを再定義する
// ❌ なんでも入る「utils.js」
export function doSomething() { ... }
export function isOk() { ... }
→ ✅ 責務ごとに分類された設計
utils/
├─ date.ts
├─ string.ts
├─ array.ts
├─ dom.ts
- ✅ “機能の名前”ではなく“責任の範囲”で構成する
- ✅ ドメイン関数との境界を明確に
2. 名前で責務を伝える
// ❌ 曖昧
format(val);
// ✅ 意図を具体化
formatDateToISO(date);
formatCurrencyToJPY(price);
- ✅ ユーティリティ関数は“名前だけで意味が読める”のが理想
- ✅ 意味が曖昧なら抽象化のしすぎ or 共通化する必要なし
3. 外部ライブラリ vs 内製ユーティリティの判断軸
機能 | 対応 |
---|---|
ソート、マップ、グルーピング | Lodashなどで可 |
特定業務ルールを含む処理 | 内製化 |
一般的な日付フォーマット | date-fnsなど |
日本語特有の表記変換 | 内製ユーティリティ化 |
→ ✅ 外部ライブラリは**“共通知識”の委譲**
→ 内製ユーティリティは**“ドメイン固有の知識”の形式知化**
4. ユーティリティを設計する7つの原則
- 引数は少なく、シンプルに
- 副作用を持たない(純粋関数)
- 引数・戻り値の型を明確に
- ドメインロジックと分離する
- 依存関係を最小限に保つ
- 名前に処理内容と目的を込める
- テストを書いて初めて完成
5. “地獄のutils.js”を避ける設計指針
❌ なんでもutilsに入れてしまう
→ ✅ useXxx()
(フック) or services/
, adapters/
に責任を分離
→ ✅ “純粋な値処理だけ”をutilsに限定する
utils/
├─ formatDate.ts
├─ parseCSV.ts
└─ escapeHTML.ts ← OK
adapters/
└─ localStorageAdapter.ts ← 副作用を扱う
6. ドメインロジックと汎用処理の明確な境界
// ❌ 業務ロジックと混在した関数
function validateUserAge(age) {
return age > 20 && String(age).length === 2;
}
// ✅ 汎用処理を抽出
function isAdult(age) {
return age >= 20;
}
function isTwoDigit(num) {
return String(num).length === 2;
}
→ ✅ “何が業務知識か”“何が再利用対象か”を設計時に分離する
設計判断フロー
① この関数は純粋か? → OKならutils対象
② 名前だけで何をするかわかるか? → NGなら分割or明示命名
③ 依存ライブラリで十分では? → 再利用性の高い処理なら外部委譲を検討
④ ドメイン知識が混在してないか? → 責務に応じてservicesやadaptersへ
⑤ テストで扱いやすいか? → 非同期や副作用を含んでいないか確認
よくあるミスと対策
❌ utils.ts
が 1000行を超えて肥大化
→ ✅ 機能単位 + 責任範囲ごとにファイル分割
❌ “便利だから”と無計画に関数化
→ ✅ 「同じ処理が3回以上登場したとき」が関数化の起点
❌ 再利用前提で作ったが、実際には1箇所でしか使われてない
→ ✅ 共通化の前に「使い回す必要があるか?」を冷静に判断
結語
ユーティリティとは、“便利”ではなく、“意味を持った最小単位”である。
- それは再利用されるために設計され
- 責務のない共通化を拒絶し
- 明確な名前と構造で存在する
JavaScriptにおけるユーティリティ設計とは、
「無秩序な関数群」ではなく、「知識の再利用戦略」である。