概要
ユーティリティ関数とは「よく使う処理」ではない。
それは**“本質的ではない処理をドメインロジックから追い出し、構造を純粋に保つための抽象”**である。
JavaScriptの開発において、形式変換・日付操作・バリデーション・文字列整形などは本質とは異なるが必須の処理である。
これらを適切にユーティリティ関数として設計・整理することで、ロジックの見通し・再利用性・テスト性が劇的に向上する。
1. ユーティリティ関数の設計原則
✅ 「再利用される」ではなく「再利用可能である」ことが前提
- 依存がない(ピュア関数)
- 構造が小さい(1つの責務)
- 意味が明確(名前で処理内容が分かる)
function toUpperCaseFirst(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
2. 関数の抽出単位は「意味 + 頻度 + 汚れ」
✅ 以下の3条件で抽出判断:
① 意味が共通で汎用的
② 頻度が高い or 重要な流れを支える
③ ドメイン外の処理(=ロジックのノイズ)
// 抽出すべき例
function formatDate(date) {
return date.toISOString().split('T')[0];
}
3. ユーティリティ vs ドメインロジックの分離
❌ ドメイン層に日付の整形や文字列操作が散在
✅ ユーティリティに抽出してロジックは “業務の意味” だけに集中
// ドメイン層
const label = `契約日: ${formatDate(user.contractAt)}`;
4. ユーティリティ階層と分類
utils/
├─ date.ts → 日付操作
├─ string.ts → 文字列整形
├─ number.ts → 桁区切りや丸め
├─ array.ts → フィルタ・グループ処理
├─ validation.ts → 汎用バリデーション
- ✅ 領域別の抽象に整理
- ✅ index.tsで集約エクスポートすればimportも簡潔に
5. ユーティリティの過剰抽象を避ける
❌ 汎用性を追いすぎて意味が消える
function doSomethingToList(list, fn) {
return list.map(fn);
}
→ ✅ 意味ある用途に絞る方が保守性が高い
6. テスト性とユニット性の最大化
- ✅ ユーティリティ関数は最もテストしやすい領域
- ✅ 入出力が固定化されており副作用ゼロが理想
test('toUpperCaseFirst', () => {
expect(toUpperCaseFirst('hello')).toBe('Hello');
});
設計判断フロー
① 処理はドメインロジックの一部か? → 汎用ならユーティリティへ
② 関数は再利用可能な構造か? → 外部依存があれば再設計
③ 意味が明確か? → 名前と内容が一致しているかを確認
④ 処理を変更する頻度と影響範囲は? → 共通化が過剰でないか判断
⑤ テストがしやすいか? → 副作用・非同期・状態依存がないかを確認
よくあるミスと対策
❌ ドメイン層で文字列整形・日付変換を毎回書く
→ ✅ utils/
に抽出し、業務ロジックに集中
❌ 関数名が抽象的すぎて目的が不明
→ ✅ formatDate
, padZero
, groupBy
など用途が明確な名前にする
❌ utils関数がアプリ固有の依存を持って再利用不能
→ ✅ 引数と戻り値のみで完結する設計に限定
結語
ユーティリティとは「便利な関数」ではない。
それは**“ノイズを外に逃がし、本質を見通すための構造戦略”**である。
- ドメインから汚れを抽出し
- 領域ごとに整理し
- 再利用可能で安全に保ち
- テストしやすく設計する
JavaScriptにおけるユーティリティ設計とは、
“ロジックを純化し、構造を美しく保つための補助層のデザイン”である。