OmniAICreator/Qiita-1.07M huggingface dataset:
JavaScriptにおける関数型思考の導入：副作用排除・純粋性・合成可能性の設計戦略

## 概要

関数型プログラミングは“考え方”であり、“制約”ではない。  
JavaScriptでもその思想を取り入れることで、**コードは明確に、状態は安全に、ロジックは再利用可能に**なる。

本稿では、以下の視点から関数型思考をJavaScriptへ導入する：

- 副作用（Side Effect）とその管理
- 純粋関数とテスタビリティ
- 不変性（Immutability）と構造共有
- 高階関数と関数合成
- 実用ライブラリ（Ramda, Lodash/fp等）の活用

---

## 1. 副作用（Side Effect）の定義と排除

副作用とは、**関数の外部世界に影響を及ぼす操作**のこと。

例：DOM操作、ログ出力、API通信、グローバル変数の変更

```js
// ❌ 副作用あり
function saveUser(user) {
  localStorage.setItem('user', JSON.stringify(user));
}

// ✅ 副作用を外に逃がす
function serializeUser(user) {
  return JSON.stringify(user);
}
```

→ ✅ 副作用は関数外へ押し出し、**純粋ロジックと処理を分離**

---

## 2. 純粋関数とは？

- ✅ 同じ入力 → 同じ出力
- ✅ 外部状態に依存しない
- ✅ 外部状態を変更しない

```js
function add(a, b) {
  return a + b;
}
```

→ ✅ **テストが簡単、再利用しやすく、構成可能**

---

## 3. 不変性（Immutability）の維持

```js
// ❌ オブジェクトを直接変更
user.name = 'Toto';

// ✅ 新しいオブジェクトを返す
const updatedUser = { ...user, name: 'Toto' };
```

→ ✅ データ構造を破壊せず、安全に状態管理ができる

---

## 4. 高階関数（Higher-Order Functions）

### ✅ 関数を“受け取る”または“返す”関数

```js
function map(arr, fn) {
  const result = [];
  for (const item of arr) {
    result.push(fn(item));
  }
  return result;
}

map([1, 2, 3], x => x * 2); // [2, 4, 6]
```

- ✅ 抽象化と再利用のための中核パターン
- ✅ `.map`, `.filter`, `.reduce` もすべて高階関数

---

## 5. 関数合成（Function Composition）

### ✅ 関数をつなぎ、パイプライン化

```js
const trim = (s) => s.trim();
const toUpper = (s) => s.toUpperCase();

const cleanAndUpper = (s) => toUpper(trim(s));
```

→ ✅ 小さな関数をつないで大きな機能を構築する

---

### RamdaやLodash/fpの活用例

```js
import { pipe } from 'ramda';

const cleanAndUpper = pipe(
  (s) => s.trim(),
  (s) => s.toUpperCase()
);
```

→ ✅ **データフローを左→右で直感的に記述可能**

---

## 6. 実用例：ユーザーの年齢フィルタ → 名前抽出 → 大文字変換

```js
const users = [
  { name: 'toto', age: 28 },
  { name: 'momo', age: 18 },
  { name: 'kiki', age: 35 }
];

const result = users
  .filter(u => u.age >= 20)
  .map(u => u.name.toUpperCase());
```

→ ✅ 副作用なし、純粋関数による**安全なデータ変換チェーン**

---

## 設計判断フロー

```text
① この関数は同じ入力で同じ出力か？ → 純粋関数か確認

② 外部状態を変更していないか？ → 副作用を外部へ

③ 状態を破壊していないか？ → イミュータブルに扱う

④ 処理を関数で分けられるか？ → 高階関数で抽象化

⑤ 合成して流れにできるか？ → pipe / composeの導入
```

---

## よくあるミスと対策

### ❌ 関数内で外部変数を更新

→ ✅ 状態を引数で受け取り、出力で返す構造に

---

### ❌ 再利用性のない巨大な関数

→ ✅ 小さな純粋関数に分解し、合成する設計へ

---

### ❌ map内で副作用操作（console, fetchなど）

→ ✅ `.map()` は純粋関数だけに使うことを徹底

---

## 結語

関数型思考とは「ロジックを“構造化”し、状態を“制御可能”にする設計戦略」である。

- 副作用を隔離し
- 関数を分解し
- データを変換で流し
- 構造を組み合わせる

**予測可能性、テスタビリティ、再利用性――  
そのすべてが“純粋な関数”から生まれる。**
JavaScriptにおけるパフォーマンス最適化：レンダリング最小化・ループ戦略・メモリ制御による高効率コード設計

## 概要

パフォーマンスとは“速さ”だけではない。  
**不要な処理を省き、構造を整え、メモリを抑え、ユーザー体験を滑らかにする**――それがJavaScriptにおけるパフォーマンス最適化の本質である。

本稿では以下の観点で最適化を整理する：

- DOMレンダリングの最小化戦略
- ループとコレクション操作の効率化
- メモリリークの回避とガーベジコレクション
- 高頻度イベントのデバウンス／スロットリング
- Web API（`requestAnimationFrame`, `IntersectionObserver`）の戦略的活用

---

## 1. DOMレンダリングの最小化

### ❌ 毎回DOMを操作

```js
items.forEach(item => {
  const el = document.createElement('li');
  el.textContent = item;
  document.body.appendChild(el); // ❌ 逐次レンダリング
});
```

---

### ✅ DocumentFragmentで一括操作

```js
const fragment = document.createDocumentFragment();

items.forEach(item => {
  const el = document.createElement('li');
  el.textContent = item;
  fragment.appendChild(el);
});

document.body.appendChild(fragment); // ✅ 一括レンダリング
```

→ ✅ レンダリングを最小限にまとめる

---

## 2. ループ・コレクション操作の選定

- ✅ `for` ループは最速（キャッシュ可）
- ✅ `.map()` / `.filter()` は可読性重視
- ❌ `.forEach()` 内でDOM操作 or asyncは非推奨

```js
for (let i = 0, len = arr.length; i < len; i++) {
  // ✅ 長大配列はキャッシュで高速化
}
```

---

## 3. メモリ管理とリーク回避

### ❌ イベントリスナーの解除忘れ

```js
element.addEventListener('click', handler); // ❌ 永続参照
```

---

### ✅ 明示的に remove

```js
element.removeEventListener('click', handler); // ✅ クリーンアップ
```

---

### ✅ WeakMap で自動GCを活用

```js
const cache = new WeakMap();

function bind(el, data) {
  cache.set(el, data); // ✅ DOMが消えれば自動破棄
}
```

---

## 4. 高頻度イベントの最適化

### ✅ Debounce / Throttle

```js
function debounce(fn, delay) {
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };
}

window.addEventListener('resize', debounce(updateLayout, 300));
```

- ✅ resize, scroll, input などには必須
- ✅ 処理頻度を抑えることでUIの滑らかさを維持

---

## 5. `requestAnimationFrame` を用いたアニメーション制御

```js
function animate() {
  updatePosition();
  requestAnimationFrame(animate);
}
animate();
```

- ✅ 描画タイミングに同期し、60fpsで制御
- ✅ setIntervalよりも自然でバッテリーフレンドリー

---

## 6. IntersectionObserverで遅延処理

```js
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      loadImage(entry.target);
      observer.unobserve(entry.target);
    }
  });
});

document.querySelectorAll('img[data-src]').forEach(img => observer.observe(img));
```

→ ✅ ビューポート内の要素だけ処理して不要なレンダリングを回避

---

## 7. スクリプト分割と非同期ロード（モダン構成）

- ✅ `type="module"` による遅延ロード
- ✅ import() による動的モジュール分割
- ✅ ライブラリサイズを考慮して必要最小限に限定

---

## 設計判断フロー

```text
① レンダリング頻度が高い？ → DOM操作をバッチ化（Fragment, innerHTML）

② データ量が多い？ → forループ + キャッシュで高速化

③ 長期参照してる？ → イベント解除・WeakMapで管理

④ イベント発火頻度が高い？ → debounce/throttleを適用

⑤ 描画タイミングに応じた処理？ → requestAnimationFrameを使用
```

---

## よくあるミスと対策

### ❌ 動的生成のたびにDOMを直接操作

→ ✅ Fragmentやテンプレートのクローンを使う

---

### ❌ スクロールやリサイズで毎フレーム処理

→ ✅ throttleかrequestAnimationFrameで制御

---

### ❌ 大量データを map/filter で何度も変換

→ ✅ 一時変数・memo化を導入し冗長処理を削減

---

## 結語

JavaScriptのパフォーマンス最適化は“魔法の高速化”ではない。  
それは、**「構造を整え、必要な処理だけを、必要なタイミングで実行する」設計的技術**である。

- ムダなレンダリングは避ける
- DOM操作は一括で
- 高頻度イベントは制限する
- メモリを意識し、消せる構造を作る
- ブラウザが持つ最適なAPIを使いこなす

**最適化とは、削ることではない。  
“意味のない負荷を削ぎ落とし、意味ある処理だけを残す”――それが本質である。**
JavaScriptにおけるDOM構造操作とアクセシビリティ：動的要素と構文的責任の分離戦略

## 概要

DOM操作は**UIを構築する力**であると同時に、**アクセシビリティ（a11y）を破壊する力**でもある。  
見た目だけでなく、**構造的意味・操作性・ナビゲーション可能性**を保ったままDOMを動的に変更することが、モダンなJavaScript UI設計には求められる。

本稿では以下の観点で整理する：

- 意味論的HTMLとDOM操作の整合
- aria属性の設計と状態管理
- フォーカス管理とキーボードナビゲーション
- UI状態とDOM属性の同期
- ライブリージョンによる動的通知

