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におけるユーティリティ関数設計:DRY・汎用性・副作用最小化を両立するアプローチ

Posted at

概要

ユーティリティ関数(Utility Functions)は、
「何度も使う処理」や、「1つの責務に特化した処理」をまとめ、コード全体の再利用性・可読性・テスト性を高めるための設計部品である。

本稿では、以下の観点からユーティリティ関数のあるべき姿を探る:

  • DRY原則と再利用性の設計
  • 副作用の最小化と“純粋性”
  • 汎用性と限定性のバランス
  • ユーティリティ関数の命名と格納戦略
  • よくある実践例とアンチパターン

1. ユーティリティ関数の基本的条件

✅ 純粋関数であること(Pure Function)

function toUpper(str) {
  return str.toUpperCase(); // 引数と返り値だけ
}
  • ❌ グローバル変数の参照・更新をしない
  • ❌ DOMやネットワークに依存しない
  • ✅ 同じ入力に対して常に同じ出力

2. DRY原則と“意味の抽出”

// ❌ 重複
const fullName1 = user.first + ' ' + user.last;
const fullName2 = employee.first + ' ' + employee.last;

// ✅ 共通化
function getFullName({ first, last }) {
  return `${first} ${last}`;
}

→ ✅ ロジックの“意味”を名前で表現する


3. 汎用性を高めすぎない:責務を限定する

// ❌ 汎用すぎて逆に使いにくい
function process(data, type, mode) {}

// ✅ 責務を明示
function formatDate(date: Date, format = 'YYYY-MM-DD') {}

→ ✅ 呼び出し時の直感的理解を優先


4. 副作用を切り離す:関数の「純度」と設計

// ❌ UIやロガーを巻き込む
function logAndFormatDate(date) {
  console.log('called');
  return formatDate(date);
}

→ ✅ 副作用はラッパー関数に分離する


5. 命名と格納:意味と関心の一致

✅ 命名ガイドライン

  • 動詞 + 名詞 例:getFullName, isEmailValid
  • ブール値isXxx, hasXxx, canXxx
  • 短すぎず、責務を明示的に伝える

✅ 格納場所の一例

/utils
  ├── string.ts
  ├── array.ts
  ├── date.ts
  └── validation.ts

6. 再利用性の高い関数の具体例

✅ 値がnull/undefinedでないかを判定

export function isDefined(value) {
  return value !== null && value !== undefined;
}

✅ 配列の重複排除

export function uniqueArray(arr) {
  return [...new Set(arr)];
}

✅ オブジェクトの深いコピー(Shallow/Deep)

export function deepClone(obj) {
  return JSON.parse(JSON.stringify(obj)); // 限定的だがシンプル
}

✅ 簡易なメールバリデーション

export function isEmailValid(email) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

7. テストしやすい設計を意識する

// ✅ 純粋関数はユニットテストが容易
test('isDefined', () => {
  expect(isDefined(null)).toBe(false);
  expect(isDefined(0)).toBe(true);
});

→ ✅ 入出力だけに依存する構造が最良


設計判断フロー

① 処理が2回以上登場する? → ユーティリティ化を検討

② 状態を変更している? → 純粋関数化できるか確認

③ 他の関数と責務が被ってない? → 関数を分割・再定義

④ 汎用すぎていないか? → 呼び出し側の明確さ優先

⑤ テスト容易か? → グローバル依存・副作用を排除

結語

ユーティリティ関数は“単なる小さな関数”ではない。
それは、再利用性・読みやすさ・責務の明確さを構造に刻む設計装置である。

  • 名前に意味があり、
  • 責務が明快であり、
  • 副作用がなく、
  • どこでも使えて、
  • 壊れない

小さく設計されたユーティリティが、大きな信頼性を生む。
関数は“動作”ではなく、“構造”として設計すべきである。

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?