2
2

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

概要

ユーティリティ関数は、共通処理を抽象化・再利用するための最小単位である。
しかし一方で、それが「ただの便利関数集」になると、

  • スコープの不明瞭さ
  • 副作用の混入
  • 汎用性の破壊
    といった問題を引き起こす。

本稿では、ユーティリティ関数を「アプリケーションを構造的に支える基盤」として設計するための原則と戦略を解説する。


1. ユーティリティ関数の定義と分類

// 計算系
const clamp = (value, min, max) => Math.max(min, Math.min(max, value));

// 判定系
const isNullish = (val) => val === null || val === undefined;

// 変換系
const toSnakeCase = (str) => str.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
  • 純粋であること(副作用を持たない)
  • 小さく、明確な責務を持つ
  • 入力と出力が完全に制御可能

2. 共通処理として抽出すべき基準

判断基準
同じ処理が3回以上現れる 日付フォーマット、数値変換
条件分岐で頻繁に使うロジック null判定、型判定
テストの独立単位にできる 計算処理、正規化処理
複数の層(UI/ドメイン)で利用される ID生成、トークン付加、形式変換

3. 責務分離と汎用性のトレードオフ

// ❌ 責務が混在した関数
function formatUser(user) {
  if (!user) return 'N/A';
  return `${user.firstName} ${user.lastName}`;
}
// ✅ 単一責務に分割
const formatName = (first, last) => `${first} ${last}`;
const isUserValid = (user) => user && user.firstName && user.lastName;

function safeFormatUser(user) {
  if (!isUserValid(user)) return 'N/A';
  return formatName(user.firstName, user.lastName);
}
  • ✅ 汎用性を保つには「粒度の分離」が鍵
  • ユーティリティ関数は低レイヤに位置付け、特定文脈に依存しないこと

4. 命名と責務の可視化

命名指針 意図
isXxx 判定関数(boolean返却)
toXxx 変換関数(形式変更)
createXxx 新しい構造の生成
formatXxx 出力用の表現調整
getXxxFromYyy 特定構造からの抽出
  • ✅ 命名は責務そのものを示すものに統一
  • ✅ 関数の型だけで使い方が想起できる設計にする

5. テストと再利用を前提とした構造

// dateUtils.ts
export const toISODate = (d: Date) => d.toISOString().split('T')[0];
export const isWeekend = (d: Date) => [0, 6].includes(d.getDay());
  • モジュール単位で目的別に分類(e.g. stringUtils, arrayUtils, dateUtils
  • ✅ 関数ごとの単体テストが簡単に書けるように副作用は排除
  • ✅ 共通処理はドメイン層ではなく基盤層に配置する

設計判断フロー

① この処理は1つの目的だけに特化しているか? → YES → ユーティリティ候補

② 他の文脈(UI/サーバー)でも使えるか? → YES → 抽出すべき

③ 依存する状態や副作用はないか? → NO → 安全にメモ化・テスト可能

④ 再利用前提の命名になっているか? → YES → 読みやすさ・維持性が向上

⑤ モジュールごとに責務が整理されているか? → YES → スケーラビリティ確保

よくあるミスと対策

❌ 一度しか使わないロジックを「とりあえずutils.ts」へ放り込む

→ ✅ 再利用性が見込めないなら、ローカル関数で閉じるべき


❌ 複数の責務を1つのユーティリティ関数でまとめている

→ ✅ 構成単位ごとに分離し、責務を明示する


❌ 副作用のある処理(console.logやDOM操作)を含む

→ ✅ ユーティリティ関数は必ず「純粋関数」で設計する


結語

ユーティリティ関数とは「小さな便利関数」ではない。
それは**“アプリケーションのあらゆる層を横断して支える、責務と再利用の設計単位”**である。

  • 再利用性と責務の分離は両立可能
  • 命名、構造、スコープを戦略的に整えることで、コード全体の保守性が跳ね上がる
  • 純粋で、予測可能で、明示的な「部品」が、堅牢なシステムを構成する

JavaScriptにおけるユーティリティ設計とは、
“小さくて強い機能を明確に分離し、全体構造に美しさを宿す戦略である。”

2
2
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
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?