---

## 1. 意味論的HTML（semantic HTML）との協調

### ❌ `div`ベースの構造操作

```js
const el = document.createElement('div');
el.innerText = 'Click me';
el.addEventListener('click', handleClick);
```

→ 非セマンティック、スクリーンリーダー未対応

---

### ✅ HTML5タグ + 明示的な属性

```js
const button = document.createElement('button');
button.innerText = '削除';
button.setAttribute('aria-label', 'この項目を削除');
```

- ✅ `button`, `nav`, `section`, `dialog` などのHTMLタグを優先
- ✅ アクション要素は `role="button"` ではなく`<button>`で

---

## 2. aria属性と状態同期

```js
const menu = document.getElementById('menu');
menu.setAttribute('aria-expanded', 'false');

function toggleMenu() {
  const expanded = menu.getAttribute('aria-expanded') === 'true';
  menu.setAttribute('aria-expanded', String(!expanded));
}
```

- ✅ 状態変更時に `aria-*` を**明示的に同期**
- ✅ `aria-expanded`, `aria-hidden`, `aria-pressed` など状態を語る属性を積極的に使う

---

## 3. フォーカス管理：動的要素とアクセシビリティの両立

```js
const modal = document.getElementById('dialog');
modal.showModal();
modal.querySelector('button.close').focus(); // フォーカスを送る
```

- ✅ ダイアログ表示時は**初期フォーカスを明示的に設定**
- ✅ `tabindex="-1"` を使ってJSからフォーカス可能にするのが定石

---

## 4. キーボードナビゲーション設計

```js
element.addEventListener('keydown', (e) => {
  if (e.key === 'Escape') {
    closeDialog();
  }
});
```

- ✅ Escape → ダイアログ閉じる  
- ✅ Enter/Space → ボタンを発火  
- ✅ 矢印キー → リストナビゲーション etc.

→ キーボード操作が**全UIと等価であること**が重要

---

## 5. aria-live：動的更新の通知

```html
<div id="announce" aria-live="polite" class="sr-only"></div>
```

```js
announce.textContent = '保存に成功しました';
```

- ✅ ユーザーに見えないが**スクリーンリーダーには通知される**
- ✅ `aria-live="polite"`（非強制） / `assertive`（即時）

---

## 6. UI状態とDOM構造の同期責任

```js
function toggleSection(section, isOpen) {
  section.setAttribute('aria-hidden', String(!isOpen));
  section.classList.toggle('hidden', !isOpen);
}
```

→ ✅ **視覚的状態（class）と意味的状態（aria）を同期させる**

---

## 7. モジュールとしての責任分離

- `dom/createButton.js` → ボタン生成
- `a11y/setAriaExpanded.js` → ARIA属性の更新
- `focus/trapFocus.js` → モーダル内でのタブ移動制御

→ ✅ 各ファイルが1つの意味的責務を担い、明示的な設計となる

---

## 設計判断フロー

```text
① 操作対象は何か？ → ボタン・入力など意味のあるHTMLタグを使う

② 状態がある？ → aria属性で状態を表現（expanded, pressed）

③ 動的UI？ → DOM更新に合わせてARIAやフォーカスも更新

④ 通知が必要？ → aria-liveで視覚外の情報を伝える

⑤ キーボード操作に対応しているか？ → keydown/keyupで補完
```

---

## よくあるミスと対策

### ❌ `<div>`をボタン代わりにクリックイベント

→ ✅ `button`タグで、アクセシビリティと自動フォーカスを確保

---

### ❌ 状態だけclassで制御、aria未設定

→ ✅ classとariaを**並行管理**する

---

### ❌ ダイアログやモーダルにフォーカスが移らない

→ ✅ `focus()` と `tabindex="-1"` を組み合わせて制御

---

## 結語

DOM操作とは、UIの見た目を変える技術ではない。  
それは**ユーザーがどう見るか、どう理解するか、どう操作するかを構造として設計する技術**である。

- 意味を持つHTMLを選び
- 状態を属性で語り
- 操作をキーボードと同期し
- 表示されない情報も伝える

**アクセシブルなDOM操作は、すべてのユーザーに届く設計である。  
その設計は、構文・視覚・操作性の三位一体で成立する。**
JavaScriptにおけるモジュール設計と依存管理：疎結合と再利用性を実現する分離戦略


## 概要

JavaScriptにおける“モジュール”とは、  
**機能・責務ごとに分割された再利用可能なコードの単位**であり、アプリケーションの複雑性に対抗する最小構成要素である。  
本稿では、**構造としてのモジュール設計、依存の分離、インターフェースの設計、抽象化の階層化**について、以下の観点から整理する：

- ESModulesとCommonJSの根本的な違い
- モジュール境界の定義と責任分離
- 依存性の逆転と抽象化設計
- インポート設計とネームスペース戦略
- プロジェクト構造におけるモジュール戦略

---

## 1. モジュールとは何か？

- ✅ 明示的な**入出力（export/import）**を持つ
- ✅ ひとつの責務に閉じた機能を定義する
- ✅ 再利用されることを前提とする

---

## 2. ESModules vs CommonJS

| 特徴          | ESModules                     | CommonJS                    |
|---------------|-------------------------------|-----------------------------|
| シンタックス  | `import` / `export`           | `require` / `module.exports`|
| 解決タイミング | 静的（ビルド時）              | 動的（実行時）              |
| 並行ロード    | 可能（ブラウザ対応）           | 不可                         |
| 使用場面      | フロントエンド、ES環境全般    | Node.jsでの従来コード        |

→ ✅ **モダンな開発ではESModulesが標準**。ツリーシェイキングや型支援との親和性も高い。

---

## 3. モジュール境界と責務分離

### ✅ モジュールは**1機能＝1責任**が原則

```js
// utils/formatDate.js
export function formatDate(date, format = 'YYYY-MM-DD') { ... }

// services/userService.js
export async function fetchUser(id) { ... }
```

→ ✅ ユーティリティ、ドメインロジック、UIなどで役割単位に分割

---

## 4. 依存性の設計：注入と抽象化

### ❌ モジュール内部で依存を直接呼び出す

```js
// services/userService.js
import { getToken } from '../auth';

export function fetchUser(id) {
  const token = getToken(); // tightly coupled
}
```

---

### ✅ 依存を外部から渡す（依存性注入）

```js
// services/userService.js
export function createUserService(tokenProvider) {
  return {
    fetchUser(id) {
      const token = tokenProvider();
      ...
    }
  };
}
```

→ ✅ モックやテスト時に入れ替え可能  
→ ✅ 実装に依存せず、**抽象に依存する**

---

## 5. モジュールインターフェース設計の原則

### ✅ インターフェースは**最低限の公開**

```js
// api/userApi.js
export async function getUser() { ... }
// export const API_KEY = '...'; ← ❌ 内部定数を漏らさない
```

- ✅ `default export` は基本避け、名前付きエクスポートを推奨
- ✅ グルーピングが必要ならオブジェクト構造にまとめる

---

## 6. モジュール連携と依存方向の設計

- **上位層（UI, Command） → 下位層（Domain, Service）**
- **“データが流れる方向”は常に一方向に**
- ✅ **双方向依存を避ける**

```
[UI] ─→ [Service] ─→ [Repository]
               ↑
         [Utilities]
```

→ ✅ 高レベルモジュールは、**抽象に依存する**ことで結合度を下げる

---

## 7. プロジェクト構造とモジュール整理

```
/src
  /modules
    /user
      userService.js
      userValidator.js
      userTypes.js
    /product
      productService.js
  /shared
    utils/
    constants/
    hooks/
```

- ✅ **ドメイン単位**でディレクトリを分離
- ✅ 共有ロジックは `shared` 以下に集約

---

## 設計判断フロー

```text
① このコードは単独で再利用される？ → モジュール化候補

② 外部依存を直接呼んでる？ → 注入可能な構造へ

③ 公開範囲は最小限？ → exportを明示的に設計

④ モジュール間の依存方向は一方通行？ → サイクル構造を解消

⑤ UI・ドメイン・ユーティリティが混在してない？ → 層を整理
```

---

## よくあるミスと対策

### ❌ ディレクトリ単位で責務が曖昧

→ ✅ “どの機能のためのコードか”で階層を決める

---

### ❌ default exportを乱用し、名前が不透明

→ ✅ 明示的な命名付きエクスポートで可読性を担保

---

### ❌ 1ファイルに複数の責務が混在

→ ✅ 各ファイルは単一の目的に特化すべき

---

## 結語

モジュール設計とは、**“変更に強く、使い回しが効き、意図が明確な構造を作ること”**である。

- 責任の分離
- 依存の注入
- 抽象との接続
- 明示的な入出力
- 結合を避けた設計

**設計されたモジュールは、コードの粒度を洗練し、アプリケーションの成長に耐える基盤となる。**
JavaScriptにおけるユニットテスト戦略：テストしやすいコード構造とJestによる責務単位の検証法

## 概要

**テスト可能性は設計品質の指標である。**  
ユニットテストは、コードが“正しい”ことを確認するための行為ではなく、**コードが“明確な責任を持っている”ことを保証するための構造設計**である。

本稿では、以下の観点からユニットテストとその周辺の設計を体系的に解説する：

- ユニットテストの責務と粒度
- テストしやすい構造とは何か
- 副作用の排除と依存の注入
- Jestによるテスト記述パターン
- 命名とテスト分類の指針
- テストが設計に与える影響

---

## 1. ユニットテストとは何か？

- ✅ 関数・モジュール・クラスなど、**“単位（Unit）”に閉じたテスト**
- ✅ 外部の状態に依存せず、**純粋な入力 → 出力**を検証
- ✅ 副作用（DOM操作・通信・ストレージ）を持たない or モックする

---

## 2. テストしやすいコードとは？

```js
// ❌ テスト困難：副作用が内包
function saveUser(user) {
  localStorage.setItem('user', JSON.stringify(user));
}

// ✅ テスト可能：依存注入
function saveUser(user, storage = localStorage) {
  storage.setItem('user', JSON.stringify(user));
}
```

→ ✅ 外部依存は引数・コンテキストで注入  
→ ✅ 単体で実行できるコードをユニットにする

---

## 3. Jestの基本構文

```js
describe('isValidEmail', () => {
  test('正しい形式のメールを通す', () => {
    expect(isValidEmail('test@example.com')).toBe(true);
  });

  test('不正なメールを弾く', () => {
    expect(isValidEmail('not-email')).toBe(false);
  });
});
```

- ✅ `describe()` で関数・機能単位のグループ化
- ✅ `test()` or `it()` でシナリオ記述
- ✅ `expect()` + マッチャー で検証 (`toBe`, `toEqual`, `toThrow` など)

---

## 4. テスト命名と分類の指針

### ✅ テストは**入力 → 条件 → 期待結果**を表現すべき

```js
test('数値が偶数のときtrueを返す', () => {
  expect(isEven(4)).toBe(true);
});
```

- ユースケースベースが望ましい
- 英語圏では “should X when Y” 形式が主流

---

## 5. モックとスタブの設計

```js
const mockStorage = {
  setItem: jest.fn(),
  getItem: jest.fn()
};

saveUser({ name: 'Toto' }, mockStorage);

expect(mockStorage.setItem).toHaveBeenCalledWith('user', '{"name":"Toto"}');
```

- ✅ 副作用はモック関数で隔離
- ✅ jest.fn() により呼び出し検証が可能

---

## 6. 失敗するテストの価値

- ✅ テストが失敗したとき「**何が、なぜ、どの入力で失敗したのか**」が即座にわかるように
- ✅ 曖昧な期待値やブラックボックス的なテストは**テスト自体が信用されなくなる**

---

## 7. ユニットテストと設計の相互作用

- ❌ 「後からテストを書く」ではなく  
- ✅ 「テストを書けるように設計する」

```js
// 非テスト可能な構造
export const config = {
  endpoint: '/api/user',
  retry: true
};

// ✅ テスト可能にする
export function getConfig(env) {
  return env === 'prod'
    ? { endpoint: '/api/user', retry: true }
    : { endpoint: '/mock/user', retry: false };
}
```

---

## 設計判断フロー

```text
① 関数は入出力が純粋？ → ユニットテスト可能

② 外部依存を持つ？ → モック or 注入できる構造へ

③ どのレベルで責務を分けている？ → describeで設計反映

④ テストの粒度は明確か？ → 複数の“期待結果”は分割する

⑤ 期待結果が曖昧でないか？ → テスト自体に明確な意味を持たせる
```

---

## よくあるミスと対策

### ❌ 1つのテストで複数の期待結果

→ ✅ テストは1ケース1アサーションが理想

---

### ❌ 内部実装に依存したテスト

→ ✅ 入出力の仕様に基づくテスト設計を

---

### ❌ テスト名が曖昧

→ ✅ 「〜のとき、〜を返す」「〜を実行したら、〜が呼ばれる」形式を徹底

---

## 結語

ユニットテストは“バグを防ぐ”ためのものではない。  
それは、“設計を確認可能な構造に変える”ための道具である。

- テストは仕様の写像であり、
- テストしやすい構造は責任が明確であり、
- テストが壊れないコードは設計が安定している

**良いテストは、良いコードを生む。  
そして、良い設計は“テストが自然に書ける構造”として現れる。**
JavaScriptにおけるエラーハンドリング設計：try/catch・例外境界・ログとユーザー通知の分離戦略


## 概要

エラーハンドリングとは、**「例外を防ぐこと」ではない。**  
それは「**例外が起きたときに、どう受け止め、誰に、どう伝えるか**」の設計である。

本稿では以下の視点から、実用的なエラーハンドリングの設計を体系化する：

- try/catchの設置場所と粒度
- 例外のログと通知の分離
- 再スローと再試行の設計
- エラー分類とユーザーへの伝え方
- グローバルエラーバウンダリと復旧戦略

---

## 1. try/catchの基本構造と設計思想

```js
try {
  const data = await fetchData();
  render(data);
} catch (e) {
  showError(e.message);
}
```

- ✅ catchブロックでは**必ずログ + UI通知**を行う
- ❌ 空のcatchは絶対NG（例外を握り潰す）

---

## 2. catchブロックの責務分離

```js
try {
  await riskyProcess();
} catch (e) {
  logError(e);       // ✅ 開発者用ログ
  notifyUser(e);     // ✅ ユーザー用メッセージ
}
```

- ✅ **開発者向けログ**は詳細に  
- ✅ **ユーザー通知**は簡潔に（不安にさせない）

---

## 3. エラーの種類と対応の分離

| エラー分類     | 例                            | ユーザー対応                |
|----------------|-------------------------------|-----------------------------|
| ユーザー操作系 | 入力ミス、無効な値             | 明確なバリデーションで制御 |
| ネットワーク系 | タイムアウト、サーバーダウン   | 再試行・リトライ導線        |
| アプリ側バグ   | 未定義変数、null参照など       | ログ + 通知 + 再発防止      |
| 想定外例外     | 外部ライブラリ、型不一致など   | フォールバック設計が必要    |

---

## 4. 再スローと例外の巻き取り

```js
function loadData() {
  try {
    return fetchData();
  } catch (e) {
    logError(e);
    throw e; // ✅ 呼び出し元に“委譲”する
  }
}
```

- ✅ 例外をログして**そのまま再スロー**
- ✅ UIで通知したい場合は“最上位”で巻き取る

---

## 5. グローバルエラーキャッチと設計境界

### ✅ 未処理のPromiseを拾う

```js
window.addEventListener('unhandledrejection', (e) => {
  logError(e.reason);
});
```

### ✅ 実行時エラーのキャッチ

```js
window.addEventListener('error', (e) => {
  logError(e.message);
});
```

→ ✅ あくまで**最終防波堤**として設置する（ローカルで拾うのが原則）

---

## 6. UI通知のパターン化

- ✅ トースト：軽微な失敗（再試行可能）
- ✅ モーダル：致命的な失敗（UIをブロック）
- ✅ インライン：フォームエラーや局所的な問題

```js
notifyUser('保存に失敗しました。もう一度お試しください。');
```

→ ✅ 文言は“冷静・簡潔・解決策を含む”ことが理想

---

## 7. エラーをデザインする：コード例

```js
try {
  await saveData(formInput);
  showSuccess('保存しました');
} catch (e) {
  if (e instanceof ValidationError) {
    showFormErrors(e.details);
  } else if (e instanceof NetworkError) {
    showToast('通信に失敗しました。再試行してください。');
  } else {
    logError(e);
    showError('予期せぬエラーが発生しました');
  }
}
```

→ ✅ 独自エラー型による分類設計が有効（`class ValidationError extends Error` など）

---

## 設計判断フロー

```text
① この処理は失敗し得る？ → try/catch設置

② 失敗時に伝えるべき情報は？ → log + notify に分離

③ 呼び出し元に伝えるべき？ → throwを再スロー

④ 再試行できる？ → retry戦略とUI導線を設計

⑤ 想定外の例外？ → グローバルcatchでログと復旧設計
```

---

## よくあるミスと対策

### ❌ catchしたエラーを握り潰す

→ ✅ 必ずログかユーザー通知へつなげる

---

### ❌ すべてのエラーに同じ通知

→ ✅ エラーの種類ごとにUI反応を設計する

---

### ❌ グローバルエラーでしか検知できない

→ ✅ 例外境界を意識し、**局所で明示的に処理**する

---

## 結語

**“エラー処理”とは、例外を潰すことではない。**  
それは、アプリケーションが“壊れないように、正しく壊れる”ための**構造設計**である。

- 捕まえる場所を設計する
- 伝える内容を整理する
- ログとUIを分けて考える
- 状態を破壊しないよう巻き取る
- 再試行やフォールバックを明示する

**優れたエラーハンドリングは、ユーザーと開発者の両方を救う設計資産である。**
JavaScriptにおけるデータ検証とバリデーション設計：型チェック・必須判定・ロジック分離による堅牢な入力制御


## 概要

**入力を信じるな、検証せよ。**  
ユーザーの入力、外部APIのレスポンス、ストレージからの復元――これら**“信用ならない値”**に対して、  
**何を必須とし、どの形式を受け入れ、どう誤りを検出・通知するか**が、アプリケーションの安全性とUXを左右する。

本稿では、バリデーションを次の観点から整理する：

- 型検査・null/undefinedの検出
- 複数条件を持つフィールド検証
- 同期/非同期バリデーション
- UI表示との責務分離
- 汎用的なバリデーション構造の構築

---

## 1. 型チェックと存在確認

### ✅ 単純なプリミティブチェック

```js
function isString(value) {
  return typeof value === 'string';
}

function isNonEmptyString(value) {
  return isString(value) && value.trim().length > 0;
}
```

→ ✅ `typeof` / `Array.isArray()` / `instanceof` による型ガードを基本とする

---

## 2. 必須チェックと複数条件の設計

```js
function validateEmail(value) {
  if (!value) return 'メールアドレスは必須です';
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) return '形式が正しくありません';
  return null;
}
```

→ ✅ nullなら成功 / エラーメッセージを返す方式が実用的

---

## 3. フィールド単位のバリデータ関数群

```js
const validators = {
  name: (v) => v?.trim() ? null : '名前は必須です',
  age: (v) => v > 0 ? null : '年齢は1以上を入力してください',
  email: validateEmail
};
```

→ ✅ 各フィールドに責任を持たせ、ルールを分離  
→ ✅ フォーム設計において再利用可能

---

## 4. フォーム全体の検証戦略

```js
function validateForm(data) {
  const errors = {};

  for (const key in validators) {
    const error = validators[key](data[key]);
    if (error) errors[key] = error;
  }

  return Object.keys(errors).length > 0 ? errors : null;
}
```

- ✅ エラーがあるかどうかは `null` または `errors` の有無で判定
- ✅ フロントエンドでの事前検証 → API送信 → サーバー検証の流れに統合可能

---

## 5. 非同期バリデーション（重複チェックなど）

```js
async function checkUsernameExists(username) {
  const res = await fetch(`/api/check-username?name=${username}`);
  const { exists } = await res.json();
  return exists ? 'このユーザー名はすでに使われています' : null;
}
```

- ✅ 入力中でも検証可能に（例：Debounce + 非同期検証）
- ✅ UI側で非同期の状態管理が必要（`isChecking`フラグなど）

---

## 6. UIとバリデーションの責務分離

- ✅ `validateXXX()` 関数は純粋関数とする（DOM操作しない）
- ✅ 表示（例：赤枠・メッセージ）は**コンポーネント側が担当**
- ✅ バリデーション関数はテスト可能なロジックに留める

---

## 7. 汎用バリデーションユーティリティの構築

```js
function createValidator(rules) {
  return (value) => {
    for (const rule of rules) {
      const error = rule(value);
      if (error) return error;
    }
    return null;
  };
}

// 使用例
const validatePassword = createValidator([
  (v) => v.length >= 8 ? null : '8文字以上必要です',
  (v) => /[A-Z]/.test(v) ? null : '大文字を含めてください'
]);
```

→ ✅ チェックルールを配列で柔軟に組み合わせ可能  
→ ✅ 共通ルールの再利用が容易に

---

## 設計判断フロー

```text
① 値の型が保証されない？ → 型ガード関数を定義

② 必須項目？ → 空チェック + 明示的なエラーメッセージ

③ ルールが複数ある？ → 順序付きの関数配列で検証

④ APIと連携したい？ → 非同期検証関数を導入

⑤ UI更新と検証を分離したい？ → 検証は純粋関数として定義
```

---

## よくあるミスと対策

### ❌ バリデーション関数内でDOMを直接操作

→ ✅ 検証は検証、表示は表示。役割を分ける

---

### ❌ エラー表現がコード内にハードコーディングされすぎる

→ ✅ 国際化や再利用性を考慮し、メッセージ辞書化を検討

---

### ❌ 同期/非同期検証が混在して管理不能に

→ ✅ ステータスを分離（例：同期検証結果 + 非同期検証中フラグ）

---

## 結語

バリデーションとは“値の正しさ”ではなく、**“正しさの判断基準を構造として設計する行為”**である。

- チェックは明確に
- メッセージは意味を持って
- 責務は関数に封じて
- 検証は構造で繰り返せるように

**ユーザーの安心は、信頼できる入力から生まれる。  
堅牢な検証は、UIの品位と信頼性を支える基盤である。**
非同期フローとUI反映の戦略：JavaScriptで構造化するローディング・エラー・再試行の堅牢な設計


## 概要

現代のUIは非同期で動く。  
ユーザーが「何かを待っている」状態に対し、**ローディング表示やエラーメッセージ、再試行機能などの応答をどう設計するか**が、**UXの質と信頼性を決定づける**。

本稿では、以下の観点から非同期フローとUI設計を体系化する：

- ローディング状態の明示と制御
- エラーの捕捉とUI通知
- 再試行戦略とユーザーの選択肢設計
- 状態遷移の構造化（状態管理・フラグ・ステートマシン）
- 抽象化による再利用可能な非同期UI構造

---

## 1. ローディング状態の構造化

### ✅ 明示的なローディングフラグの導入

```js
let isLoading = false;

async function fetchData() {
  isLoading = true;
  try {
    const res = await fetch('/api/user');
    const data = await res.json();
    updateUI(data);
  } catch (e) {
    showError(e);
  } finally {
    isLoading = false;
  }
}
```

→ ✅ `finally` で必ず解除する構造に  
→ ✅ フラグ名は `isLoading` / `isSubmitting` など文脈で分ける

---

## 2. エラー処理とユーザー通知

### ✅ try/catch + 明示的なUI表示

```js
let errorMessage = '';

try {
  await fetchData();
} catch (e) {
  errorMessage = 'データの取得に失敗しました';
}
```

→ ✅ 「なぜ失敗したか」「次にどうすればいいか」を伝えるメッセージ設計が重要

---

## 3. 再試行戦略：明示的なリトライ設計

```js
async function tryFetch(retry = 3) {
  for (let i = 0; i < retry; i++) {
    try {
      return await fetchData();
    } catch (e) {
      if (i === retry - 1) throw e;
    }
  }
}
```

- ✅ 自動再試行は限定的に使う（例：ネット不安定時）
- ✅ 明示的な再試行ボタンもUIとして用意

---

## 4. 状態モデルの設計（構造化）

```js
const state = {
  status: 'idle', // idle | loading | success | error
  data: null,
  error: null
};
```

→ ✅ 状態を文字列・enumで管理すると、分岐が明示的になりUI設計が簡潔になる

---

## 5. UIコンポーネントでの非同期ハンドリング

### ✅ 状態に応じて描画を切り替える

```js
if (state.status === 'loading') {
  return showSpinner();
} else if (state.status === 'error') {
  return showError(state.error);
} else if (state.status === 'success') {
  return renderData(state.data);
}
```

→ ✅ ロジックとUIの分離が保たれ、状態に応じたUIが意図通り動作する

---

## 6. 汎用ラッパー関数で共通化

```js
async function withLoading(action, stateRef) {
  stateRef.status = 'loading';
  try {
    const result = await action();
    stateRef.status = 'success';
    stateRef.data = result;
  } catch (e) {
    stateRef.status = 'error';
    stateRef.error = e.message;
  }
}
```

→ ✅ 複数の非同期関数に共通の状態管理構造を適用可能

---

## 7. トースト通知やダイアログの設計ポイント

- ✅ エラーは“目立つUI”で即時に伝える
- ✅ トーストは短時間・非ブロッキングで適切
- ✅ モーダルは「致命的エラー」や「操作が必要なとき」に限定

---

## 設計判断フロー

```text
① 待ち時間が1秒以上ある？ → ローディングUI表示

② 失敗する可能性がある？ → エラーメッセージ + 再試行導線

③ 状態が複数存在する？ → statusを用いた状態遷移モデルに

④ UI更新の責務が集中？ → withLoadingなどで共通化

⑤ ユーザー通知は十分か？ → トーストやUIメッセージで即時性を担保
```

---

## よくあるミスと対策

### ❌ ローディング中に多重発火

→ ✅ `isLoading` を使ってボタンを一時無効化

---

### ❌ エラーを握り潰してユーザーに何も伝えない

→ ✅ UIにフィードバックを必ず表示する

---

### ❌ 成功・失敗でUIが更新されない

→ ✅ 状態フラグとレンダリングの紐づけを明確にする

---

## 結語

非同期フローとは「ユーザーの待ち」と「アプリケーションの応答」をつなぐ設計である。

- 待ち時間は明示する
- エラーは伝える
- 成功は確実に表示する
- 状態遷移は構造で示す
- 複雑化したらラップして抽象化する

**ユーザーにとって重要なのは、“操作に対して意味のある反応があること”。  
その非同期は、意味のある設計として成立しているか？**
TotalCommanderでカレントディレクトリをWindows Terminalで開くボタンバーを追加

TotalCommanderでボタンバーにカレントディレクトリを開くボタンバーを追加したかったが、下記のような点もなんとかしたかったので対応方法調べてみました。

- パスの途中にスペースが入ってもうまく取り扱える
- 何回もボタンを押して、Windows Terminalが複数たちがる事は避けて、新しくボタンを押した分はタブで開いてほしい

## ボタンバーの設定

Windows TerminalのパラメータとTotalCommanderのパラメータを調べたところ、下記の記載で対応できそう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/c6c0c2ab-66bc-46c8-aeba-c7d9f1a07316.png)

```text
コマンド：wt -w 0 nt -p "Command Prompt" -d
パラメータ："%P\"
アイコン：terminal.ico
```

コマンドでWindowsTreminalを起動する際に、-wオプションに0で最後に使用したウィンドウを指定し、-ntオプションで新しいタブを開き、-dオプションでTotalCommanderのパラメータで渡されるカレントディレクトリ（"%P\"）を開くといった具合。

ぱためーたの部分は%Pで指定すると、パスにスペースが入るケースではうまく動かないが `"%P\"` といった形で指定すると動きます。

なおアイコンで指定している、terminal.icoについては、下記から取得した物を利用。

https://github.com/microsoft/terminal/tree/main/res

## 参考

[Windows ターミナルに対するコマンド ライン引数を使用する](https://learn.microsoft.com/ja-jp/windows/terminal/command-line-arguments?tabs=windows)
[Persistent path for Open Windows Terminal in current folder as admin](https://www.ghisler.ch/board/viewtopic.php?t=78447)

## 総評

もともとは、WindowsTerminalを起動するだけのボタンバーを追加していましたが。

カレントディレクトリで開きたい、ボタンを押すたびに複数のWindowsTerminalが新規に開くといった事が煩わしくなってきたので。
少し調べて設定してみました。

ちょっとしたことですが、だいぶ便利に利用できます。
コピペで使える！コーディングを効率化するLLMプロンプトテンプレート

# コピペで使えるコーディングを効率化するLLMプロンプトテンプレート

LLM（大規模言語モデル）を活用してコーディング作業を効率化するためのプロンプトテンプレートをご紹介します。以下のテンプレートはそのままコピーしてお使いいただけます。

:::note warn
この記事はClaude 3.7 Sonnet extended Thinkingの協力により書かれています。
:::


## コード生成テンプレート

```
以下の仕様に基づいて、[言語名]のコードを記述してください：
- 機能：[実現したい機能]
- 入力：[入力データの形式]
- 出力：[期待する出力の形式]
- 条件：[考慮すべき条件や制約]
- コードスタイル：[遵守すべきコーディング規約]

ベストプラクティスを遵守し、エラーハンドリングも適切に実装してください。
```

## バグ修正支援テンプレート

````
以下のコードにバグがあります。修正してください：

```[言語名]
[バグのあるコード]
```

エラーメッセージ/症状：
[エラーメッセージや問題の症状]

期待する動作：
[正しく動作した場合の挙動]
````

## コード最適化テンプレート

````
以下のコードを最適化してください：

```[言語名]
[最適化したいコード]
```

最適化の観点：
- パフォーマンス改善
- メモリ使用量削減
- 可読性向上
- [その他の観点]

最適化後のコードと、どのように改善されたかの説明を教えてください。
````

## 単体テスト生成テンプレート

````
以下のコードに対する単体テストを[テストフレームワーク名]で作成してください：

```[言語名]
[テスト対象のコード]
```

テストすべきケース：
- 正常系：[正常なケース]
- 異常系：[エラーケース]
- 境界値：[境界値]
````

## コードレビューテンプレート

````
以下のコードをレビューしてください：

```[言語名]
[レビュー対象のコード]
```

レビューの観点：
- バグの有無
- セキュリティリスク
- パフォーマンス
- 可読性
- ベストプラクティス
````

## ドキュメント生成テンプレート

````
以下のコードに対するドキュメントを生成してください：

```[言語名]
[ドキュメント化したいコード]
```

ドキュメントには以下を含めてください：
- 概要説明
- 関数/クラスの説明
- パラメータの詳細
- 戻り値の説明
- 使用例
````

## アルゴリズム解説リクエストテンプレート

````
以下のアルゴリズム/データ構造について説明してください：
[アルゴリズム/データ構造名]

特に以下の点を含めてください：
- 基本概念と動作原理
- 時間計算量と空間計算量
- 適した使用シーンとユースケース
- [言語名]での実装例
- 考えられる最適化手法
````

これらのテンプレートをプロジェクトの状況に合わせてカスタマイズしてご活用ください。
【解決】Claude Desktopの「spawn npx ENOENT」エラー対処法 - MCPサーバー設定

## 結論

npxコマンドをフルパスで指定すれば解決します。

npxとは別の話ですがIssueが上がっており、そちらを参考に解決しました！

https://github.com/modelcontextprotocol/servers/issues/760

## 問題
MCPのキャッチアップおよび、ClaudeにWebサーチの機能を付与するため、[BraveのMCPサーバー](https://github.com/modelcontextprotocol/servers/tree/main/src/brave-search)とClaudeDesktopを接続しようと試みましたが、以下のような`ENOENT`エラーが発生し設定が失敗しました。

```
[error] spawn npx ENOENT
```

このエラーは、Claudeが`npx`コマンドのパスを解決できずに発生しているようです

## 解決方法

### 失敗例

以下のような設定では、エラーが発生しました。

```json
{
	"mcpServers": {
		"brave-search": {
			"command": "npx",
			"args": ["-y", "@modelcontextprotocol/server-brave-search"],
			"env": {
				"BRAVE_API_KEY": "<Your_API_KEY>"
			}
		}
	}
}
```

### 成功例

npxコマンドをフルパスで指定することにより解決できました⭐️
※フルパスはユーザー環境によって異なります

```json
{
	"mcpServers": {
		"brave-search": {
			"command": "/Users/<Username>/.anyenv/envs/nodenv/shims/npx",
			"args": ["-y", "@modelcontextprotocol/server-brave-search"],
			"env": {
				"BRAVE_API_KEY": "<YOUR_API_KEY>"
			}
		}
	}
}
```

## まとめ

相対パスでのコマンド指定では、npxコマンドのパスが解決できなかったようです。
そのため、npxの実行ファイルまでのフルパスを取得し、設定ファイルに書き込んであげることで解決しました

ご自身の環境でnpxのフルパスを確認するには、ターミナルで以下のコマンドを実行してください：

```bash
which npx
```
Codewars 6 kyu The Vowel Code

# Codewars 6 kyu The Vowel Code
https://www.codewars.com/kata/53697be005f803751e0015aa/train/python
Task
Step 1: Create a function called encode() to replace all the lowercase vowels in a given string with numbers.
Step 2: Now create a function called decode() to turn the numbers back into vowels.

# Verbalization
As encode(), replace a -> 1, e -> 2, i -> 3, o -> 4, u -> 5
As decode(), replace 1 -> a, 2 -> e, 3 ->  i, 4 -> o, 5 -> u
 
# Code 
```py
def encode(st):
    st = st.replace('a', '1')
    st = st.replace('e', '2')
    st = st.replace('i', '3')
    st = st.replace('o', '4')
    st = st.replace('u', '5')
    return st
def decode(st):
    st = st.replace('1', 'a')
    st = st.replace('2', 'e')
    st = st.replace('3', 'i')
    st = st.replace('4', 'o')
    st = st.replace('5', 'u')
    return st
```

# Other solution.
```py
#use dictionary
def encode(st):
    encode_dict = {'a': '1', 'e': '2', 'i': '3', 'o': '4', 'u': '5'}
    result = ""
    for char in st:
        result += encode_dict.get(char, char) 
    return result

def decode(st):
    decode_dict = {'1': 'a', '2': 'e', '3': 'i', '4': 'o', '5': 'u'}
    result = ""
    for char in st:
        result += decode_dict.get(char, char)  
    return result

```
第2弾：Dify+Xinference+OllamaでローカルAIチャットボットを作る！


# はじめに
[前回：Dify+Xinference+OllamaでローカルAIチャットボットを作る！](https://qiita.com/segfo/items/a4dd3fc97f62ce708c68)
続というからには前回のなんとなくの全容がわかるようなわからないような話ではなくて、どういう風な実装を行ったかとかについて話していければいいなって思いました。
そもそも、前回は大体ざっくりなもうそもそも作ってなくてもできそうなレベルの話をしていたのでｗ

# チャットボットの実装
チャットボットは基本的にはDifyで組んでいます。

## 全体像
全体像はこんな感じです
![スクリーンショット 2025-03-31 114312-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30037/5aff5128-2b58-4906-9b91-0580ff6ca9aa.png)

基本的な考え方としては、LLMにも得手・不得手があるので、得意分野のLLMに得意なものを食わせる形にするという方向性で実装していきます。

# 0番の説明
0番の本流では話題を推定しています。どの話題なのか？専門性はあるのか？をざっくりと確認する形にします。

Difyには**質問分類器**というノードがあるんですが、分類対象の質問が増えるとうまく判定してくれなかったりそもそも処理が遅いのでLLMに独自にプロンプトを流して軽くするなどの工夫をしているのでこうなっています。

次に1～3の分流があります。
1番はレビューの分流
2番は専門的な知識を要求する分流（今は電気工事の内容のみ、今後はIT関係の知識も並列に組み込むつもり）
3番は雑談の分流

# 1番
- 〇〇の文章を翻訳して　だとか（1-2）
- このコードの意図を教えて　だとか（1-1）
- このコードにある脆弱性を教えて　だとか（1-1）

そういう自然言語やコードレビューを行わせる流れが1番です。

# 2番
専門的な話についての分流が2番です、辞書を引く必要があるものですね。ここでいう辞書を引く必要があるかどうかは、LLMの知識で対応できないものを指します。なのであらかじめ0番で質問内容が専門的であり特定の領域の話であるかどうかを判定しておきます。
この経路はRAGの経路です。LLMには知識がないことが往々にして有ります。推論は正しそうだけど明らかに違うこと言ってるから質問の回答を探すクエリを正しく作れないことがまぁ有ります。ここはLLMのモデルによって様々ですがユーザクエリを基に用語集を辞書から引っ張ってきて事前知識を与えることにしました。

書籍にはAdvanced-RAGのHyDEという手法であると記述されていますが、さらにこれを発展させてみました。

## 考え方
[参考書籍](https://qiita.com/segfo/items/a4dd3fc97f62ce708c68#%E5%8F%82%E8%80%83%E6%9B%B8%E7%B1%8D)によれば、**HyDEは質問から仮の推論結果を出させること**を指しています。ベクトルDBから検索したいデータは**質問の回答**と近似した内容であるためですね。

ここからは自由研究の範囲なので、論文とかがあるわけではないですが一応書いておきます。
ここでの**知識がない**というのは、LLMが用語自体は学習しているけど文脈があいまいで、用語を正しく使えない時を**知識がない状態**であると定義します。さらに知識というのは例えば、電圧や電流に関する定義、分類といった専門性のある分野の話です。（低圧や高圧、特別高圧の電圧区分のような話を指します）
なので、質問文から**辞書ベースで仮の知識**を与え、さらに引いた辞書の内容（コンテキスト）と質問から、質問に対する仮の推論結果を専門的な用語を用いて出させます。
こうすることで、推論結果の質がモデルによって極端に左右されることなく出せるかなと思った次第です。

### 書籍に載っているHyDE
1. 回答をLLMに推論させる
1. 推論した結果をVectorDBに引かせる
1. LLMに要約させる

### 改良したHyDE
1. 質問文をVectorDBに引かせる
1. LLMにVectorDBの文脈を基に質問文について回答せよと指示を与える
1. 推論した結果をVectorDBに引かせる
1. LLMに要約させる

こんな感じ。

# 3番
雑談フローです！基本的に壁当てBotの心臓部分といっても良い気はします。
LLMは現在の気温や季節なんかの問い合わせには非常に弱いので現在時刻や現在が朝昼晩なのか日は沈んでいるのかだとかそういう情報をまず与えてから雑談させています。これがエモさです。
で、一応ここにはユーザからの質問に対する直接的な応答が入るのでシステムプロンプトの出力チェックを入れています。（一番高リスクなので）


# セキュリティ
Difyで実装する場合においては、システムプロンプトもステートレスであることで、書き換えが発生したとしてもそのクエリ（ただしメモリ機能を使わない場合）のみの書き換えに収まることを一応は検証しました。
（若干本当か？感はありながら書いているのでまたあとで訂正するかも）
なのでとりあえずは、出力がされてるかどうかのチェックをすることにしています。

システムプロンプトの出力チェックはシンプルに発言内容であらかじめプロンプトの内容を保存したベクトルDBを引くことで実現しています。もし、プロンプトが引かれていたら定型文を返却することにしています。

ブラインド系の攻撃が有りそうだけどまぁ個人利用の範疇で外部公開やサービス化はしないつもりなので受容したい。とはいえセキュリティ的な事項なのでこの辺りの勉強したい感は強いね。


# まとめ
- 基本はLLM単体の性能では比較的早期に頭打ちとなる（重み付き量子化4bit～5bitモデルの場合の検証結果です）
- 複数のLLMを用いるが、そのカバー対象となる話題の判定が結構難しかったりする
- バカつよマシンがあればクソデカ基盤モデルを載せて動かせるのでその限りではないかのうせいはあるが、PCなどのエッジノードレベルでやるならこの方法がよさそう
【GitHub Actions】jsonに「link:」が入っているとnpm installできない

GitHub Actionsでのデプロイを試みていた際に発生したエラーがなかなか解消できずに詰まってしまったので状況を共有します。

## 発生したエラーと状況
```yaml:sample.yaml
name: Build

on:
  push:
    branches:
      - main

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v4

      - name: setup-node
        uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: npm

      - name: install
        run: npm install 
```
上記のyamlファイルの記述で`Git push`を行いインストールまで進めるか調査していました。
すると次のようなエラーが発生してActionがFailureになりました。

```
npm error code EUNSUPPORTEDPROTOCOL
npm error Unsupported URL Type "link:": link:dataconnect-generated/js/default-connector
npm error A complete log of this run can be found in: /home/runner/.npm/_logs/(デバッグログのログファイル).log
Error: Process completed with exit code 1.
```

今回発生したエラーの原因を見てみます。

### 前提：GitHub Actionsの「code 1」エラーについて
https://qiita.com/KerorinNF/questions/939cb56ed00ea5da665f

上記の記事が概念の理解として非常に参考になりました。

結論としては **「構文エラーではなく処理の結果としてエラーになっている場合」に出るエラー文**のようです。

なので今回の場合はyamlの記述自体には問題がないので処理の過程で出たエラーを見てみると良いこととなります。

### 今回のエラーで起きた問題点
改めてエラーの文章を見てみましょう。

`npm error Unsupported URL Type "link:": link:dataconnect-generated/js/default-connector`
この部分が原因のようです。

上記のエラー文を日本語訳してみると`dataconnect-generated/js/default-connector`**という読み込みファイルの「link:」という形式がサポートされていない**ことが原因と推測されます。

そこで該当の部分(firebaseをインストールした時に生成された部分)を見てみると次のような記載がありました。
```json:package.json
  "dependencies": {
    "@firebasegen/default-connector": "link:dataconnect-generated/js/default-connector",
  },
```
問題となっている`link:`の記述を発見できました。この部分はfirebaseを使うために生成していたフォルダを指し示すものです。

さらに具体的な原因については下記の記事が参考になりました。

https://zenn.dev/manase/scraps/1fa5dec4291e71

> link:プロトコルはYarnの機能であり、npmではサポートされていません。
そのため、npmはこの依存関係を解釈できず、EUNSUPPORTEDPROTOCOLエラーが発生します。

つまり、今回のエラーの直接的な要因は
* jsonに`link:`の記載が含まれていること
* 上記の状態でインストール方法として`npm`を使用したこと

の2つでした。

## エラーの対処方法
つまり、対処法としては「`link:`でない指定をすること」か「npm以外でインストールすること」が考えられそうです。

実際の処理方法は先ほどの記事に記載がありました。

https://zenn.dev/manase/scraps/1fa5dec4291e71


> 可能であれば、npmの代わりにYarnを使用してプロジェクトを管理します。
Yarnはlink:プロトコルをサポートしています。

もしくは

> package.jsonからlink:を削除して、適切なバージョン番号やパスに置き換えます。
例えば、ローカルパッケージを使用したい場合は、npmのfile:プロトコルを使用できます。

この2種のどちらかで解消できるとのことでした。

今回のケースではjsonファイルの記載を変更する方法を選択しました。
具体的には以下のように修正しました。
```json:package.json
  "dependencies": {
    "@firebasegen/default-connector": "file:dataconnect-generated/js/default-connector",
  },
```
このようにjsonファイルを修正することで`npm install`の処理がGitHub Action上で通るようになりました。

## 結論/まとめ
* GitHub Actionsのyamlファイルに`npm`系の指示を記載する時にはjsonファイルを一度確認してみましょう
* `link:`の記載があったら`file:`形式に直してみましょう
* もしくは`npm`の処理を`yarn`に修正してみまsy
JavaScriptにおける状態管理の設計：ローカル・グローバル・ステートマシンによる予測可能性と一貫性の確保


## 概要

状態（state）とは、**UIやアプリケーションが“今どうあるか”を定義する情報の集合体**である。  
状態管理とは、**「状態をどこに持ち」「どう変化させ」「どう再現性を担保するか」**を設計する行為である。

本稿では、以下を軸に状態管理を構造的に整理する：

- ローカルステート vs グローバルステートの役割と境界
- 状態の責務とスコープの設計
- ステートマシンによる状態遷移の明示化
- 状態変更のトリガーと影響範囲の制御
- 現場における実用アプローチの選定基準

---

## 1. ローカルステート：コンポーネント内の状態

```js
let count = 0;

function increment() {
  count++;
  render(count);
}
```

- ✅ コンポーネント内完結
- ✅ UIに直接関係する短命ステート向き
- ❌ 複数コンポーネントで共有すると破綻

---

## 2. グローバルステート：アプリケーション全体で共有される状態

```js
const appState = {
  user: null,
  theme: 'dark',
  isLoading: false
};
```

- ✅ 認証情報・設定・ネットワーク状態など
- ✅ 単一の“真実の情報源”（Single Source of Truth）
- ❌ 不用意に増やすと依存爆発

---

## 3. ステートマシン的思考：状態遷移を制御する

### ✅ 明示的な“状態 → 状態”の遷移モデル

```js
const state = {
  status: 'idle', // idle → loading → success / error
};

function transition(event) {
  if (state.status === 'idle' && event === 'FETCH') {
    state.status = 'loading';
  } else if (state.status === 'loading' && event === 'SUCCESS') {
    state.status = 'success';
  }
}
```

→ ✅ 状態とイベントの“許容遷移”を明文化  
→ ✅ 誰がいつ何を変えるかが見える設計に

---

## 4. 状態を「責務」で分類する戦略

| 状態の種類       | 例                                  | 保持場所             |
|------------------|--------------------------------------|----------------------|
| 表示用の一時状態 | モーダル開閉・フォームの入力内容     | ローカルステート     |
| アプリケーション状態 | 認証ユーザ・テーマ・カート             | グローバルステート   |
| ネットワーク状態 | isLoading, errorMessage              | 一時的にはローカル、共有が必要ならグローバル |
| 状態遷移         | 認証: 未ログイン → ログイン中 → 完了  | ステートマシンモデル |

---

## 5. グローバルステートを管理する手段

### ✅ Context API（Reactなど）

```js
const ThemeContext = createContext('dark');
```

- ✅ 軽量で構成もシンプル
- ❌ 状態の更新頻度が高いと再レンダリング地獄

---

### ✅ 状態管理ライブラリ（Zustand, Redux, Vuex など）

```js
const useStore = create(() => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 }))
}));
```

- ✅ スコープを切ってセレクティブ購読
- ✅ ミドルウェアによるログ・永続化も可
- ❌ 抽象化しすぎると複雑化する

---

## 6. 状態の“不変性”と安全な更新

```js
const next = { ...prev, isOpen: true };
```

- ✅ 状態を直接 mutate しない（再レンダリングが起きない）
- ✅ `Object.assign` / スプレッド構文でコピー更新

---

## 7. 状態トリガーの設計と制御

- UI → 状態更新
- APIレスポンス → 状態更新
- タイマー / 外部イベント → 状態更新

### ✅ 更新元が多い場合は「イベント」として抽象化

```js
dispatch('LOGIN_SUCCESS', payload);
```

→ ✅ 状態に直接触れず、間接的に制御する構造へ

---

## 設計判断フロー

```text
① 状態はローカルUI専用？ → useState等で管理

② 状態は複数コンポーネントから参照される？ → グローバル管理

③ 状態が明確なフェーズを持つ？ → ステートマシン設計

④ 状態の変更元が複数ある？ → イベントドリブン化

⑤ 状態が変化する頻度は？ → 高頻度ならセレクティブ購読設計
```

---

## よくある失敗と対策

### ❌ 状態の責任が不明瞭で“なんとなく共有”

→ ✅ スコープ設計を「誰が持ち」「誰が読んで」「誰が変えるか」で分割

---

### ❌ グローバルステートにローカル状態を混在

→ ✅ UI状態（例：開閉）はローカルに留める

---

### ❌ 状態の変更に副作用が埋め込まれている

→ ✅ 状態と副作用は分離（例：useEffectで外部反応）

---

## 結語

状態管理は単なる変数の保持ではない。  
それは**「情報の流れをどう設計し、責任をどこに持たせるか」**という、アーキテクチャの中核そのものである。

- 状態は構造に従い
- 状態変化はルールで制御され
- 状態の読み書きは責任が明確である

**設計された状態は、予測可能性と信頼性をもたらす。  
状態は“どう持つか”ではなく、“どう変化するか”まで設計すべきである。**
Auroraをcloudformationで管理する場合にて、クラスター削除時のバックアップ保持を行う方法を探していたらとしたら思わぬ仕様を知った

# いきなりまとめ

- Auroraでは削除時に自動バックアップの保持が可能
- しかしcloudformationでは対応していない
- サポートに聞いたところ、AWS Backupで継続的バックアップを有効化している場合、保持されることが判明
- 早くCfnでも対応してほしい

# 前提: Auroraのバックアップ事情

Auroraにはバックアップの仕組みが複数あります。詳しくは以下の記事を読んでみてください。

https://qiita.com/Yona_Sou/items/4e590db0193f79736cd0

今回はその中でも自動バックアップの話になります

# Auroraを削除するとバックアップはどうなるのか

Auroraを削除するときは自動バックアップを保持することができます。

保持をすることで、クラスターを削除しても自動バックアップは保持期間まで残しておくことができます。

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/Aurora.Managing.Backups.Retaining.html

この機能自体は比較的最近の機能で2023/08でリリースされた機能になります

https://aws.amazon.com/jp/about-aws/whats-new/2023/08/amazon-aurora-automatic-backup-deleted-clusters/

# cloudformationでは対応していない

IaC をするとなるとcloudformationを使いたいですが、なんとcloudformationでは対応していません

- [AWS::RDS::DBCluster](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-rds-dbcluster.html)に保持関連のプロパティが無い
- [AWS::RDS::DBInstance](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-rds-dbinstance.html#cfn-rds-dbinstance-deleteautomatedbackups)にはあるが、Aurora は対応していないと書かれている

そのため、cloudformationでAuroraを管理している場合は、Stack削除時に自動バックアップは削除されてしまうことになります

# サポートに聞いてみた

どうにか方法は無いかということでサポートに問い合わせをしたところ、結論としては`AWS Backupの継続的バックアップと関連付いている場合に限り、cloudformationで削除をしても自動バックアップが保持される`ことがわかりました

以下サポートの回答の抜粋です

```
現在、 DeleteDBCluster API で、 DeleteAutomatedBackups パラメーターを指定しない場合の挙動は、下記のようなものになっております。

1. DB クラスターが AWS バックアップの継続的バックアップと関連付いている場合

DeleteAutomatedBackups パラメーターを指定しない場合、デフォルトの挙動はバックアップを保持するものとなります。
言い換えると、 --no-delete-automated-backups を指定して実行する場合と同等の挙動となります。
お客様が以前検証を行われた際には、デフォルトの挙動はバックアップを削除するものでしたが、変更されました。

2. DB クラスターが AWS バックアップの継続的バックアップと関連付いていない場合

DeleteAutomatedBackups パラメーターを指定しない場合、デフォルトの挙動はバックアップを削除するものとなります。
言い換えると、 --delete-automated-backups を指定して実行する場合と同等の挙動となります。

CloudFormation から DB クラスターを削除する際には DeleteAutomatedBackups パラメーターを指定できませんので、AWS Backup で継続的バックアップを取得されているお客様の環境では、 1 の挙動が適用されます。
```

## 詳細に解説

CloudformationでAuroraリソース=AWS::RDS::DBClusterを含むStackを削除した際は内部的にDeleteDBCluster APIが実行されます

https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DeleteDBCluster.html

そしてDeleteDBCluster に渡す引数としてDeleteAutomatedBackups パラメーターがありますが、これを指定しない場合のふるまいが、AWS Backupの継続的バックアップと関連付けがされているかどうかで異なっています

- AWS Backupの継続的バックアップと関連付けが`されている`場合は、自動バックアップを`保持する`
- AWS Backupの継続的バックアップと関連付けが`されていない`場合は、自動バックアップを`保持しない`

おそらくAWS Backupでバックアップを管理する場合はRDS側のAPIで勝手にバックアップが削除されてはサービス上困るので、このような仕様になっているとは思うのですが、驚きの仕様です。

Auroraとは別のサービスによって内部的なふるまいが変わる、というのは何とも言えませんよね

当然ドキュメントにも書かれていなかったので、記載するようにフィードバックを行いました

# 結論と今後

結論としてはバックアップ保持をしたかったらAWS Backupの継続的バックアップを利用するしかない状態です。

一方で仕様としてはあまり好ましくない状態ではあるので、早めにCloudformationでのサポートをしてほしいところです。2023年リリースの機能なので、そろそろ対応してもおかしくないとは思うのですが。
JavaScriptにおけるイベント設計戦略：バブリング・キャプチャ・委譲と管理可能なイベント構造



## 概要

DOMイベントは、**ユーザー操作に応答するアプリケーションの“神経系”**である。  
しかし、安易な `addEventListener` の多用や伝播の誤解は、**予測不能なバグやメモリリーク、非効率なUI構造**を引き起こす。

本稿では以下を体系化する：

- バブリング・キャプチャの仕組みと使い分け
- イベント委譲による効率化
- 明示的なイベント設計のパターン
- リスナー登録・解除の責務と設計
- カスタムイベントの活用と分離設計

---

## 1. イベントの伝播：キャプチャとバブリング

### ✅ 3段階の流れ

```
1. キャプチャフェーズ（親 → 子）
2. ターゲットフェーズ（対象要素）
3. バブリングフェーズ（子 → 親）
```

```js
element.addEventListener('click', handler, true);  // キャプチャ
element.addEventListener('click', handler, false); // バブリング（デフォルト）
```

→ ✅ 明示的に `true/false` を指定して意図を明文化する

---

## 2. バブリング制御と停止

```js
element.addEventListener('click', (e) => {
  e.stopPropagation(); // ✅ バブリングを止める
  e.preventDefault();  // ✅ デフォルト動作の抑制
});
```

- ✅ `stopPropagation()` → 他のリスナーに伝播させない
- ✅ `preventDefault()` → リンク遷移、フォーム送信などをキャンセル

---

## 3. イベント委譲の設計（イベントバインドの最適化）

### ❌ 各要素にリスナーを直付け

```js
buttons.forEach(btn => btn.addEventListener('click', onClick));
```

→ 要素が動的に増減する場合、メンテ不能・非効率

---

### ✅ 親要素に1つのリスナー（委譲）

```js
document.querySelector('#list').addEventListener('click', (e) => {
  if (e.target.matches('.list-item')) {
    handleItemClick(e.target.dataset.id);
  }
});
```

- ✅ 子要素にクラスやdata属性を付けて判別
- ✅ 親に1つだけバインド → 高効率・柔軟

---

## 4. removeEventListenerの正しい設計

### ❌ 無名関数では解除不可

```js
element.addEventListener('click', () => console.log('clicked'));
element.removeEventListener('click', () => console.log('clicked')); // ❌ 効かない
```

→ ✅ 明示的な関数定義が必要

```js
function onClick(e) { ... }
element.addEventListener('click', onClick);
element.removeEventListener('click', onClick);
```

---

## 5. 一度だけ実行するイベント

```js
element.addEventListener('click', handler, { once: true });
```

→ ✅ `once: true` で自動的に1回限りの実行に（手動で解除不要）

---

## 6. カスタムイベントとコンポーネント分離

```js
const event = new CustomEvent('user:created', {
  detail: { id: 123 }
});

element.dispatchEvent(event);

element.addEventListener('user:created', (e) => {
  console.log(e.detail.id); // 123
});
```

- ✅ UIコンポーネント間の通信に最適
- ✅ “発火”と“受信”を構造的に分離できる

---

## 7. イベント命名・スコープ設計指針

| 設計指針         | 解説                                    |
|------------------|-----------------------------------------|
| `click`, `input` | DOMの基本イベント                       |
| `xxx:ready`      | 状態通知（カスタムイベント）            |
| `user:created`   | エンティティ指向のイベント名設計       |
| グローバル禁止   | document/window直付けは極力避ける       |
| コンポーネント内 | 独自要素 or Shadow DOM内で閉じるべき    |

---

## 設計判断フロー

```text
① 要素が動的に増える？ → イベント委譲

② stopPropagation は必要？ → 他のハンドラとの関係を設計

③ 一度しか使わないイベント？ → once: true を使う

④ イベント解除が必要？ → 関数を変数に束縛して管理

⑤ 複数コンポーネント間で通信？ → CustomEvent で疎結合化
```

---

## よくあるミスと対策

### ❌ 複数バインド → イベントの多重発火

→ ✅ removeEventListener で常に解除戦略を持つ

---

### ❌ stopPropagation の乱用

→ ✅ 原因を切るより“構造を見直す”

---

### ❌ 同じリスナーが複数バインド

```js
// ループやクリック内でaddEventListenerし続ける
```

→ ✅ フラグ管理やonceオプションで設計を

---

## 結語

イベントとは「**ユーザーの意図に対する、アプリケーション側の反応の設計**」である。

- DOM構造と伝播構造は一致しない
- 発火点と処理点は分けて考える
- バブリング・キャプチャは“構造上の意味”を持つ
- 再利用されるイベント構造には、明示と設計が必要

**“ただ反応する”ではなく、“意図に応じて設計された反応”を構築すること。  
それが、モダンなUIの神経設計である。**
JavaScriptにおける日付・時刻処理の設計：Dateオブジェクト、ISOフォーマット、ライブラリ運用の戦略


## 概要

日付と時刻は**すべてのアプリケーションに現れる“状態”であり、“落とし穴”**でもある。  
JavaScriptでは標準で `Date` オブジェクトが用意されているが、その操作性・可読性・正確性においては多くの課題がある。

本稿では、以下の観点から日付処理を設計する：

- Dateオブジェクトの基礎と注意点
- ISOフォーマットの活用
- 時刻演算のトラップ
- 日付ライブラリ（Luxon, date-fns等）の比較と戦略
- 現実的な日付処理のベストプラクティス

---

## 1. `Date` オブジェクトの基礎

```js
const now = new Date();
console.log(now.toISOString()); // ISO 8601形式
```

- ✅ コンストラクタにISO文字列を渡せば、UTCとして正確に解釈される
- ❌ `Date.parse()` や `"YYYY-MM-DD"` など曖昧な形式は避ける

```js
new Date('2024-12-01') // ❌ 環境依存（UTCかローカルか曖昧）
new Date('2024-12-01T00:00:00Z') // ✅ 明示的にUTC
```

---

## 2. ISO 8601形式を使う理由

```js
const date = new Date('2024-12-01T15:00:00Z');
```

- ✅ 一意性がある
- ✅ タイムゾーンを含めて伝達可能
- ✅ バックエンド・DB・API連携との親和性が高い

---

## 3. 日付の演算と注意点

### ❌ 手動で加算・減算しようとする

```js
const d = new Date();
d.setDate(d.getDate() + 1); // ✅ ただし月末→翌月などに注意
```

→ ✅ Dateは**内部的にUNIXタイム（ミリ秒）で保持されている**ため、演算は慎重に行う

---

## 4. 時刻の比較と差分

```js
const a = new Date('2024-01-01T00:00:00Z');
const b = new Date('2024-01-02T00:00:00Z');

const diffMs = b - a; // ✅ 数値比較が可能
const diffDays = diffMs / (1000 * 60 * 60 * 24); // → 1
```

---

## 5. 日付の整形：`toLocaleString()` vs 外部ライブラリ

### ❌ 標準の `toLocaleString()` は非一貫

```js
new Date().toLocaleDateString('ja-JP'); // "2025/3/30"
```

→ ✅ 表示形式が環境依存で**一貫性がない**

---

## 6. 推奨されるライブラリと設計思想

### ✅ Luxon（Moment.jsの後継）

```js
import { DateTime } from 'luxon';

const now = DateTime.now().setZone('Asia/Tokyo');
const iso = now.toISO(); // ISO文字列
const formatted = now.toFormat('yyyy-MM-dd HH:mm');
```

- ✅ タイムゾーンを意識した設計が可能
- ✅ 明示的な構文と操作性

---

### ✅ date-fns（関数型ライブラリ）

```js
import { format, parseISO, addDays } from 'date-fns';

const date = parseISO('2024-01-01T00:00:00Z');
const next = addDays(date, 1);
const output = format(next, 'yyyy-MM-dd');
```

- ✅ 関数中心の柔軟設計
- ✅ tree-shakingに優れ、軽量
- ❌ タイムゾーン処理は別パッケージに依存

---

## 7. よくある失敗と防止策

### ❌ 文字列フォーマットが環境でブレる

→ ✅ 表示用の整形は `toFormat()` / `format()` で明示的に

---

### ❌ 日時をローカル/UTCで混同

```js
new Date('2025-01-01'); // ❌ ローカル解釈
```

→ ✅ `"2025-01-01T00:00:00Z"` のようにUTC明記する

---

### ❌ 日時操作を標準のDateで手動実装

→ ✅ 日付ライブラリで明示的に設計されたAPIを使うべき

---

## 設計判断フロー

```text
① 単純な日時取得？ → Date.now() / new Date()

② 表示用途？ → Luxon.format() / date-fns.format()

③ 差分・加減算？ → addDays, diffDaysなどのライブラリ使用

④ タイムゾーンを扱う？ → Luxon推奨

⑤ データ保存・API通信？ → ISO 8601 で統一
```

---

## 結語

日付と時刻は、アプリケーションの中でもっとも誤解されやすく壊れやすいデータである。

- **Dateは曖昧に動く。**
- **ISOで固定し、ライブラリで制御せよ。**
- **フォーマットも比較も演算も、意図を明示せよ。**

**「その日付は“いつの、誰の、どの瞬間”か？」――  
それに答えられる構造が、正しく設計された時刻表現である。**
JavaScriptにおけるユーティリティ関数設計：DRY・汎用性・副作用最小化を両立するアプローチ


## 概要

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

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

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

---

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

### ✅ 純粋関数であること（Pure Function）

```js
function toUpper(str) {
  return str.toUpperCase(); // 引数と返り値だけ
}
```

- ❌ グローバル変数の参照・更新をしない
- ❌ DOMやネットワークに依存しない
- ✅ 同じ入力に対して常に同じ出力

---

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

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

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

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

---

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

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

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

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

---

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

```js
// ❌ 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でないかを判定

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

---

### ✅ 配列の重複排除

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

---

### ✅ オブジェクトの深いコピー（Shallow/Deep）

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

---

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

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

---

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

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

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

---

## 設計判断フロー

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

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

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

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

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

---

## 結語

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

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

**小さく設計されたユーティリティが、大きな信頼性を生む。  
関数は“動作”ではなく、“構造”として設計すべきである。**
JavaScriptにおける関数の引数設計：位置・名前・デフォルトによるインターフェース最適化戦略


## 概要

関数の引数は、**関数の使い方を決定する“契約”**である。  
何を受け取るか、どれが必須か、何が省略可能か――それを**構文として明示する設計**こそが、**使いやすく壊れにくいコードの鍵**となる。

本稿では、以下の軸で関数引数の設計戦略を構造化する：

- 位置引数 vs オブジェクト引数の選定基準
- デフォルト値の設計と罠
- 構造分解による明示的な呼び出し
- オプション引数と“明確な不在”の伝達
- 設計判断フローと実践ユースケース

---

## 1. 基本の位置引数とその限界

```js
function createUser(name, age, admin) {
  return { name, age, admin };
}

createUser('Toto', 30, true);
```

- ✅ シンプル・軽量
- ❌ 引数が増えると順番が崩壊する
- ❌ オプションの挿入・スキップが難しい

---

## 2. オブジェクト引数による命名付きインターフェース

```js
function createUser({ name, age, admin = false }) {
  return { name, age, admin };
}

createUser({ name: 'Toto', age: 30 });
```

- ✅ 引数の意味が呼び出し側で明確に
- ✅ オプション/必須の管理が柔軟
- ✅ デフォルト値の設計も簡潔

---

## 3. 構造分解とデフォルトのコンビネーション

```js
function notify({ message = '成功', type = 'info' } = {}) {
  console.log(`[${type}] ${message}`);
}

notify();                          // [info] 成功
notify({ message: '失敗', type: 'error' }); // [error] 失敗
```

- ✅ 全体引数が省略されても安全
- ✅ 柔軟なオプションAPIが実現可能

---

## 4. 引数の構造化：必須・任意の分離戦略

```js
function updateUser(id, { name, age } = {}) {
  // idは必須、他は任意
}
```

- ✅ 「絶対に必要な引数」と「設定可能な引数」を明示的に分離

---

## 5. フラグ型引数のアンチパターン

```js
function toggle(isActive, silently) {
  // ❌ silently = true の意味が曖昧
}
```

→ ✅ フラグではなくオプション名で渡す

```js
function toggle(isActive, { silently = false } = {}) {
  if (!silently) notifyUser();
}
```

---

## 6. スプレッド演算子と引数透過性

```js
function logEvent(event, ...args) {
  console.log(`[${event}]`, ...args);
}

logEvent('click', 'button#submit', 300);
```

- ✅ 可変長引数を扱いやすくなる
- ✅ React/Vueなどのイベント転送にも活用される

---

## 7. 設計判断フロー

```text
① 引数が2つ以内？ → 位置引数で簡潔に

② 引数が3つ以上、またはオプションあり？ → オブジェクト引数へ

③ 必須と任意を分けたい？ → 位置 + オブジェクト分離

④ 意図が曖昧なbooleanを使ってない？ → 意味のあるキー名を使う

⑤ 柔軟な拡張を許容したい？ → デフォルト値と構造分解を活用
```

---

## よくある誤設計と対策

### ❌ フラグ引数の多用

```js
function loadData(cache, debug, timeout) {}
```

→ ✅ `loadData({ cache, debug, timeout })` へ構造的に変更

---

### ❌ デフォルト値を関数本体で上書き

```js
function notify(msg) {
  const message = msg || '成功'; // ❌ '', 0, false を潰す可能性あり
}
```

→ ✅ `msg ?? '成功'` を使う or `= '成功'` を引数定義時に明示

---

## 結語

関数の引数は“入口”であり、“約束”であり、“設計の意思”である。

- 意図が見えるように
- 柔軟性があっても破綻しないように
- 拡張しても読みやすいままであるように

**使う人を守る関数は、インターフェースに意図が刻まれている。  
設計された引数は、読む人を迷わせない。**