※小説ではない※専門書 要約資料集 為替(換算)3.9万円でもらう 紐解集生成 専門 初入門 資料   作:{作者名}

324 / 382
# BOOK-0358k PC創造大全 目録I 関数設計の基本形

> 現代学問宇宙図鑑・PC創造大全(BOOK-0358・統合大型巻)ノウハウ目録・第k部
> 分類記号: KNOW-F-0001〜KNOW-F-0125(関数設計ノウハウ目録・基本形篇・全125項目)
> **接続**: 型見本=BOOK-0184(関数パターン目録I・構造二百種の予約) / 脊椎対=BOOK-0358f(関数を正式に組む) / 次巻=BOOK-0358l(制御と分岐の型・KNOW-F-0126〜0250)
> **執筆規格**: 五点セット(①名称 ②構造の型〈擬似コードまたはJS断片・依存ゼロ〉 ③使いどころ ④組合せ例 ⑤確認事項〈罠と検算・境界値〉)を全125項目に完備。白カード0。

---



# BOOK-0358k PC創造大全 目録I 関数設計の基本形

# BOOK-0358k PC創造大全 目録I 関数設計の基本形

 

> 現代学問宇宙図鑑・PC創造大全(BOOK-0358・統合大型巻)ノウハウ目録・第k部

> 分類記号: KNOW-F-0001〜KNOW-F-0125(関数設計ノウハウ目録・基本形篇・全125項目)

> **接続**: 型見本=BOOK-0184(関数パターン目録I・構造二百種の予約) / 脊椎対=BOOK-0358f(関数を正式に組む) / 次巻=BOOK-0358l(制御と分岐の型・KNOW-F-0126〜0250)

> **執筆規格**: 五点セット(①名称 ②構造の型〈擬似コードまたはJS断片・依存ゼロ〉 ③使いどころ ④組合せ例 ⑤確認事項〈罠と検算・境界値〉)を全125項目に完備。白カード0。

 

---

 

## 序章 関数を「設計する」ということ

 

第III巻(BOOK-0184)では、関数がとりうる「構造のパターン」そのもの——恒等関数や指数関数、合成や反復といった数学的な骨格——を目録化した。本冊(目録I)はその隣接領域として、数学的な骨格を実際のプログラムの関数として書き下すときに繰り返し現れる「設計の型」を扱う。同じ処理内容でも、名前の付け方・引数の並べ方・戻り値の形・エラーの伝え方によって、読みやすさと壊れにくさは大きく変わる。これらは天才的なひらめきではなく、先人が繰り返し失敗と修正を重ねて磨いた「型」であり、型として覚えてしまえば誰でも再現できる技能であるとされる。

 

本冊は関数設計の基本形125種を、命名(第一章)・引数設計(第二章)・戻り値設計(第三章)・制御フローと早期return(第四章)・例外とエラーメッセージ設計(第五章)の5章に分け、各章25項目、合計125項目としてKNOW-F-0001〜KNOW-F-0125の通し番号で正式登録する。各項目には依存ゼロ(外部ライブラリを一切使わない、素のJavaScriptまたは擬似コード)の構造の型を示し、そのまま動く整合性を保つ。

 

**用語の初出定義**: 本冊で「関数」とは、入力(引数)を受け取り、決まった手続きに従って出力(戻り値)を返す、名前を持つ処理のまとまりを指す。「契約」とは、関数が「何を受け取り(前提)・何を返し(保証)・何をしてはいけないか(禁則)」を約束する取り決めを指し、脊椎対のBOOK-0358fで詳述される概念を本冊でも踏襲する。「早期return」とは、関数の冒頭で異常系や例外的な条件を先に処理してreturnし、以降の本体処理を正常系だけに単純化する書き方を指す。

 

---

 

## 第一章 命名の技(KNOW-F-0001〜0025)

 

関数の名前は、その関数を一度も読んだことがない人に向けた最初の説明文である。本章では、名前だけで「何を受け取り、何をするか」が伝わるようにするための型を25種扱う。

 

### KNOW-F-0001 動詞+目的語の基本形

 

**構造の型**:

```js

// 悪い例: 名詞だけ、または動詞が欠けている

function total(items) { /* ... */ }

 

// 良い例: 動詞+目的語で「何をするか」が明示される

function calculateTotal(items) {

return items.reduce((sum, item) => sum + item.price, 0);

}

```

 

**使いどころ**: 副作用や計算を行う関数(手続き・コマンド)全般に適用する基本形。名詞だけの名前は「関数」なのか「値」なのか区別がつかず、呼び出し側で `total(items)` が計算をしているのか、単に既存の合計値を取り出しているのかが読み取れない。

 

**組合せ例**: KNOW-F-0004(get/set対の命名規約)やKNOW-F-0006(変換系動詞)は、いずれも本項の「動詞+目的語」を土台にした専門化である。動詞の選び方に迷ったらまず本項の基本形に立ち返り、その後で用途に応じた専門動詞(get/create/validateなど)へ絞り込むとよい。

 

**確認事項**: 罠は「動詞はあるが目的語が曖昧」なケース(例: `process(data)` は何をprocessするのか不明)。境界値としては、目的語が長くなりすぎる場合(`calculateTotalPriceIncludingTaxAndShippingFee`)は関数の責務過多のシグナルであり、KNOW-F-0050(引数過多のシグナル)やKNOW-F-0092(早期return多用時の関数分割シグナル)と同様に分割を検討する合図になる。

 

---

 

### KNOW-F-0002 真偽値はis/has/canなどの助動詞接頭辞

 

**構造の型**:

```js

function isEmpty(list) {

return list.length === 0;

}

function hasPermission(user, action) {

return user.roles.includes(action);

}

function canRetry(error) {

return error.transient === true;

}

```

 

**使いどころ**: 戻り値が真偽値(boolean)になる関数・変数すべてに適用する。`is`は状態、`has`は所有・保持、`can`は可否・能力、`should`は推奨、という意味の使い分けをチーム内で固定しておくと、名前だけで「これはif文の条件に直接置ける」と判断できる。

 

**組合せ例**: KNOW-F-0009(否定形booleanを避ける)と対で使う。`isEmpty`があれば`isNotEmpty`という否定名は作らず、呼び出し側で`!isEmpty(list)`とする。KNOW-F-0016(述語関数の命名)は本項をArray.prototype.filterやsomeなどの高階関数に渡すコールバックへ拡張したものである。

 

**確認事項**: 罠は接頭辞と実装のズレ——`isValid`という名前なのに例外を投げる実装になっている(真偽値を返さない)ケース。境界値検査としては、`hasPermission(user, action)`に`user`がnull/undefinedのときの挙動を明示すること(KNOW-F-0033のnull/undefined方針と接続)。

 

---

 

### KNOW-F-0003 複数形/単数形の一貫性

 

**構造の型**:

```js

// 配列を返すなら複数形、単一要素を返すなら単数形

function getUser(id) { // 単数: 1件のオブジェクトを返す

return users.find(u => u.id === id);

}

function getUsers(role) { // 複数形: 配列を返す

return users.filter(u => u.role === role);

}

```

 

**使いどころ**: コレクション操作を行う関数群全般。`getUser`と`getUsers`のように語尾のsの有無だけで戻り値の型(単一 vs 配列)を予告できるようにする。

 

**組合せ例**: KNOW-F-0064(空配列/空オブジェクト返し)と組み合わせると、`getUsers`は該当なしのとき`undefined`でなく空配列`[]`を返す設計が自然に導かれる(単数形の`getUser`は該当なしのとき`undefined`またはnullを返す非対称設計になりやすい点も併せて確認する)。

 

**確認事項**: 罠は複数形の関数が単一オブジェクトを返してしまう実装ミス、および単数形の関数が配列を返してしまう逆のミス。境界値として、0件・1件・複数件の3パターンで戻り値の型が変わらないことを検算する(1件のときだけ配列でなく素の値を返す、といった型のブレは呼び出し側のバグを誘発する)。

 

---

 

### KNOW-F-0004 get/set対の命名規約

 

**構造の型**:

```js

class Temperature {

#celsius = 0;

getCelsius() { return this.#celsius; }

setCelsius(value) {

if (typeof value !== "number") throw new TypeError("celsius must be a number");

this.#celsius = value;

}

}

```

 

**使いどころ**: 内部状態への読み書きを提供するとき。`get`は副作用なしで値を返す(問い合わせ)、`set`は状態を変更する(命令)という役割分担を守る。

 

**組合せ例**: KNOW-F-0074(コマンド/クエリ分離)の具体例そのものであり、`getCelsius`はクエリ(問い合わせ、戻り値あり・副作用なし)、`setCelsius`はコマンド(命令、副作用あり・戻り値なし)という分離を体現している。KNOW-F-0032(引数バリデーション位置)は`setCelsius`内のガード節と接続する。

 

**確認事項**: 罠は`getX()`の内部で状態を変更してしまう(問い合わせのはずが副作用を持つ)こと。境界値として、`setCelsius(NaN)`や`setCelsius("20")`のような不正入力に対する挙動を明示すること。

 

---

 

### KNOW-F-0005 create/build/makeの使い分け

 

**構造の型**:

```js

// create: 完成品を1回の呼び出しで生成する

function createUser(name, email) {

return { id: crypto.randomUUID(), name, email, createdAt: Date.now() };

}

 

// build: 段階的に組み立てた最終形を返す(ビルダーの最終呼出し)

class UserBuilder {

#data = {};

withName(name) { this.#data.name = name; return this; }

withEmail(email) { this.#data.email = email; return this; }

build() { return { ...this.#data, id: crypto.randomUUID() }; }

}

```

 

**使いどころ**: `create`は必要な材料が揃っていて即座に完成品を返せる場合、`build`は段階的な組み立て(ビルダーパターン)の最終ステップ、`make`はより軽量・汎用的な生成(create/buildほど厳密な意味を持たせたくない場合)に使う。

 

**組合せ例**: KNOW-F-0019(ファクトリ関数の命名)は本項の`create`系を型として一般化したものであり、KNOW-F-0040(ビルダーパターンとの関係)は`build`系がなぜ必要になるか(引数過多の解消)を説明する。

 

**確認事項**: 罠はプロジェクト内で`create`と`make`が同じ意味で混用され、どちらを使うべきか判断基準が失われること。境界値として、`createUser`が必須フィールド(name, email)を欠いたまま呼ばれた場合の挙動(例外か、デフォルト値補完か)を明示する。

 

---

 

### KNOW-F-0006 変換系動詞 to<Type>() / from<Type>()

 

**構造の型**:

```js

function toCelsius(fahrenheit) {

return (fahrenheit - 32) * 5 / 9;

}

function fromCelsius(celsius) {

return celsius * 9 / 5 + 32;

}

// 検算: toCelsius(fromCelsius(20)) は 20 に戻る(往復変換の恒等性)

```

 

**使いどころ**: ある表現形式から別の表現形式へ変換する関数群。`toX`は「Xへ変換する」、`fromX`は「Xから変換する」という方向を name だけで示す。JSON変換やDTO変換など、往復可能な変換ペアで特に有効。

 

**組合せ例**: BOOK-0184の理-KAN-021(逆関数)の実装側対応にあたる。`toCelsius`と`fromCelsius`は互いの逆関数であり、KNOW-F-0071(冪等性)や検算の考え方をそのまま流用できる——`fromCelsius(toCelsius(x)) === x`が近似的に成立することを確認するのが確認事項の定石になる。

 

**確認事項**: 罠は`toX`と`fromX`の方向を取り違えて実装してしまうこと(呼び出し側では引数の型で気づきにくい)。境界値として、浮動小数点演算による往復変換の誤差(20 → toCelsius → fromCelsius が20.000000001になる等)を許容範囲込みで確認する。

 

---

 

### KNOW-F-0007 検索系動詞 find/search/filter の使い分け

 

**構造の型**:

```js

function findUser(users, id) { // 単一件、なければundefined

return users.find(u => u.id === id);

}

function searchUsers(users, keyword) { // あいまい検索、複数件の可能性

return users.filter(u => u.name.includes(keyword));

}

function filterActiveUsers(users) { // 条件による絞り込み、常に配列

return users.filter(u => u.active);

}

```

 

**使いどころ**: `find`は単一件・厳密一致・0件ならundefined、`search`はあいまい一致・複数件が前提、`filter`は条件による絞り込みで常に配列(0件でも空配列)を返す、という語感の違いをコード上の契約として固定する。

 

**組合せ例**: KNOW-F-0003(複数形/単数形)と対応させると、`findUser`(単数)はKNOW-F-0064で述べる「該当なしをどう表すか」の判断が必要になるのに対し、`filterActiveUsers`(複数)は該当なしでも空配列を返せば済むため判断が単純化される。

 

**確認事項**: 罠は`find`という名前なのに複数件を返してしまう実装、または`filter`という名前なのに該当なしのとき`null`を返してしまう実装(KNOW-F-0052のnull回避パターンに反する)。境界値として、空配列を渡したときの`find`(undefined)、`filter`(空配列)の挙動をそれぞれ確認する。

 

---

 

### KNOW-F-0008 破壊的操作の末尾記号規約

 

**構造の型**:

```js

// 非破壊的: 新しい配列を返し、元の配列は変更しない

function sorted(list) {

return [...list].sort((a, b) => a - b);

}

// 破壊的: 元の配列そのものを変更する(名前にMutate/InPlaceを明示)

function sortInPlace(list) {

list.sort((a, b) => a - b);

return list;

}

```

 

**使いどころ**: JavaScriptには(Rubyの`!`のような)言語標準の破壊的操作記号はないため、`InPlace`・`Mutate`・命令形(`sort`はArray標準で破壊的、`toSorted`は非破壊的)のような接尾辞・接頭辞を用いて、呼び出し側が「元のデータが変わるかどうか」を名前だけで判断できるようにする規約を関数群単位で定める。

 

**組合せ例**: KNOW-F-0034(引数の不変性)と対になる項目であり、非破壊的関数を既定にし、破壊的関数だけを明示的に目立つ名前にする設計方針が、後続のバグ(意図しない元データの書き換え)を防ぐ。

 

**確認事項**: 罠は標準ライブラリの破壊的メソッド(`Array.prototype.sort`, `splice`など)を、非破壊的だと誤解して使うこと。境界値として、`sortInPlace([])`(空配列)や、要素1個の配列に対する挙動が例外を起こさないことを確認する。

 

---

 

### KNOW-F-0009 否定形booleanを避ける

 

**構造の型**:

```js

// 悪い例: 否定の否定が発生しやすい

function isNotDisabled(user) { return !user.disabled; }

if (!isNotDisabled(user)) { /* 二重否定で読みにくい */ }

 

// 良い例: 肯定形で定義し、必要なら呼び出し側で否定する

function isEnabled(user) { return !user.disabled; }

if (!isEnabled(user)) { /* 単純な否定のみ */ }

```

 

**使いどころ**: 真偽値を返す関数・変数を定義するすべての場面。肯定形で名前を付けておけば、呼び出し側での`!`の重なりを1段階までに抑えられる。

 

**組合せ例**: KNOW-F-0002(is/has/can接頭辞)の補則にあたる。`isEnabled`・`isEmpty`・`hasError`のように肯定形で統一し、否定が必要な箇所は呼び出し側の`!`一つに任せる。

 

**確認事項**: 罠は`isDisabled`のような「否定的な状態を肯定形で表した」名前と、`isNotEnabled`のような「肯定的な状態を否定した」名前が混在しチームで統一されないこと。境界値としては特にないが、複数の否定条件を`&&`で連結する際に可読性が急落する境目(否定2つ以上)を分割の目安にするとよい。

 

---

 

### KNOW-F-0010 略語の禁止/許容ルール

 

**構造の型**:

```js

// 略語ルール例: ドメイン標準の略語(id, url, html, http)のみ許容し、

// それ以外は正式名称で書く運用をチームの命名規約として明文化する

function fetchUserById(id) { /* id は許容略語 */ }

function calcTtl(cfg) { /* calc, cfg は非許容: calculate, config と書く */ }

function calculateTtl(config) { /* 修正後 */ }

```

 

**使いどころ**: チームや辞書全体で命名の一貫性を保つ必要がある場面。全面禁止でも全面許容でもなく、業界標準として定着した略語(id/url/html/http/api/db等)のみをホワイトリスト化する運用が現実的である。

 

**組合せ例**: KNOW-F-0011(ドメイン用語の一貫性)、KNOW-F-0024(命名の一貫性チェックリスト化)と組み合わせ、許容略語一覧をプロジェクトの用語辞書に登録して機械検査可能にする。

 

**確認事項**: 罠は個人ごとに略語の判断基準が異なり、同じ概念に`cfg`と`config`が混在すること。境界値として、略語ホワイトリストにない単語が新規追加されたときにレビューで正式名称へ差し戻すルールを運用に組み込む。

 

---

 

### KNOW-F-0011 ドメイン用語辞書との一貫性

 

**構造の型**:

```js

// 用語辞書: { "顧客": "customer", "注文": "order", "在庫": "stock" }

// 同じ概念に "client" と "customer" を混在させない

function createCustomer(name) { /* customer で統一 */ }

function createClient(name) { /* 別概念: 開発ツールの利用者などと区別して使う場合のみ許可 */ }

```

 

**使いどころ**: ドメイン(業務領域)固有の概念を関数名・変数名に反映するとき。同じ実体を指す単語が複数存在すると(customer/client、order/purchase等)、検索性が落ち、読み手が「同じものか別物か」を都度確認するコストが発生する。

 

**組合せ例**: KNOW-F-0010(略語ルール)と対になる「表記ゆれ対策」の項目。用語辞書はfusen-kbのような辞書資産として登録し、命名時に必ず参照する運用にすると効果が長続きする。

 

**確認事項**: 罠は用語辞書を作った後にメンテナンスされず形骸化すること。境界値として、新機能追加時に既存語彙で表現できない新概念が出た場合は、辞書への追加をコードレビューの必須項目にする。

 

---

 

### KNOW-F-0012 単位をパラメータ名・戻り値名に含める

 

**構造の型**:

```js

// 悪い例: 単位が名前から読み取れない

function setTimeout2(fn, timeout) { /* ミリ秒?秒? */ }

 

// 良い例: 単位を名前に含める

function scheduleAfter(fn, delayMs) {

return setTimeout(fn, delayMs);

}

function getFileSizeBytes(path) { /* ... */ }

```

 

**使いどころ**: 時間・距離・重量・データ量など、単位の取り違えが実害につながる引数・戻り値すべてに適用する。`delayMs`・`sizeBytes`・`distanceMeters`のように単位を接尾辞として明示する。

 

**組合せ例**: KNOW-F-0046(引数の単位混同を防ぐ設計)の最も手軽な実装形がこれである。より厳格にしたい場合はKNOW-F-0042(値オブジェクト)で単位付きの型そのものを作る発展形へ進む。

 

**確認事項**: 罠は単位付きの名前にリネームした後、呼び出し側の実引数の単位が実は違っていた(秒をミリ秒として渡していた)ことが発覚するケース——リネームは既存の誤りを可視化する副次効果を持つ。境界値として、`delayMs`に負の値や0が渡された場合の挙動を明示する。

 

---

 

### KNOW-F-0013 ハンガリアン記法の是非

 

**構造の型**:

```js

// 型接頭辞ハンガリアン(非推奨): 型情報は静的型やlintで代替可能

let strName = "Alice"; // 非推奨

 

// 意味ハンガリアン(許容): 単位・役割など型検査では拾えない情報を示す

let rawInputHtml = "<b>hi</b>"; // サニタイズ前であることを明示

let sanitizedHtml = sanitize(rawInputHtml);

```

 

**使いどころ**: 変数・引数の型そのもの(str, num, arr)を接頭辞にする「型ハンガリアン」は、TypeScriptやJSDocの型注釈、あるいはlintで代替できるため基本的に不要。一方、「未サニタイズ」「秒」など型検査だけでは分からない意味情報を示す「意味ハンガリアン」は今日でも有効に使われる。

 

**組合せ例**: KNOW-F-0012(単位を名前に含める)は意味ハンガリアンの一種であり、KNOW-F-0116(エラーメッセージへの機密情報混入防止)で登場する`rawInput`/`sanitized`の区別も同じ発想である。

 

**確認事項**: 罠は型ハンガリアンを機械的に全変数へ適用し、型が変わるたびに変数名もリネームする必要が生じて保守コストが増すこと。境界値としては特にないが、`rawInputHtml`のような意味ハンガリアンを使った変数が、サニタイズ処理を経ずに出力へ渡っていないかをレビューで確認する運用と組み合わせると効果が高い。

 

---

 

### KNOW-F-0014 汎用名(data, info, temp, obj)の回避

 

**構造の型**:

```js

// 悪い例: 何のデータか分からない

function process(data) { return data.map(obj => obj.value * 2); }

 

// 良い例: 具体的な対象名を使う

function doubleAllPrices(products) {

return products.map(product => product.price * 2);

}

```

 

**使いどころ**: 関数の引数名・ローカル変数名を決めるすべての場面。`data`・`info`・`temp`・`obj`・`item`のような汎用語は、コードの検索性(grepでの発見しやすさ)と可読性の両方を下げる。

 

**組合せ例**: KNOW-F-0001(動詞+目的語)で関数名を具体化するのと対で、引数名も具体化することで、関数シグネチャ全体(`doubleAllPrices(products)`)が一つの文として読めるようになる。

 

**確認事項**: 罠は汎用名がコピー&ペーストで量産され、後から一括リネームしようにも影響範囲が広すぎて手が付けられなくなること。境界値として、汎用的なユーティリティ関数(本当に何でも受け取れる関数、例えば`identity(x)`)では逆に`x`のような短い名前の方が適切な例外ケースがある点も確認する。

 

---

 

### KNOW-F-0015 コールバック引数の命名慣習(onXxx, handleXxx)

 

**構造の型**:

```js

function fetchData(url, onSuccess, onError) {

fetch(url)

.then(res => res.json())

.then(onSuccess)

.catch(onError);

}

// 呼び出し側でイベント処理を行う関数はhandleを使う

function handleSubmit(event) { /* ... */ }

```

 

**使いどころ**: 高階関数の引数として渡すコールバックを定義する場面。関数を「受け取る側」の引数名は`onイベント名`(onClick, onSuccess)、「処理する側」の関数名は`handleイベント名`(handleClick, handleSubmit)という慣習をチームで統一する。

 

**組合せ例**: KNOW-F-0018(イベントハンドラ命名)は本項の`handleXxx`側を専門化したものであり、KNOW-F-0048(引数として関数を渡す設計)は本項の理論的背景(高階関数)を扱う。

 

**確認事項**: 罠は`onSuccess`という引数名なのに実際は同期的に即時実行されてしまう(非同期を期待した呼び出し側が混乱する)実装ズレ。境界値として、`onError`が渡されなかった場合(undefined)にエラーが握りつぶされないよう、デフォルトのエラー処理を用意する。

 

---

 

### KNOW-F-0016 述語関数(predicate)の命名 — 単数形+条件節

 

**構造の型**:

```js

const isAdult = (user) => user.age >= 20;

const hasDiscount = (order) => order.total > 10000;

 

const adults = users.filter(isAdult);

const discountedOrders = orders.filter(hasDiscount);

```

 

**使いどころ**: `Array.prototype.filter`・`some`・`every`・`find`に渡す真偽値関数(述語)を独立した名前付き関数として切り出す場面。無名関数のまま埋め込むよりも、意図が名前として読めるようになる。

 

**組合せ例**: KNOW-F-0002(is/has/can接頭辞)をコールバックへ応用した項目。KNOW-F-0073(コールバックの戻り値活用)は述語関数の戻り値がfilter/mapの挙動をどう左右するかを扱う。

 

**確認事項**: 罠は述語関数の中で副作用(外部変数の書き換えなど)を起こしてしまうこと——filterに渡す関数は純粋(参照透過)であるべき。境界値として、配列が空のときに`filter`が空配列を返す(述語が一度も呼ばれない)ことを確認する。

 

---

 

### KNOW-F-0017 非同期関数の命名規約

 

**構造の型**:

```js

// Async接尾辞、またはPromiseを返すことが自明な動詞(fetch/load)を使う

async function fetchUserAsync(id) {

const res = await fetch(`/api/users/${id}`);

return res.json();

}

// 呼び出し側は名前からawaitが必要と判断できる

const user = await fetchUserAsync(1);

```

 

**使いどころ**: Promiseを返す関数・async functionすべてに適用する。`Async`接尾辞、または`fetch`/`load`/`save`のような「時間がかかることが自明な動詞」を選ぶことで、呼び出し側に`await`忘れを警告する手がかりを与える。

 

**組合せ例**: KNOW-F-0062(Promise/async関数の戻り値設計)、KNOW-F-0115(非同期エラーのハンドリング)と三点セットで扱う項目。命名(本項)・戻り値の型(0062)・エラー処理(0115)の3つを揃えて初めて非同期関数の設計が完結する。

 

**確認事項**: 罠は`Async`接尾辞を付けたのに内部でawaitを忘れてPromiseのPromiseを返してしまう(`Promise<Promise<T>>`のネスト)実装ミス。境界値として、`fetchUserAsync`にネットワークが繋がらない場合の拒否(reject)経路を確認する。

 

---

 

### KNOW-F-0018 イベントハンドラ命名(handle+動詞+目的語)

 

**構造の型**:

```js

button.addEventListener("click", handleSubmitClick);

 

function handleSubmitClick(event) {

event.preventDefault();

submitForm(event.target.form);

}

```

 

**使いどころ**: DOMイベントやカスタムイベントに対する処理関数を定義する場面。`handle`接頭辞でイベント処理関数であることを示し、続く語でどのイベント・どの対象への処理かを明示する。

 

**組合せ例**: KNOW-F-0015(コールバック引数の命名慣習)の`handleXxx`側の専門形。イベントハンドラ内部からビジネスロジック(`submitForm`)を分離しておくと、KNOW-F-0059(voidの使いどころ)やテスト容易性(KNOW-F-0124)にもつながる。

 

**確認事項**: 罠はイベントハンドラの中にビジネスロジックを直接書き込み、DOMに依存しないテストができなくなること。境界値として、同じイベントに複数のハンドラが登録された場合の実行順序・`preventDefault`の呼び忘れを確認する。

 

---

 

### KNOW-F-0019 ファクトリ関数の命名(createXxx/xxxFactory)

 

**構造の型**:

```js

function createLogger(prefix) {

return {

info: (msg) => console.log(`[${prefix}] ${msg}`),

error: (msg) => console.error(`[${prefix}] ${msg}`),

};

}

const appLogger = createLogger("APP");

appLogger.info("起動しました");

```

 

**使いどころ**: 設定に応じて異なる振る舞いを持つオブジェクト・関数群を生成する場面。`createXxx`は「その場で1つ作る」、`xxxFactory`は「作る関数自体を値として扱う」ニュアンスの違いがある。

 

**組合せ例**: KNOW-F-0005(create/build/makeの使い分け)の具体的応用であり、KNOW-F-0066(部分適用/カリー化された関数の戻り値)とも接続する——ファクトリ関数はしばしば「設定を固定した専用関数」を返すカリー化の一種とみなせる。

 

**確認事項**: 罠はファクトリが返すオブジェクトの内部状態(クロージャ変数)が複数インスタンス間で意図せず共有されてしまうこと(モジュールスコープの変数を誤って参照する等)。境界値として、`createLogger("")`のように空文字列のprefixが渡された場合の表示を確認する。

 

---

 

### KNOW-F-0020 バリデーション関数の命名(validateXxx / assertXxx / isValidXxx)

 

**構造の型**:

```js

function isValidEmail(email) { // 真偽値を返す(判定のみ)

return /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email);

}

function assertValidEmail(email) { // 不正なら例外を投げる(制御フロー)

if (!isValidEmail(email)) throw new Error(`invalid email: ${email}`);

}

function validate(input) { // 複数フィールドをまとめて検証しエラー一覧を返す

const errors = [];

if (!isValidEmail(input.email)) errors.push("email is invalid");

return errors;

}

```

 

**使いどころ**: 入力検証を行う関数群を、戻り値の型で3種類に使い分ける場面。`isValidXxx`は真偽値、`assertXxx`は例外(制御フローを止める)、`validate`は複数エラーの集約という役割分担を名前で予告する。

 

**組合せ例**: KNOW-F-0108(バリデーションエラーの集約)は`validate`系の発展形であり、KNOW-F-0101(例外と戻り値の使い分け基準)は`isValidXxx`と`assertXxx`のどちらを選ぶべきかの判断基準を扱う。

 

**確認事項**: 罠は`isValidXxx`という名前なのに例外を投げてしまう実装(呼び出し側がtry-catchを用意していないと未処理例外になる)。境界値として、空文字列・null・undefinedをそれぞれ`isValidEmail`に渡したときに例外を投げず安全にfalseを返すことを確認する。

 

---

 

### KNOW-F-0021 変換パイプライン関数の命名連鎖(parseXxx→normalizeXxx→formatXxx)

 

**構造の型**:

```js

function parseDateInput(raw) { // 文字列 → 中間表現(Date)

return new Date(raw);

}

function normalizeToUtc(date) { // 中間表現 → 正規化済み中間表現

return new Date(date.toISOString());

}

function formatAsIsoDate(date) { // 中間表現 → 文字列

return date.toISOString().slice(0, 10);

}

const result = formatAsIsoDate(normalizeToUtc(parseDateInput("2026/07/10")));

```

 

**使いどころ**: 「文字列 → 内部表現 → 別の文字列」のような多段変換を行う処理を、1つの巨大関数にせず、各段階を独立した小関数に分割する場面。`parse`(取り込み)→`normalize`(正規化)→`format`(出力整形)という語彙の連鎖が処理の流れそのものを表す。

 

**組合せ例**: KNOW-F-0006(to/from変換動詞)の系列を多段に拡張したものであり、KNOW-F-0067(戻り値のチェイン可能性)と組み合わせるとメソッドチェーンとしても表現できる。

 

**確認事項**: 罠は各段階の入出力の型が一貫していない(parseの出力型とnormalizeの入力型がずれる)こと。境界値として、`parseDateInput("invalid")`のような不正な日付文字列が`Invalid Date`を生成し、後続の段階でエラーにならず静かに壊れたデータが流れる危険を確認する(KNOW-F-0032の引数バリデーションと接続)。

 

---

 

### KNOW-F-0022 名前の長さと文脈のバランス

 

**構造の型**:

```js

// スコープが広い(モジュール外に公開)場合は長く具体的に

export function calculateShippingFeeForInternationalOrder(order) { /* ... */ }

 

// スコープが狭い(1行のコールバック内など)場合は短くてよい

const total = items.reduce((sum, i) => sum + i.price, 0);

```

 

**使いどころ**: 名前の長さを決める全ての場面。原則は「スコープが狭く、寿命が短い変数ほど短い名前でよく、スコープが広く、寿命が長い(公開API等)ほど具体的で長い名前にする」というバランス感覚である。

 

**組合せ例**: KNOW-F-0023(一時変数・内部関数の命名規約)は本項の「狭いスコープ側」を、KNOW-F-0011(ドメイン用語辞書)は「広いスコープ側」の一貫性を担当する、対になる項目。

 

**確認事項**: 罠は狭いスコープの変数にまで冗長な長い名前を付けてかえって読みにくくすること、逆に公開APIの関数名を`f`や`calc`のように短くしすぎて意味不明になること。境界値としては特にないが、レビュー時に「この名前は呼び出し元から見て何をするか一目で分かるか」を基準に判定するとよい。

 

---

 

### KNOW-F-0023 一時変数・内部関数の命名規約

 

**構造の型**:

```js

function calculateTotal(items) {

let sum = 0; // ループ内だけで使う一時変数はsumで十分

for (const item of items) {

const linePrice = item.price * item.quantity; // 内部限定の中間値

sum += linePrice;

}

return sum;

}

```

 

**使いどころ**: 関数内部だけで完結する短命な変数・ヘルパー関数を命名する場面。外部から一切参照されないことが保証されているため、ドメイン用語辞書ほど厳密な命名でなくても、その関数のコンテキスト内で意味が通れば十分とする。

 

**組合せ例**: KNOW-F-0022(名前の長さと文脈のバランス)の実例であり、KNOW-F-0087(条件式の複雑さを関数抽出で解消)で抽出される内部ヘルパー関数の命名にもこの緩やかな基準を適用する。

 

**確認事項**: 罠は「一時変数だから」といって`a`, `b`, `tmp`のような意味のない名前を多用し、10行を超える関数内で意味を追えなくなること。境界値の目安として、変数の生存期間がループ1回分・数行以内であれば短い名前を許容し、それを超えて関数全体で使われるなら具体的な名前へ格上げする。

 

---

 

### KNOW-F-0024 命名の一貫性チェックリスト化(lint的自己検査)

 

**構造の型**:

```js

// 自己検査の疑似コード: 命名規約に反する識別子を検出する

function checkNamingRules(sourceCode, rules) {

const violations = [];

for (const rule of rules) {

const matches = sourceCode.match(rule.pattern) || [];

for (const m of matches) {

if (!rule.isValid(m)) violations.push({ rule: rule.name, token: m });

}

}

return violations; // 空配列なら合格

}

```

 

**使いどころ**: KNOW-F-0001〜0023で述べた命名規約群を、レビュー担当者の主観に頼らず機械的に検査したい場面。ESLintのようなツールのカスタムルール、あるいは簡易な正規表現チェックスクリプトとして実装できる。

 

**組合せ例**: KNOW-F-0010(略語ルール)のホワイトリスト、KNOW-F-0002(is/has/can接頭辞)の対象boolean変数など、本冊の命名項目のほとんどはこの機械検査に落とし込める。KNOW-F-0125(エラー処理の一貫性チェックリスト)と対をなす「命名版チェックリスト」である。

 

**確認事項**: 罠はルールを厳しくしすぎて誤検知(false positive)が多発し、開発者がチェックを無視するようになること。境界値として、新しいルールを追加する際は既存コードベース全体に対して一度試験実行し、誤検知率が許容範囲(例えば5%未満)であることを確認してから正式導入する。

 

---

 

### KNOW-F-0025 誤解を招く名前の禁止

 

**構造の型**:

```js

// 悪い例: 名前は「取得」だが実際はネットワーク通信を伴う重い処理

function getUser(id) {

return fetch(`/api/users/${id}`).then(r => r.json()); // 名前が嘘をついている

}

// 良い例: 実態に合わせて動詞を選ぶ

function fetchUser(id) {

return fetch(`/api/users/${id}`).then(r => r.json());

}

```

 

**使いどころ**: すべての命名判断における最終チェック項目。`get`は「軽量・即座・副作用なし」を期待させる名前であり、ネットワーク通信やディスクI/Oのような重い処理・失敗しうる処理には`fetch`・`load`・`fetchXxxAsync`(KNOW-F-0017)のような「時間がかかることを予告する動詞」を使うべきである。

 

**組合せ例**: 本項は第一章の総括にあたり、KNOW-F-0001〜0024すべての命名技法が守るべき上位原則(「名前は嘘をつかない」)を明文化したものである。第二章以降の引数・戻り値・エラー処理の設計判断でも、この原則(契約と実装を一致させる)が繰り返し適用される。

 

**確認事項**: 罠は命名規約(接頭辞のルール等)には従っているのに、実装の実態(重さ・副作用の有無・失敗しうるか)とズレていること。境界値として、リファクタリングで関数の実装(同期→非同期、軽量→重い処理)を変更したときは、必ず名前も見直す運用ルールをチームに定着させる。

 

---

 

## 第二章 引数設計の技(KNOW-F-0026〜0050)

 

関数の引数は、呼び出し側との「入力の契約」である。本章では、引数の並べ方・個数・デフォルト値・オプションオブジェクトなど、呼び出し側の負担を減らしつつ誤用を防ぐための型を25種扱う。

 

### KNOW-F-0026 引数順序の原則(重要度順・データ→設定の順)

 

**構造の型**:

```js

// 原則: 主たる操作対象(データ)を先に、付随する設定・オプションを後に置く

function resize(image, width, height, { keepAspectRatio = true } = {}) {

// image: 主対象、width/height: 必須設定、keepAspectRatio: 付随オプション

}

```

 

**使いどころ**: 2つ以上の引数を持つ関数すべて。「操作対象→必須の設定値→省略可能なオプション」の順に並べておくと、呼び出し側が引数リストの前半だけ見ればおおよその使い方を把握できる。

 

**組合せ例**: KNOW-F-0029(オプションオブジェクトパターン)は本項の「末尾のオプション」を発展させた形であり、KNOW-F-0037(コールバック引数の位置規約)も「末尾に置く」という同じ原則の応用である。

 

**確認事項**: 罠は関連性の薄い引数を先頭に置いてしまい、呼び出し側が主対象を見失うこと。境界値として、引数が1個だけの関数ではこの原則は問題にならないが、3個を超えたあたりからKNOW-F-0027(個数上限)の検討対象になる。

 

---

 

### KNOW-F-0027 引数個数上限(3個ルール)とその超過時の対処

 

**構造の型**:

```js

// 悪い例: 引数4個超、順序を覚えないと呼べない

function createEvent(title, start, end, location, isAllDay, color) { /* ... */ }

 

// 良い例: 3個を超える設定はオブジェクトにまとめる

function createEvent(title, { start, end, location, isAllDay = false, color = "blue" }) {

/* ... */

}

```

 

**使いどころ**: 引数の個数を設計する全ての場面での目安。経験則として「3個まではそのまま並べてよいが、4個を超えたらオプションオブジェクト化を検討する」という上限を置くと、呼び出し側の引数順序の暗記負担が減る。

 

**組合せ例**: KNOW-F-0029(オプションオブジェクトパターン)が超過時の主たる対処法であり、KNOW-F-0040(ビルダーパターン)はオブジェクト化してもなお項目数が多い場合のさらなる発展形である。

 

**確認事項**: 罠は「3個ルール」を機械的に適用しすぎて、本来まとまりのある3引数をわざわざオブジェクト化し逆に読みにくくすること(例えば`add(a, b, c)`のような数学的に対称な3引数)。境界値として、意味的に対称な引数(座標のx, y, zなど)は個数に関わらずそのまま並べてよい例外を認める。

 

---

 

### KNOW-F-0028 デフォルト引数の設計

 

**構造の型**:

```js

function createConnection(host, port = 443, { timeoutMs = 5000, retries = 3 } = {}) {

return { host, port, timeoutMs, retries };

}

console.assert(createConnection("example.com").port === 443);

console.assert(createConnection("example.com", 8080).timeoutMs === 5000);

```

 

**使いどころ**: 多くの呼び出しで同じ値を使うが、まれに変更したい引数を持つ関数。デフォルト値によって呼び出し側の記述量を減らし、かつ意図を明示できる(`port = 443`は「通常はHTTPSポート」という文書化にもなる)。

 

**組合せ例**: KNOW-F-0029(オプションオブジェクトパターン)と組み合わせると、デフォルト値をオブジェクトの分割代入時に一括で設定でき(`{ timeoutMs = 5000 } = {}`)、KNOW-F-0039(デフォルト値と副作用の分離)は評価タイミングの罠を扱う。

 

**確認事項**: 罠はデフォルト値が「意味のある値」なのか「未設定を表すプレースホルダー」なのか曖昧なこと(0やnullをデフォルトにすると「明示的に0を渡した」のか「省略した」のか区別できない)。境界値として、`createConnection("example.com", undefined, {})`のように途中の引数だけundefinedで渡した場合にデフォルト値が正しく適用されることを確認する(JavaScriptの仕様上、undefinedはデフォルト値適用のトリガーになる)。

 

---

 

### KNOW-F-0029 オプションオブジェクトパターン(名前付き引数の代替)

 

**構造の型**:

```js

function fetchList({ page = 1, pageSize = 20, sortBy = "createdAt", order = "desc" } = {}) {

return { page, pageSize, sortBy, order };

}

// 呼び出し側は必要な項目だけ名前付きで指定できる

fetchList({ page: 2, order: "asc" });

```

 

**使いどころ**: 省略可能な設定項目が多い関数、あるいは将来項目が増える見込みのある関数。JavaScriptには名前付き引数の言語機能がないため、単一のオブジェクト引数と分割代入によってそれを模倣する。

 

**組合せ例**: KNOW-F-0027(引数個数上限)の超過時対処、KNOW-F-0041(引数の順序に依存しないAPI設計)の実装手段そのものである。KNOW-F-0044(引数のデストラクチャリングパターン)は本項の分割代入部分を専門に扱う。

 

**確認事項**: 罠はオプションオブジェクトのキー名を打ち間違えても実行時にエラーにならず、静かに無視されて既定値のまま動いてしまうこと(TypeScriptを使わない場合の代表的な落とし穴)。境界値として、`fetchList()`(引数なし)と`fetchList({})`(空オブジェクト)の両方が同じ既定値で動くことを確認する(デフォルト引数`= {}`がこれを保証する)。

 

---

 

### KNOW-F-0030 可変長引数(rest parameters)の使いどころ

 

**構造の型**:

```js

function sum(...numbers) {

return numbers.reduce((total, n) => total + n, 0);

}

console.assert(sum(1, 2, 3) === 6);

console.assert(sum() === 0);

```

 

**使いどころ**: 引数の個数が呼び出しごとに変わり、かつすべて同じ意味・同じ型を持つ場面(合計を求める・複数の要素を結合する等)。個数が固定でない場合に配列を引数として渡すよりも、呼び出し側の記述が自然になる。

 

**組合せ例**: KNOW-F-0043(配列引数とスプレッド構文の使い分け)と対をなし、関数定義側では`...args`(rest)、呼び出し側では`fn(...array)`(spread)という表裏の関係にある。KNOW-F-0036(引数の型ガード)と組み合わせ、rest引数の要素すべてが期待する型かを検証することもある。

 

**確認事項**: 罠はrest引数の後に別の引数を置いてしまう構文エラー(restは必ず最後に置かなければならない)。境界値として、`sum()`(引数0個)が例外を投げずに0を返すこと、および極端に大量の引数(数万個)を渡した場合のスタック・メモリ上限を意識する。

 

---

 

### KNOW-F-0031 フラグ引数(boolean引数)を避ける

 

**構造の型**:

```js

// 悪い例: 呼び出し側でtrueが何を意味するか読み取れない

function createUser(name, sendWelcomeEmail) { /* ??? */ }

createUser("Alice", true);

 

// 良い例: 名前付きオプションにするか、関数を分ける

function createUser(name, { sendWelcomeEmail = false } = {}) { /* ... */ }

createUser("Alice", { sendWelcomeEmail: true });

```

 

**使いどころ**: boolean型の引数を追加しようとするすべての場面での判断基準。`createUser("Alice", true)`という呼び出しは、コードを読むだけでは`true`が何を意味するか分からない(呼び出し箇所にコメントが必要になる時点で設計不良のシグナル)。

 

**組合せ例**: KNOW-F-0029(オプションオブジェクトパターン)による解消がもっとも一般的であり、真偽値で処理内容そのものが大きく変わる場合はKNOW-F-0035(オーバーロード的設計)のように関数自体を分割する選択もある。

 

**確認事項**: 罠はフラグ引数が3つ、4つと増え、`createUser(name, true, false, true)`のような「真偽値の羅列」になること(呼び出し箇所の可読性が完全に失われる)。境界値として、フラグが2値でなく将来3値以上に拡張される可能性がある場合は、booleanでなく列挙的な文字列(`"eager" | "lazy" | "none"`)に置き換えることを検討する。

 

---

 

### KNOW-F-0032 引数のバリデーション位置(関数冒頭でのガード)

 

**構造の型**:

```js

function divide(a, b) {

if (typeof a !== "number" || typeof b !== "number") {

throw new TypeError("a and b must be numbers");

}

if (b === 0) {

throw new RangeError("b must not be zero");

}

return a / b; // ここから先は正常な引数のみが到達する

}

```

 

**使いどころ**: 外部(呼び出し側)から受け取る引数が想定外の値である可能性がある関数すべて。関数の本体処理を始める前に、冒頭でまとめて検証(ガード節)することで、本体のロジックを「正常な入力だけを扱えばよい」単純な形に保てる。

 

**組合せ例**: 第四章KNOW-F-0076(ガード節による早期return基本形)の引数版であり、KNOW-F-0045(引数バリデーションとエラー早期return)と直接対応する。KNOW-F-0020(バリデーション関数の命名)で述べた`assertXxx`をここに組み込むこともできる。

 

**確認事項**: 罠はバリデーションを本体処理の途中に分散して書いてしまい、どこまで検証が済んでいるか追いにくくなること。境界値として、`divide(10, 0)`(ゼロ除算)・`divide("10", 2)`(型不正)の両方が本体処理に到達する前に例外で止まることを確認する。

 

---

 

### KNOW-F-0033 null/undefinedの扱い方針の統一

 

**構造の型**:

```js

// 方針例: 「値がない」はundefinedで統一し、nullは使わない(またはその逆)

function findConfig(key) {

return configMap.has(key) ? configMap.get(key) : undefined; // nullは使わない

}

function useConfig(key) {

const value = findConfig(key) ?? "default"; // undefinedのみを想定したデフォルト処理

return value;

}

```

 

**使いどころ**: 特定の関数に限らずプロジェクト全体。JavaScriptには`null`と`undefined`という2つの「値がない」表現が存在するため、どちらを「意図的に空」、どちらを「未設定・未初期化」に使うかをプロジェクト単位で統一しないと、`== null`のような曖昧な比較が増えてバグを誘発する。

 

**組合せ例**: KNOW-F-0052(null回避のためのOptional的パターン)と対になる「入口側」の方針であり、KNOW-F-0064(空配列/空オブジェクト返し)は「そもそもnull/undefinedを返さない」というさらに踏み込んだ選択肢を示す。

 

**確認事項**: 罠は`if (value == null)`(緩い等価比較でnullとundefinedの両方を弾く書き方)をプロジェクトの一部でだけ使い、他の箇所では`=== null`や`=== undefined`を個別に使うといった不統一。境界値として、`findConfig`に存在しないキーを渡した場合に必ず`undefined`が返り、`null`が混入しないことを確認する。

 

---

 

### KNOW-F-0034 引数の不変性(ミューテーションしない設計)

 

**構造の型**:

```js

// 悪い例: 引数の配列を直接書き換える(呼び出し元に影響が漏れる)

function addTax(cart) {

cart.forEach(item => item.price *= 1.1); // 副作用が漏れる

return cart;

}

// 良い例: 新しい配列・オブジェクトを作って返す

function withTax(cart) {

return cart.map(item => ({ ...item, price: item.price * 1.1 }));

}

```

 

**使いどころ**: すべての引数(特にオブジェクト・配列)を受け取る関数。関数の内部で引数そのものを書き換える(ミューテーション)と、呼び出し元が「渡したはずの元データ」が知らないうちに変わってしまうという遠隔作用のバグを生みやすい。

 

**組合せ例**: KNOW-F-0008(破壊的操作の末尾記号規約)と対で使う——本項の非破壊的関数を既定にし、破壊的な操作を行う関数だけ明示的な名前(`InPlace`等)を付ける。KNOW-F-0060(戻り値のイミュータビリティ)は出口側の対応する原則である。

 

**確認事項**: 罠は`{ ...item }`のようなスプレッド構文が「浅いコピー」であり、ネストしたオブジェクトまでは複製されないこと(item.tags配列などは参照が共有されたまま)。境界値として、空配列`[]`や、要素が1つもないオブジェクトを渡した場合に例外を起こさず空の結果を返すことを確認する。

 

---

 

### KNOW-F-0035 オーバーロード的設計(型で分岐するのでなく関数を分ける)

 

**構造の型**:

```js

// 悪い例: 引数の型によって処理が大きく分岐する(JSにオーバーロードはない)

function render(target) {

if (typeof target === "string") { /* セレクタとして扱う */ }

else if (target instanceof HTMLElement) { /* 要素として扱う */ }

}

// 良い例: 型ごとに関数を分ける

function renderBySelector(selector) { /* ... */ }

function renderByElement(element) { /* ... */ }

```

 

**使いどころ**: 引数の型によって処理内容が大きく異なる場面。JavaScriptには静的なオーバーロード機構がなく、`typeof`分岐に頼ると1つの関数が複数の異なる責務を抱え込みやすい。型ごとに関数を分割し、必要なら共通処理を内部で呼び合う形にする。

 

**組合せ例**: KNOW-F-0036(引数の型ガード)は本項をあえて1つの関数内で行う場合の防御的実装であり、両者はトレードオフの関係にある(呼び出し側の使いやすさ vs 実装の単純さ)。KNOW-F-0092(早期return多用時の関数分割シグナル)も同じ「型分岐は分割のサイン」という発想を共有する。

 

**確認事項**: 罠は型分岐を残したまま処理が肥大化し、片方の型のケースを修正したらもう片方が壊れるという「絡み合い」が発生すること。境界値として、想定していない第3の型(number等)が渡された場合にどちらの分岐にも該当せず静かに何もしない、という危険な既定動作を避け、明示的にエラーを投げることを確認する。

 

---

 

### KNOW-F-0036 引数の型ガード(防御的チェック)

 

**構造の型**:

```js

function assertIsArray(value, name = "value") {

if (!Array.isArray(value)) {

throw new TypeError(`${name} must be an array, got ${typeof value}`);

}

}

function sumAll(numbers) {

assertIsArray(numbers, "numbers");

return numbers.reduce((a, b) => a + b, 0);

}

```

 

**使いどころ**: TypeScriptのような静的型検査を使わない、または外部入力(JSON等)を直接受け取る関数の入口。実行時に型を確認し、想定外の型であれば早期に例外を投げることで、後続の処理で発生する分かりにくいエラー(`undefined.map is not a function`等)を、原因の分かりやすいエラーに変換できる。

 

**組合せ例**: KNOW-F-0032(引数のバリデーション位置)の一部として型ガードを組み込むのが定石であり、KNOW-F-0113(境界層でのエラー変換)は外部入力を受け取る層(APIハンドラ等)で本項を集中的に使う設計を扱う。

 

**確認事項**: 罠は型ガードを一部の関数にだけ入れ、内部の下位関数では省略してしまい、結局どこかで想定外の型が素通りすること。境界値として、`sumAll(null)`・`sumAll("123")`(配列でない値)がそれぞれ`assertIsArray`で捕捉されることを確認する。

 

---

 

### KNOW-F-0037 コールバック引数の位置規約(末尾に置く)

 

**構造の型**:

```js

// 良い例: コールバックは常に最後の引数

function retry(operation, maxAttempts, onEachFailure) {

for (let i = 0; i < maxAttempts; i++) {

try { return operation(); }

catch (err) { onEachFailure?.(err, i); }

}

throw new Error("all attempts failed");

}

```

 

**使いどころ**: コールバック関数を受け取るすべての高階関数。コールバックを引数リストの末尾に置く慣習は、呼び出し側で無名関数やアロー関数をインラインで書いたときに、コードの見た目が「本体の中に処理が続く」ように読めるという利点がある(`array.map((x) => ...)`と同じ形)。

 

**組合せ例**: KNOW-F-0026(引数順序の原則)の一部として扱われる規約であり、KNOW-F-0048(引数として関数を渡す設計)の実践的な補足にあたる。

 

**確認事項**: 罠はコールバックを引数の途中に挟んでしまい、呼び出し側でオプション引数を省略できなくなること(コールバックの後にまだ引数が続く設計は避ける)。境界値として、コールバック引数が省略可能(`onEachFailure?.`のようにオプショナルチェイニングで安全に呼ぶ)な場合、未指定でも例外にならないことを確認する。

 

---

 

### KNOW-F-0038 引数の依存関係を表現する

 

**構造の型**:

```js

// 悪い例: startとendが独立引数で、片方だけ渡すと壊れる

function createRange(start, end) { /* startだけ渡すと end は undefined */ }

 

// 良い例: 依存し合う引数は1つのオブジェクトにまとめてまとめて検証する

function createRange({ start, end }) {

if (start === undefined || end === undefined) {

throw new Error("start and end must both be provided together");

}

if (start > end) throw new RangeError("start must be <= end");

return { start, end };

}

```

 

**使いどころ**: 「Aを指定するならBも必須」「AとBは同時に指定できない(排他)」のような引数間の制約がある関数。個別の引数のままだと制約が名前や型からは読み取れないため、オブジェクトにまとめた上で関数冒頭のガード節(KNOW-F-0032)で制約を検証する。

 

**組合せ例**: KNOW-F-0029(オプションオブジェクトパターン)を前提とし、KNOW-F-0108(バリデーションエラーの集約)と組み合わせて複数の制約違反を一括報告する設計に発展させられる。

 

**確認事項**: 罠は依存関係のドキュメント化を怠り、制約(startとendの同時指定必須)がコードコメントだけに存在し実行時に検証されないこと。境界値として、`createRange({ start: 5, end: 5 })`(start===end)が有効な区間として許容されるか、エラーにするかを明示する。

 

---

 

### KNOW-F-0039 デフォルト値と副作用の分離

 

**構造の型**:

```js

// 悪い例: デフォルト値の評価のたびにnew Date()が実行され、呼び出しごとに値が変わる

function logEvent(message, timestamp = new Date()) { /* ... */ }

 

// 良い例: 副作用を伴う既定値が必要なら関数内部で明示的に扱う

function logEvent(message, timestamp) {

const effectiveTimestamp = timestamp ?? new Date();

return { message, timestamp: effectiveTimestamp };

}

```

 

**使いどころ**: デフォルト値に「呼び出すたびに結果が変わる式」(`new Date()`、`Math.random()`、`[]`や`{}`のような新規オブジェクト生成)を使う場面での注意点。JavaScriptのデフォルト引数は呼び出しごとに再評価されるため一見問題ないが、意図を明示するために本体側で`??`を使う形の方が可読性・テスト容易性(KNOW-F-0124)が高い。

 

**組合せ例**: KNOW-F-0028(デフォルト引数の設計)の応用編であり、KNOW-F-0071(冪等性)とも関係する——同じ引数で呼んでも`timestamp`が省略されるたびに異なる結果になる関数は、テストでの再現性が下がる。

 

**確認事項**: 罠は「デフォルト引数は1度だけ評価されてキャッシュされる」という誤解(実際には呼び出しごとに再評価される、これは他言語のデフォルト引数と異なる場合があるため要注意)。境界値として、`logEvent("start")`を短時間に2回連続で呼んだ場合、2つの異なる`timestamp`が生成されることをテストで確認する。

 

---

 

### KNOW-F-0040 ビルダーパターンとの関係(引数が多すぎる場合の代替)

 

**構造の型**:

```js

class QueryBuilder {

#parts = { select: "*", from: null, where: [] };

select(cols) { this.#parts.select = cols; return this; }

from(table) { this.#parts.from = table; return this; }

where(cond) { this.#parts.where.push(cond); return this; }

build() {

if (!this.#parts.from) throw new Error("from is required");

const whereClause = this.#parts.where.length

? ` WHERE ${this.#parts.where.join(" AND ")}` : "";

return `SELECT ${this.#parts.select} FROM ${this.#parts.from}${whereClause}`;

}

}

const sql = new QueryBuilder().select("id, name").from("users").where("age > 18").build();

```

 

**使いどころ**: オプションオブジェクト(KNOW-F-0029)にしてもなお項目数が多く、かつ項目間に組み立て順序や条件付き追加(where句を0個以上追加する等)がある場合。メソッドチェーンによって「1行に詰め込みすぎた引数リスト」を、読みやすい段階的な組み立てに分解できる。

 

**組合せ例**: KNOW-F-0005(create/build/make)の`build`側の本格的な実装であり、KNOW-F-0067(戻り値のチェイン可能性)の典型例でもある。

 

**確認事項**: 罠は`build()`を呼び忘れて未完成のビルダーオブジェクトをそのまま使ってしまうこと(型検査がない場合に気づきにくい)。境界値として、`from`を指定せずに`build()`した場合に例外が投げられること、`where`を1度も呼ばなかった場合にWHERE句なしのSQLが生成されることを確認する。

 

---

 

### KNOW-F-0041 引数の順序に依存しないAPI設計(名前付き引数化)

 

**構造の型**:

```js

// 位置引数(順序を覚える必要がある)

function movePlayer(x, y, speed) { /* ... */ }

// 名前付き引数化(順序を意識しなくてよい)

function movePlayer({ x, y, speed = 1 }) { /* ... */ }

movePlayer({ speed: 2, y: 10, x: 5 }); // 順序を入れ替えても同じ結果

```

 

**使いどころ**: 引数の意味が似通っていて順序を取り違えやすい関数(x, yのような座標、start, endのような区間)。位置引数のままだと`movePlayer(10, 5, 2)`のように書いたときx,yの取り違えに気づけないが、名前付き引数化すればキー名がその場でチェックになる。

 

**組合せ例**: KNOW-F-0029(オプションオブジェクトパターン)の実装手段そのものであり、KNOW-F-0038(引数の依存関係)とあわせて使うことが多い。

 

**確認事項**: 罠は名前付き引数化してもキー名のタイプミス(`{ xx: 5 }`)が実行時エラーにならず静かに`undefined`として扱われること(KNOW-F-0029の確認事項と同型の罠)。境界値として、同じ意味を持つ引数(x, y)が2つ以上ある関数では、位置引数のままにすると誤りが実際に混入しやすいことをテストケースで示す(`movePlayer(5, 10, ...)`と`movePlayer(10, 5, ...)`を取り違えた場合の挙動の違いを比較する)。

 

---

 

### KNOW-F-0042 引数の型を単純化する(プリミティブ執着 vs 値オブジェクト)

 

**構造の型**:

```js

// プリミティブ執着(primitive obsession): 通貨と数量を裸の数値で扱う

function addMoney(amountA, currencyA, amountB, currencyB) { /* ... */ }

 

// 値オブジェクト化: 通貨込みの1つの値として扱う

function addMoney(moneyA, moneyB) {

if (moneyA.currency !== moneyB.currency) throw new Error("currency mismatch");

return { amount: moneyA.amount + moneyB.amount, currency: moneyA.currency };

}

```

 

**使いどころ**: 単位・種別・制約が常に付随する値(お金と通貨、座標と座標系、メールアドレスと検証済みフラグ)を引数として繰り返し扱う場面。裸のプリミティブ値(数値・文字列)のまま関数間を受け渡す「プリミティブ執着」は、単位の取り違え(KNOW-F-0046)を型で防げないという弱点を持つ。

 

**組合せ例**: KNOW-F-0012(単位を名前に含める)が命名による軽量な対策であるのに対し、本項はより強力な「型による強制」の対策であり、両者は防御の層を分ける関係にある。

 

**確認事項**: 罠は値オブジェクト化をやりすぎて、単純な計算にまで過剰な抽象化を持ち込み、かえって処理が追いにくくなること。境界値として、`addMoney`に異なる通貨を渡した場合に確実に例外が発生し、暗黙の換算(意図しない計算)が行われないことを確認する。

 

---

 

### KNOW-F-0043 配列引数とスプレッド構文の使い分け

 

**構造の型**:

```js

function sum(numbers) { // 配列を1つの引数として受け取る

return numbers.reduce((a, b) => a + b, 0);

}

const nums = [1, 2, 3, 4];

sum(nums); // 配列をそのまま渡す

sum([...nums, 5]); // スプレッド構文で新しい配列を作って渡す(元のnumsは不変)

```

 

**使いどころ**: すでに配列を持っているデータをrest引数の関数(KNOW-F-0030)に渡すとき、あるいは既存配列に要素を追加した「新しい配列」を作りたいとき。スプレッド構文`...`は「配列を展開する」動作であり、rest引数の「複数の値を配列にまとめる」動作とは逆方向であることを区別する。

 

**組合せ例**: KNOW-F-0030(可変長引数)と表裏の関係にある項目であり、KNOW-F-0034(引数の不変性)の実現手段としてもスプレッド構文(元配列を書き換えず新配列を作る)が頻繁に使われる。

 

**確認事項**: 罠はスプレッド構文が「深いコピー」だと誤解すること(実際は浅いコピーであり、ネストした配列・オブジェクトは参照が共有される、KNOW-F-0034の確認事項と同型)。境界値として、`sum([...[], 5])`(空配列へのスプレッド)が正しく`[5]`になることを確認する。

 

---

 

### KNOW-F-0044 引数のデストラクチャリングパターン

 

**構造の型**:

```js

function summarizeOrder({ id, items, customer: { name: customerName } = {} }) {

return `注文${id}: ${customerName ?? "匿名"}様、${items.length}点`;

}

console.assert(

summarizeOrder({ id: 1, items: [1, 2], customer: { name: "Bob" } })

=== "注文1: Bob様、2点"

);

```

 

**使いどころ**: オプションオブジェクト(KNOW-F-0029)からネストした値を取り出す場面。分割代入によって、関数本体で`options.customer.name`のような深いプロパティアクセスを繰り返さずに済み、必要な項目だけを引数リストの時点で明示できる(その関数が何を使うかのドキュメントにもなる)。

 

**組合せ例**: KNOW-F-0029(オプションオブジェクトパターン)の読み取り側の技法であり、KNOW-F-0028(デフォルト引数の設計)と組み合わせてネストしたデフォルト値(`customer: {} = {}`)を安全に扱う。

 

**確認事項**: 罠はネストが深いデストラクチャリングを1行に詰め込みすぎて、逆に何を取り出しているか読みにくくなること。境界値として、`customer`プロパティ自体が渡されなかった場合(`{ id: 1, items: [] }`)に、ネストしたデフォルト値`= {}`によって例外が発生せず`customerName`が`undefined`になることを確認する(これがないと`Cannot destructure property 'name' of undefined`という実行時エラーになる)。

 

---

 

### KNOW-F-0045 引数バリデーションとエラー早期return

 

**構造の型**:

```js

function withdraw(account, amount) {

if (amount <= 0) return { ok: false, error: "amount must be positive" };

if (amount > account.balance) return { ok: false, error: "insufficient funds" };

account.balance -= amount;

return { ok: true, balance: account.balance };

}

```

 

**使いどころ**: 想定内のエラー(業務ルール違反)を例外でなく戻り値として表現したい関数で、KNOW-F-0032(引数バリデーション位置)を早期returnと組み合わせて実装する場面。第四章のガード節(KNOW-F-0076)と第三章のResult型パターン(KNOW-F-0055)を接続する橋渡しの項目である。

 

**組合せ例**: KNOW-F-0101(例外と戻り値の使い分け基準)で述べる「想定内エラーは戻り値で表現する」方針の具体的な実装形がこれにあたる。

 

**確認事項**: 罠は複数のバリデーション条件を1つの巨大なif文にまとめてしまい、どの条件で失敗したのか呼び出し側に伝わらなくなること(本項のように条件ごとに早期returnし、個別のエラーメッセージを持たせるのが望ましい)。境界値として、`amount === 0`(境界の0)・`amount === account.balance`(残高ちょうど)の2つの境界ケースで正しい分岐に入ることを確認する。

 

---

 

### KNOW-F-0046 引数の単位混同を防ぐ設計

 

**構造の型**:

```js

// 悪い例: pxとremが同じ number 型で混在しうる

function setWidth(px) { element.style.width = `${px}px`; }

setWidth(remToPx(2)); // remをpxに変換し忘れると崩れる

 

// 良い例: 単位ごとに専用の生成関数を用意し、直接numberを渡させない

function px(value) { return { unit: "px", value }; }

function rem(value) { return { unit: "rem", value }; }

function setWidth(sizeUnit) {

const px2 = sizeUnit.unit === "rem" ? sizeUnit.value * 16 : sizeUnit.value;

element.style.width = `${px2}px`;

}

```

 

**使いどころ**: 複数の単位系が混在しうる数値(px/rem、秒/ミリ秒、バイト/キロバイト)を扱う関数群。KNOW-F-0012(命名による対策)だけでは呼び出し側の実引数の取り違えまでは防げないため、値オブジェクト(KNOW-F-0042)による型レベルの防御を追加する。

 

**組合せ例**: KNOW-F-0012とKNOW-F-0042の複合適用例であり、単位混同という一つの問題を「命名」「型」の2層で防御する考え方を具体化したものである。

 

**確認事項**: 罠は`px()`と`rem()`のような専用関数を導入したのに、一部の呼び出し箇所で裸の数値がまだ残っていて型検査なしには検出できないこと。境界値として、`setWidth(px(0))`(値0)が例外にならず正しく`"0px"`になることを確認する。

 

---

 

### KNOW-F-0047 引数の副作用渡し(コールバックによる外部状態変更)の危険性

 

**構造の型**:

```js

// 危険な例: コールバックの中で外部の配列を直接書き換える

function processItems(items, onEach) {

items.forEach(onEach);

}

const log = [];

processItems([1, 2, 3], (item) => log.push(item * 2)); // logという外部状態への副作用

 

// より安全な例: 副作用でなく戻り値として結果を集める

function mapItems(items, transform) {

return items.map(transform); // 呼び出し元は戻り値を受け取るだけでよい

}

const doubled = mapItems([1, 2, 3], (item) => item * 2);

```

 

**使いどころ**: コールバック引数を設計するすべての場面での注意点。コールバックの中で外部変数を書き換える設計(副作用渡し)は動作を追跡しづらく、テスト時にモックの状態を毎回確認する必要が生じる。可能な限り、コールバックの戻り値を関数本体が集約して返す設計(`map`のような形)に寄せる。

 

**組合せ例**: KNOW-F-0016(述語関数の命名)で述べた「述語は純粋であるべき」という方針の一般化であり、KNOW-F-0063(戻り値に状態を持たせない)とも同じ思想を共有する。

 

**確認事項**: 罠は副作用渡しのコールバックが複数箇所から呼ばれ、外部状態(`log`配列など)への書き込み順序に依存した挙動になること(並行実行や非同期処理では順序が保証されない場合がある)。境界値として、`onEach`が例外を投げた場合に`forEach`がその場で処理を打ち切り、残りの要素に対してコールバックが呼ばれないことを確認する。

 

---

 

### KNOW-F-0048 引数として関数を渡す設計(高階関数)の基本

 

**構造の型**:

```js

function withLogging(fn) {

return function (...args) {

console.log(`call: ${fn.name}(${args.join(", ")})`);

const result = fn(...args);

console.log(`return: ${result}`);

return result;

};

}

const loggedAdd = withLogging((a, b) => a + b);

loggedAdd(2, 3); // ログを出力しつつ 5 を返す

```

 

**使いどころ**: 既存の関数に「ログを付ける」「リトライさせる」「キャッシュさせる」のような共通の振る舞いを、元の関数を書き換えずに後付けしたい場面。関数を引数として受け取り、新しい関数を返す(高階関数)ことで、横断的な関心事(ロギング等)を個別の関数から分離できる。

 

**組合せ例**: KNOW-F-0015(コールバック引数の命名慣習)は本項の呼び出し規約側、KNOW-F-0066(部分適用/カリー化)は本項をさらに発展させ「引数の一部を固定した新しい関数」を作る技法である。

 

**確認事項**: 罠は`withLogging`でラップした関数の`this`束縛が失われること(アロー関数でラップすると元のメソッドの`this`が意図通りに渡らない場合がある)。境界値として、`fn`が例外を投げた場合に`withLogging`のログ出力(`return:`側)がどう振る舞うか(例外を握りつぶさず伝播させるべき)を明示する。

 

---

 

### KNOW-F-0049 引数のデフォルトnull vs 省略可能の違い

 

**構造の型**:

```js

// パターンA: 引数自体を省略可能にする(呼ばなくてもよい)

function greet(name) { return `こんにちは、${name ?? "ゲスト"}さん`; }

greet(); // "こんにちは、ゲストさん"

 

// パターンB: 引数は必須だが値としてnullを許容する(「未選択」を明示的に渡す)

function setAvatar(userId, imageUrlOrNull) {

return { userId, avatar: imageUrlOrNull }; // 呼び出し側はnullを明示して渡す

}

setAvatar(1, null); // 「アバターなし」を明示的に指定

```

 

**使いどころ**: 「値がない」ことをどう表現するか選ぶ場面。パターンA(省略可能)は「呼び出し側が気にしなくてよい設定」向き、パターンB(明示nullを必須で渡す)は「値がないこと自体が重要な情報であり、呼び出し側に意識させたい」場合向きである。

 

**組合せ例**: KNOW-F-0033(null/undefinedの扱い方針)の具体的な選択肢の一つであり、パターンBはKNOW-F-0038(引数の依存関係)のように呼び出し側の意図を明示させたい場面と相性がよい。

 

**確認事項**: 罠は同じプロジェクト内でパターンAとパターンBが無秩序に混在し、ある関数は省略可、別の関数は明示null必須、という不統一が呼び出し側の混乱を招くこと。境界値として、パターンBの関数に誤って`undefined`(省略)を渡した場合の挙動(nullと同じ扱いにするか、エラーにするか)を明示する。

 

---

 

### KNOW-F-0050 引数過多のシグナル(責務過多のリファクタリング契機)

 

**構造の型**:

```js

// 引数が7個: 責務過多のサイン

function createInvoice(customerId, items, tax, discount, dueDate, currency, notes) { /* ... */ }

 

// リファクタリング後: 関連する引数をオブジェクトへ、責務を分割

function createInvoice(customerId, items, billingOptions) {

const { tax, discount, dueDate, currency, notes } = billingOptions;

/* ... */

}

```

 

**使いどころ**: 関数の引数リストが増え続けているときの警戒信号として、本冊で述べた全ての引数設計技法(KNOW-F-0026〜0049)を振り返るきっかけにする項目。引数が多いこと自体は問題ではなく、「関連する引数をグループ化できるか」「関数が複数の責務を抱えていないか」を点検する契機として使う。

 

**組合せ例**: KNOW-F-0027(3個ルール)・KNOW-F-0029(オプションオブジェクト)・KNOW-F-0040(ビルダーパターン)は本項が示す問題への三段階の対処法(グループ化→オブジェクト化→段階的組み立て)であり、第一章KNOW-F-0001(動詞+目的語の名前が長くなりすぎる問題)とも連動する。

 

**確認事項**: 罠は引数が多い関数を「とりあえずオブジェクトにまとめる」だけで満足し、本質的な責務過多(1つの関数が請求書生成・税計算・通貨変換まで担っている等)を見過ごすこと。境界値として、オブジェクト化した後も関数内部の分岐(if/switch)が10行を超えるようであれば、KNOW-F-0092(関数分割シグナル)に従い複数の小さな関数への分割を検討する。

 

---

 

## 第三章 戻り値設計の技(KNOW-F-0051〜0075)

 

戻り値は関数から呼び出し側への「出力の契約」である。本章では、戻り値の型を一定に保つ・複数の値を返す・nullを避ける・冪等性を保つといった、呼び出し側が安心して結果を使えるようにするための型を25種扱う。

 

### KNOW-F-0051 単一責務の戻り値(一つの意味だけを返す)

 

**構造の型**:

```js

// 悪い例: 戻り値が「合計金額」なのか「エラーメッセージ」なのか型で変わる

function calculateTotal(items) {

if (items.length === 0) return "カートが空です"; // 文字列

return items.reduce((s, i) => s + i.price, 0); // 数値

}

// 良い例: 常に同じ意味・同じ型を返す

function calculateTotal(items) {

return items.reduce((s, i) => s + i.price, 0); // 空なら0、常にnumber

}

```

 

**使いどころ**: すべての関数の戻り値を設計する出発点となる原則。1つの関数は1つの意味を持つ値だけを返すべきであり、条件によって「数値」と「エラーを表す文字列」のように意味の異なる値を返し分けるべきではない。

 

**組合せ例**: KNOW-F-0057(戻り値の型を常に一定にする)は本項をより厳密に「型」のレベルで規定したものであり、KNOW-F-0055(Result型パターン)はエラー表現を戻り値に含めたい場合の正しい合流点を示す。

 

**確認事項**: 罠は「特別な場合だけ違う型を返す」近道をとってしまうこと(空配列のときだけnullを返す等、KNOW-F-0064と関連)。境界値として、`calculateTotal([])`(空配列)が例外にも特殊値にもならず、0という「意味のある通常値」を返すことを確認する。

 

---

 

### KNOW-F-0052 null回避のためのOptional的パターン

 

**構造の型**:

```js

// undefinedに統一し、nullと二重管理しない

function findUserById(users, id) {

return users.find(u => u.id === id); // 見つからなければundefined(Array.find標準の挙動)

}

// 呼び出し側は ?? や ?. で安全に扱う

const name = findUserById(users, 99)?.name ?? "不明なユーザー";

```

 

**使いどころ**: 「値が存在しないかもしれない」ことを表現するすべての戻り値。センチネル値(-1やゼロ文字列)で「なし」を表す設計は誤用されやすいため避け、`undefined`(またはプロジェクトで統一した「値なし」の型)とオプショナルチェイニング(`?.`)・Null合体演算子(`??`)の組で扱う。

 

**組合せ例**: KNOW-F-0033(null/undefinedの扱い方針)の出口側の対応項目であり、KNOW-F-0007(find/search/filterの使い分け)で述べた`find`系関数の戻り値はまさに本項のパターンに従う。

 

**確認事項**: 罠は「見つからない」を`-1`や空文字列のようなセンチネル値で表現し、正常な値(たまたま-1が有効なIDである等)と区別がつかなくなること。境界値として、`findUserById([], 1)`(空配列に対する検索)が例外を投げずに`undefined`を返すことを確認する。

 

---

 

### KNOW-F-0053 タプル返し(配列で複数値を返す)

 

**構造の型**:

```js

function divideWithRemainder(a, b) {

return [Math.floor(a / b), a % b]; // [商, 余り] の順序が固定されたタプル

}

const [quotient, remainder] = divideWithRemainder(17, 5);

console.assert(quotient === 3 && remainder === 2);

```

 

**使いどころ**: 2〜3個程度の、意味的に強く結びついた値をまとめて返す場面(商と余り、最小値と最大値など)。分割代入の変数名を呼び出し側で自由に決められる利点がある一方、順序を覚えておく必要がある。

 

**組合せ例**: KNOW-F-0054(オブジェクト返し)とは対になる選択肢であり、値の個数が少なく順序に自然な意味がある(商が先、余りが後)場合はタプル、値の個数が多い・順序に意味がない場合はオブジェクトを選ぶという使い分けの基準になる。

 

**確認事項**: 罠は値の個数が増えるにつれて`const [a, b, c, d, e] = fn()`のように順序の取り違えリスクが増すこと(3個を超えたらKNOW-F-0054への切り替えを検討する)。境界値として、`divideWithRemainder(5, 5)`(商1、余り0)や`divideWithRemainder(0, 5)`(商0、余り0)の境界ケースを確認する。

 

---

 

### KNOW-F-0054 オブジェクト返し(名前付きプロパティで複数値を返す)

 

**構造の型**:

```js

function analyzeText(text) {

return {

charCount: text.length,

wordCount: text.trim().split(/\s+/).filter(Boolean).length,

lineCount: text.split("\n").length,

};

}

const { wordCount } = analyzeText("hello world"); // 必要な項目だけ取り出せる

```

 

**使いどころ**: 4個以上の値を返す、または各値の意味を呼び出し側でも明示したい場面。プロパティ名によって順序を覚える必要がなく、呼び出し側は分割代入で必要な項目だけを取り出せる。

 

**組合せ例**: KNOW-F-0053(タプル返し)と対をなす選択肢。KNOW-F-0055(Result型パターン)はオブジェクト返しの中でも特に「成功/失敗」を表す形に特化した専門パターンである。

 

**確認事項**: 罠はオブジェクトのプロパティ名を将来変更したときに、呼び出し側の分割代入すべてを追跡してリネームする必要が生じること(タプルより変更コストが低い場合と高い場合がある点を認識する)。境界値として、`analyzeText("")`(空文字列)が`charCount: 0, wordCount: 0, lineCount: 1`(splitは空文字列でも1要素の配列を返す)になることを検算する。

 

---

 

### KNOW-F-0055 Result型パターン({ok, value, error})

 

**構造の型**:

```js

function parseJsonSafe(text) {

try {

return { ok: true, value: JSON.parse(text) };

} catch (err) {

return { ok: false, error: err.message };

}

}

const result = parseJsonSafe("{ invalid");

if (!result.ok) {

console.error("解析失敗:", result.error);

} else {

console.log(result.value);

}

```

 

**使いどころ**: 失敗する可能性がある処理を、例外を投げずに戻り値だけで表現したい場面。呼び出し側に`if (result.ok)`のチェックを強制する形にすることで、エラーハンドリングの書き忘れ(catchのつけ忘れ)を型・構造レベルで気づきやすくする。

 

**組合せ例**: KNOW-F-0101(例外と戻り値の使い分け基準)で「想定内のエラーは戻り値」と判断した場合の標準実装形であり、KNOW-F-0114(Result型とtry-catchの併用戦略)でtry-catchとの共存方法を扱う。

 

**確認事項**: 罠は`result.ok`のチェックを怠り、`result.error`にアクセスしても実行時エラーにならず単に`undefined`が返ることに気づかず先に進んでしまうこと(型検査がない場合の弱点)。境界値として、成功時は`value`のみ、失敗時は`error`のみが存在し、両方が同時に存在する(またはどちらも存在しない)状態がないことを確認する。

 

---

 

### KNOW-F-0056 例外を投げるか戻り値で表現するかの判断基準

 

**構造の型**:

```js

// 判断基準の例: 「呼び出し側が握りつぶさず必ず処理すべき異常」は例外、

// 「起こりうる通常の分岐」は戻り値で表現する

function getConfigValue(key) {

if (!(key in config)) {

throw new Error(`config key not found: ${key}`); // プログラマの記述ミス相当 → 例外

}

return config[key];

}

function tryGetConfigValue(key) {

return key in config ? { found: true, value: config[key] } : { found: false }; // 想定内 → 戻り値

}

```

 

**使いどころ**: 特定の関数に限らず、関数の設計初期段階すべて。KNOW-F-0101で詳述する判断基準の要約をここで先取りし、第二・第三章の橋渡しとして提示する: 「呼び出し元が対処法を持たない・プログラムのバグに近い異常」は例外、「呼び出し元がその場で分岐して処理できる想定内の結果」は戻り値、という原則を用いる。

 

**組合せ例**: KNOW-F-0055(Result型)とKNOW-F-0102(カスタムエラークラス)は、それぞれこの判断基準の「戻り値側」「例外側」の具体的な実装形にあたる。

 

**確認事項**: 罠は同じ種類の失敗(設定キーが見つからない)に対して、ある箇所では例外、別の箇所では戻り値、と一貫しない実装が混在すること。境界値として、`getConfigValue`と`tryGetConfigValue`という「同じ目的で2つの入口を用意する」設計自体が、呼び出し側にとってどちらを使うべきかの判断コストを生むため、プロジェクトの規約でどちらを既定にするか明示しておく。

 

---

 

### KNOW-F-0057 戻り値の型を常に一定にする

 

**構造の型**:

```js

// 悪い例: 条件によって配列だったりnullだったりする

function getTags(post) {

return post.tags && post.tags.length > 0 ? post.tags : null;

}

// 良い例: 常に配列(空配列を含む)を返す

function getTags(post) {

return post.tags ?? [];

}

```

 

**使いどころ**: すべての関数戻り値の設計で確認すべき原則。呼び出し側が`result.map(...)`のように戻り値の型を前提としたコードを書けるようにするため、「配列のはずが条件によってnullになる」といった型のブレをなくす。

 

**組合せ例**: KNOW-F-0051(単一責務の戻り値)の型版であり、KNOW-F-0064(空配列/空オブジェクト返し)は本項を実現する具体的な手段の一つである。

 

**確認事項**: 罠は型のブレが原因で発生する`Cannot read properties of null`のようなエラーが、呼び出し側の遠く離れた箇所で発生し原因の特定に時間がかかること。境界値として、`getTags({})`(tagsプロパティ自体が存在しない場合)でも例外にならず空配列が返ることを確認する。

 

---

 

### KNOW-F-0058 早期returnとガード節の関係

 

**構造の型**:

```js

function getDiscountRate(user) {

if (!user.isMember) return 0; // ガード節: 非会員は割引なし

if (user.yearsActive < 1) return 0.05; // ガード節: 新規会員

return 0.1; // 本体: 通常会員

}

```

 

**使いどころ**: 戻り値を決める条件分岐が複数ある関数。第四章で詳述するガード節(KNOW-F-0076)の技法を、戻り値設計の視点から見た項目であり、各早期returnが「その条件における戻り値の意味」を1行で表現する。

 

**組合せ例**: 第四章KNOW-F-0076・KNOW-F-0077(ネストを浅くする)と対応する戻り値側の解説であり、KNOW-F-0072(戻り値の型をユニオンでなく統一する設計判断)とあわせて読むと、早期returnの各分岐で型が一貫しているかを点検できる。

 

**確認事項**: 罠は早期returnの各分岐で戻り値の型が異なってしまうこと(ある分岐は数値、別の分岐はオブジェクト、など)。境界値として、`getDiscountRate`にすべての条件を満たさないケース(存在しないなら)が生じないよう、最後のreturnが「デフォルトの結果」として機能することを確認する。

 

---

 

### KNOW-F-0059 voidの使いどころ(副作用のみの関数)

 

**構造の型**:

```js

function logAudit(action, userId) {

auditLog.push({ action, userId, at: Date.now() }); // 副作用のみ

// 戻り値なし(呼び出し側は戻り値を使わないことが名前からも分かる)

}

logAudit("login", 42); // 戻り値を受け取らない呼び出し方が自然

```

 

**使いどころ**: 意味のある戻り値を持たず、副作用(ログ記録・状態更新・DOM操作)だけを目的とする関数。戻り値を返さない(`undefined`のまま)ことで、「この関数の結果を使ってはいけない」という契約を型として明示する。

 

**組合せ例**: KNOW-F-0004(get/set対の命名規約)の`set`系はしばしばvoidを返し、KNOW-F-0074(コマンド/クエリ分離)の「コマンド」側の戻り値設計として本項を位置づけられる。

 

**確認事項**: 罠はvoid関数の戻り値を呼び出し側がうっかり使ってしまい、`undefined`に対する操作でエラーになること(命名で「これは戻り値を持たない」と伝えるKNOW-F-0025が対策になる)。境界値として、`logAudit`をチェーンして`logAudit(...).then(...)`のように誤用しないよう、非同期でないことも名前(Asyncの不在)で示す。

 

---

 

### KNOW-F-0060 戻り値のイミュータビリティ

 

**構造の型**:

```js

function getDefaultSettings() {

return Object.freeze({ theme: "light", fontSize: 14 }); // 呼び出し側が書き換えられない

}

const settings = getDefaultSettings();

// settings.theme = "dark"; // strictモードでは例外、非strictでは無視される

```

 

**使いどころ**: 複数の呼び出し元で共有される「基準値」「設定オブジェクト」「定数的なデータ」を返す関数。呼び出し側が誤って戻り値を書き換えてしまうと、その変更が他の呼び出し元にも影響する可能性がある共有状態のバグを防ぐ。

 

**組合せ例**: KNOW-F-0034(引数の不変性)の出口側にあたる対の項目であり、KNOW-F-0070(戻り値のキャッシュと副作用の分離)でキャッシュされた戻り値を安全に共有する際にも本項の考え方が必要になる。

 

**確認事項**: 罠は`Object.freeze`が浅い凍結であり、ネストしたオブジェクト(`settings.nested.value`)までは凍結されないこと。境界値として、strictモード(ESモジュールは既定でstrict)では凍結されたオブジェクトへの書き込みが例外を投げ、非strictでは黙って無視される違いを確認する。

 

---

 

### KNOW-F-0061 ジェネレータ/イテレータによる遅延戻り値

 

**構造の型**:

```js

function* range(start, end) {

for (let i = start; i < end; i++) yield i;

}

const it = range(0, 3);

console.assert(it.next().value === 0);

console.assert(it.next().value === 1);

// 全要素を配列化せず、必要な分だけ順に取り出せる

```

 

**使いどころ**: 大量の要素、あるいは理論上無限に続く系列を扱う関数で、すべてを一度に配列化するとメモリを大量消費する場面。ジェネレータ関数(`function*`)は呼ばれるたびに次の値を1つずつ計算する「遅延評価」の戻り値を提供する。

 

**組合せ例**: KNOW-F-0088(ループの終了条件の明示化)と組み合わせて無限系列に安全な終了条件を与えることが多く、BOOK-0184の理-KAN-022(反復適用関数)の実装側対応にあたる。

 

**確認事項**: 罠はジェネレータを`for...of`でなく誤って直接配列のように扱ってしまう(`range(0,3).length`のようなアクセスはできない)こと。境界値として、`range(3, 3)`(startとendが等しい)が1回も`yield`せず即座に完了することを確認する。

 

---

 

### KNOW-F-0062 Promise/async関数の戻り値設計

 

**構造の型**:

```js

async function loadUserProfile(id) {

const user = await fetchUser(id); // 常にPromiseを返す(async関数の性質)

const posts = await fetchPosts(id);

return { user, posts }; // 戻り値はPromise<{user, posts}>

}

loadUserProfile(1).then(({ user, posts }) => console.log(user, posts));

```

 

**使いどころ**: 非同期処理を含む関数すべて。`async function`は常にPromiseを返すという言語仕様を踏まえ、戻り値の「中身」の型(`{ user, posts }`)を第三章の他の原則(単一責務・型の一貫性)に従って設計する。

 

**組合せ例**: KNOW-F-0017(非同期関数の命名規約)・KNOW-F-0115(非同期エラーのハンドリング)と三点セットで扱う項目であり、KNOW-F-0055(Result型)を非同期関数の戻り値に組み合わせる(`Promise<Result>`)設計もよく使われる。

 

**確認事項**: 罠はasync関数内で例外を投げた場合、それが同期的なthrowではなくPromiseのreject(拒否)として伝播することを見落とし、呼び出し側で`try-catch`でなく`.catch`が必要なことに気づかないケース。境界値として、`loadUserProfile`が存在しないidを渡された場合の拒否理由(reject reason)が具体的なエラーメッセージを持つことを確認する。

 

---

 

### KNOW-F-0063 戻り値に状態を持たせない(参照透過性)

 

**構造の型**:

```js

// 悪い例: 呼び出すたびに内部カウンタに依存し結果が変わる(参照透過でない)

let callCount = 0;

function getGreeting(name) {

callCount++;

return callCount === 1 ? `はじめまして、${name}さん` : `また来たね、${name}さん`;

}

// 良い例: 外部状態は引数として明示的に渡す

function getGreeting(name, isFirstVisit) {

return isFirstVisit ? `はじめまして、${name}さん` : `また来たね、${name}さん`;

}

```

 

**使いどころ**: 同じ入力に対して常に同じ出力を期待する関数(純関数として扱いたい関数)すべて。戻り値が引数以外の外部可変状態(モジュールスコープの変数、グローバル変数)に依存すると、テストのたびに結果が変わり再現性が失われる。

 

**組合せ例**: KNOW-F-0071(冪等性)と密接に関連し、BOOK-0184で扱った「参照透過性」の概念のソフトウェア実装側の具体化にあたる。KNOW-F-0047(引数の副作用渡しの危険性)とも同じ「外部状態への依存を避ける」思想を共有する。

 

**確認事項**: 罠は関数を「純粋に見せかけて」実は内部でモジュールスコープの変数を読み書きしていること(引数だけを見ても副作用の有無が分からない)。境界値として、`getGreeting("Alice", true)`を何度呼んでも同じ結果になることをテストで確認する(外部状態版は不可能だが、修正後版は可能になる)。

 

---

 

### KNOW-F-0064 デフォルト値としての空配列/空オブジェクト返し

 

**構造の型**:

```js

function getCartItems(cart) {

return cart?.items ?? []; // nullやundefinedの代わりに空配列

}

// 呼び出し側は常に配列メソッドをそのまま使える(nullチェック不要)

const total = getCartItems(cart).reduce((s, i) => s + i.price, 0);

```

 

**使いどころ**: 「該当データがない」ケースを表現する戻り値の既定の選択肢として、null/undefinedでなく「空のコレクション」を返す設計(Null Objectパターンに近い考え方)。呼び出し側で`if (result) { result.forEach(...) }`のような分岐を省略できる。

 

**組合せ例**: KNOW-F-0057(戻り値の型を常に一定にする)を実現する最も代表的な手段であり、KNOW-F-0003(複数形の命名)で述べた複数形の関数はほぼ本項の対象になる。

 

**確認事項**: 罠は「空配列」と「取得に失敗した(該当データそのものが存在しないエラー)」の区別が必要な場面で本項を機械的に適用し、エラーと正常な0件を区別できなくしてしまうこと(その場合はKNOW-F-0055のResult型を使うべき)。境界値として、`getCartItems(undefined)`(cart自体が渡されない)・`getCartItems({})`(itemsを持たないcart)の両方で空配列が返ることを確認する。

 

---

 

### KNOW-F-0065 戻り値のドキュメント化(JSDocによる契約明示)

 

**構造の型**:

```js

/**

* 商品リストの合計金額を計算する。

* @param {{price: number, quantity: number}[]} items - 商品リスト(空配列可)

* @returns {number} 合計金額(円)。itemsが空なら0を返す。

*/

function calculateTotal(items) {

return items.reduce((s, i) => s + i.price * i.quantity, 0);

}

```

 

**使いどころ**: 公開APIやチーム内で共有される関数すべて。TypeScriptの型注釈がない環境でも、JSDocのコメントによって引数・戻り値の型と意味をエディタの補完機能に反映させ、実質的な契約書として機能させられる。

 

**組合せ例**: 本冊全体で示した「型を一定にする」「単位を明示する」といった技法(KNOW-F-0012・0057)の記録先として使われ、脊椎対BOOK-0358fで詳述する「関数契約」の考え方を、実際のコード上で実現する手段の一つである。

 

**確認事項**: 罠はコード本体を変更したときにJSDocコメントの更新を忘れ、実装とドキュメントが乖離すること(古いコメントは間違った情報より始末が悪い場合がある)。境界値として、`@returns`に書いた「itemsが空なら0を返す」という記述が実際のコードと一致するかを、コードレビュー時に必ず突き合わせる運用にする。

 

---

 

### KNOW-F-0066 部分適用/カリー化された関数の戻り値

 

**構造の型**:

```js

function multiplyBy(factor) {

return function (value) { // 「関数を返す関数」、戻り値自体が関数

return value * factor;

};

}

const double = multiplyBy(2);

const triple = multiplyBy(3);

console.assert(double(5) === 10 && triple(5) === 15);

```

 

**使いどころ**: 設定値(factor)を先に固定し、残りの引数だけを後から渡す専用関数を作りたい場面。`Array.prototype.map`に渡すコールバックを動的に生成する(`items.map(multiplyBy(taxRate))`)ような使い方でも有効。

 

**組合せ例**: KNOW-F-0019(ファクトリ関数の命名)と同じ発想(あらかじめ設定を固定した専用の処理を作る)であり、KNOW-F-0048(高階関数の基本)を「引数を返す」のでなく「関数を返す」方向に発展させたものである。

 

**確認事項**: 罠はカリー化された関数を多用しすぎて、`multiplyBy(2)(3)(4)`のような呼び出しがどの段階で何を固定しているのか読みにくくなること。境界値として、`multiplyBy(0)`(factor=0)が例外にならず、常に0を返す関数を正しく生成することを確認する。

 

---

 

### KNOW-F-0067 戻り値のチェイン可能性(メソッドチェーン設計)

 

**構造の型**:

```js

class StringFormatter {

#value;

constructor(value) { this.#value = value; }

trim() { this.#value = this.#value.trim(); return this; } // thisを返す

toUpperCase() { this.#value = this.#value.toUpperCase(); return this; }

toString() { return this.#value; }

}

const result = new StringFormatter(" hello ").trim().toUpperCase().toString();

console.assert(result === "HELLO");

```

 

**使いどころ**: 同じ対象に対して複数の変換・操作を連続して適用したい場面。各メソッドが`this`(または新しいインスタンス)を返すことで、呼び出しを`.`でつなげられ、中間変数を都度作らずに一連の処理を1つの式として読める。

 

**組合せ例**: KNOW-F-0040(ビルダーパターン)はこの戻り値設計を組み立て用途に特化させたものであり、KNOW-F-0021(変換パイプライン)は関数を分けた場合の等価な代替表現にあたる。

 

**確認事項**: 罠はメソッドチェーンの途中で例外が発生した場合、チェーン全体のどこで失敗したかがスタックトレースだけでは追いにくくなること。境界値として、空文字列`""`に対して`.trim().toUpperCase()`を呼んでも例外にならず空文字列のまま処理が完了することを確認する。

 

---

 

### KNOW-F-0068 例外安全性(戻り値経路と例外経路の一貫性)

 

**構造の型**:

```js

function loadSettingsOrDefault(raw) {

try {

const parsed = JSON.parse(raw);

return { ...defaultSettings, ...parsed }; // 正常経路

} catch {

return { ...defaultSettings }; // 例外経路でも同じ型を返す

}

}

```

 

**使いどころ**: try-catchを内部で使う関数の戻り値設計。正常経路(try節)と例外を捕捉した経路(catch節)の両方で、戻り値の型・意味を一致させることで、呼び出し側が「例外が起きたかどうか」を戻り値の形から気にしなくてよくなる。

 

**組合せ例**: KNOW-F-0057(戻り値の型を常に一定にする)を、内部でtry-catchを使う関数に適用した具体例であり、第五章KNOW-F-0109(try-catchのスコープを最小化する)とあわせて、捕捉範囲と戻り値設計の両面から堅牢性を高める。

 

**確認事項**: 罠はcatch節で例外の内容を握りつぶし(KNOW-F-0110)、デバッグ時に何が起きたか分からなくなること(本項ではデフォルト値を返すこと自体は正しいが、ログだけは残すべき)。境界値として、`loadSettingsOrDefault("")`(空文字列、JSON.parseが例外を投げる)がデフォルト設定を返すことを確認する。

 

---

 

### KNOW-F-0069 戻り値としてのエラーコード vs 例外オブジェクト

 

**構造の型**:

```js

// エラーコード方式(C言語的、レガシー互換や低レベルAPIで見られる)

const ERR_NOT_FOUND = 404;

const ERR_NONE = 0;

function findRecordCode(id) {

const record = db.get(id);

return record ? { code: ERR_NONE, record } : { code: ERR_NOT_FOUND, record: null };

}

// 例外オブジェクト方式(JS標準に馴染む)

function findRecordOrThrow(id) {

const record = db.get(id);

if (!record) throw new Error(`record not found: ${id}`);

return record;

}

```

 

**使いどころ**: 外部システム(C言語のライブラリやハードウェア寄りのAPI)との連携を意識する場面ではエラーコード方式が親和性を持つことがあるが、通常のJavaScript/TypeScriptプロジェクトでは例外オブジェクト、またはKNOW-F-0055のResult型に統一する方が言語の慣用に沿う。

 

**組合せ例**: KNOW-F-0102(カスタムエラークラスの設計)・KNOW-F-0103(エラーコードの体系設計)は、この2方式を「例外オブジェクトにエラーコードを持たせる」形で統合した折衷案を示す。

 

**確認事項**: 罠はエラーコードの数値(404など)がHTTPステータスコードと紛らわしく、意味を取り違えること。境界値として、コード0が「正常」を意味するのか「未定義」を意味するのか、プロジェクトの規約として明文化する。

 

---

 

### KNOW-F-0070 戻り値のキャッシュと副作用の分離(メモ化)

 

**構造の型**:

```js

function memoize(fn) {

const cache = new Map();

return function (arg) {

if (cache.has(arg)) return cache.get(arg); // キャッシュ済みならそのまま返す

const result = fn(arg);

cache.set(arg, result);

return result;

};

}

const slowSquare = (n) => { for (let i = 0; i < 1e6; i++); return n * n; };

const fastSquare = memoize(slowSquare);

```

 

**使いどころ**: 同じ引数に対して常に同じ結果を返す(参照透過な、KNOW-F-0063)関数で、かつ計算コストが高い場合。メモ化はキャッシュという「副作用」を関数の外側(ラッパー)に閉じ込め、元の関数自体は純粋なまま保つ設計を取る。

 

**組合せ例**: KNOW-F-0048(高階関数の基本)の応用形であり、KNOW-F-0071(冪等性)が前提条件になる——冪等でない関数(呼ぶたびに結果が変わる関数)にメモ化を適用すると誤った結果をキャッシュしてしまう。

 

**確認事項**: 罠はメモ化のキャッシュがメモリを圧迫し続けること(上限や有効期限がないキャッシュは長時間稼働するプロセスでメモリリークの原因になる)。境界値として、`fastSquare(0)`(0を引数にした場合)がキャッシュのキーとして正しく扱われ、`cache.has(0)`が`false`との混同(0とfalseの型の違い)を起こさないことを確認する(Mapのキー比較はSameValueZeroであり、この点は安全である)。

 

---

 

### KNOW-F-0071 冪等性(同じ入力で同じ戻り値)

 

**構造の型**:

```js

// 冪等な関数: 何度呼んでも同じ入力なら同じ結果

function normalizeEmail(email) {

return email.trim().toLowerCase();

}

console.assert(normalizeEmail(normalizeEmail(" Alice@Example.com ")) === normalizeEmail(" Alice@Example.com "));

```

 

**使いどころ**: リトライされる可能性がある処理(ネットワーク通信の再送、ジョブの再実行)の内部で使う関数、あるいはキャッシュ(KNOW-F-0070)の対象にしたい関数。「同じ入力なら同じ出力」という性質は、テストの再現性と処理の安全な再実行性の両方を支える。

 

**組合せ例**: KNOW-F-0063(参照透過性)とほぼ同義の性質であり、BOOK-0184の検算行の考え方(同じ入力からは常に同じ結果が出ることを確認する)そのものが冪等性の検証手順にあたる。

 

**確認事項**: 罠は「冪等」と「副作用がない」を混同すること——`normalizeEmail`を2回連続で適用しても結果が変わらない(idempotent)のは真だが、DBへの書き込みを伴う関数でも「同じ状態に収束する」という意味で冪等になりうる(例: `setStatus(id, "done")`は何度呼んでも最終状態は同じ)。境界値として、`normalizeEmail("")`(空文字列)を2回適用しても`""`のまま変わらないことを確認する。

 

---

 

### KNOW-F-0072 戻り値の型をユニオンでなく統一する設計判断

 

**構造の型**:

```js

// 悪い例: 戻り値が number | string | null の三択(呼び出し側の分岐が複雑化)

function getScore(player) {

if (!player) return null;

if (player.disqualified) return "失格";

return player.score;

}

// 良い例: 型を統一し、状態は別プロパティで表現する

function getScoreInfo(player) {

if (!player) return { status: "unknown", score: 0 };

if (player.disqualified) return { status: "disqualified", score: 0 };

return { status: "ok", score: player.score };

}

```

 

**使いどころ**: 複数の「特殊な場合」を戻り値の型そのもので表現しようとしている関数。型がバラバラなユニオン(numberだったりstringだったりnullだったり)は、呼び出し側で`typeof`による分岐が必要になり、KNOW-F-0035(オーバーロード的設計)と同じ問題を戻り値側で起こす。

 

**組合せ例**: KNOW-F-0054(オブジェクト返し)・KNOW-F-0057(型を常に一定にする)の複合適用例であり、BOOK-0184理-KAN-028(三値分岐関数)の実装対応にあたる——数値やnullの三択でなく、専用の列挙的な値(status文字列)へ寄せる発想が共通している。

 

**確認事項**: 罠は`status`のような判別用プロパティの取りうる値(”unknown”/“disqualified”/“ok”)がコード中に文字列リテラルとして散在し、タイプミスに気づけないこと(定数化やTypeScriptのUnion型リテラルでの防御を検討する)。境界値として、`getScoreInfo(null)`と`getScoreInfo(undefined)`の両方が同じ`{status: "unknown", score: 0}`を返すことを確認する。

 

---

 

### KNOW-F-0073 コールバックの戻り値活用(filter/mapの述語戻り値boolean)

 

**構造の型**:

```js

const numbers = [1, -2, 3, -4, 5];

const positives = numbers.filter((n) => n > 0); // 述語の戻り値(boolean)で残す/除外を決定

const doubled = numbers.map((n) => n * 2); // 変換関数の戻り値そのものが新要素になる

const total = numbers.reduce((sum, n) => sum + n, 0); // 蓄積関数の戻り値が次のsumになる

```

 

**使いどころ**: `Array.prototype`の高階メソッド(filter/map/reduce/sort/find等)にコールバックを渡すすべての場面。各メソッドがコールバックの戻り値をどう解釈するか(booleanで残す/除外、変換後の値そのものを使う、次のアキュムレータにする)を正しく理解して設計する。

 

**組合せ例**: KNOW-F-0016(述語関数の命名)・KNOW-F-0025(理-KAN-025累積和との対応、BOOK-0184)と接続し、reduceのコールバックは特に「戻り値が次の呼び出しの引数になる」という再帰的な構造(KNOW-F-0084の再帰関数のベースケース設計とも共通する発想)を持つ点に注意する。

 

**確認事項**: 罠は`reduce`のコールバック内でアキュムレータ(sum)を返し忘れること(戻り値のないアロー関数の省略記法と波括弧付きの記法を混同すると発生しやすい典型的なバグ)。境界値として、`[].reduce((sum, n) => sum + n, 0)`(空配列、初期値ありなので0を返す)と、初期値を省略した`[].reduce((sum, n) => sum + n)`(空配列、初期値なしは例外になる)の違いを確認する。

 

---

 

### KNOW-F-0074 戻り値なし関数のシグネチャ表現(コマンド/クエリ分離)

 

**構造の型**:

```js

// クエリ: 状態を変更せず、値を返す

function getBalance(account) { return account.balance; }

// コマンド: 状態を変更し、値を返さない(コマンド・クエリ分離原則)

function deposit(account, amount) { account.balance += amount; }

// 悪い例: 変更と取得を1つの関数に混ぜる(呼び出し側が意図を読み取りにくい)

function depositAndGetBalance(account, amount) {

account.balance += amount;

return account.balance;

}

```

 

**使いどころ**: 関数が「値を尋ねる(クエリ)」のか「状態を変える(コマンド)」のかを設計する場面。両者を厳密に分離しておくと、`getBalance`を何度呼んでも安全(副作用がない)という前提を呼び出し側が信頼できる。

 

**組合せ例**: KNOW-F-0004(get/set対の命名規約)の理論的背景がこの「コマンド・クエリ分離原則」であり、KNOW-F-0059(voidの使いどころ)はコマンド側の戻り値設計そのものである。

 

**確認事項**: 罠は「更新した結果をついでに返すと呼び出し側が便利」という理由でコマンドとクエリを混ぜてしまい、後からその関数が副作用を持つのか問い合わせだけなのか名前だけでは判断できなくなること。境界値として、`depositAndGetBalance`のような複合関数を許容する場合は、名前(`deposit`でなく`depositAndGetBalance`)で複合であることを明示する折衷案も選択肢として残す。

 

---

 

### KNOW-F-0075 戻り値の粒度設計(生データか加工済みデータか)

 

**構造の型**:

```js

// 生データをそのまま返す(呼び出し側で加工の自由度が高い)

function getRawSalesRecords(db) {

return db.query("SELECT * FROM sales");

}

// 加工済みデータを返す(呼び出し側の負担は少ないが柔軟性は下がる)

function getMonthlySalesSummary(db, month) {

const records = getRawSalesRecords(db).filter(r => r.month === month);

return { month, total: records.reduce((s, r) => s + r.amount, 0), count: records.length };

}

```

 

**使いどころ**: 戻り値をどの程度「加工」した状態で返すかを決める場面。生データを返す関数は再利用性が高いが呼び出し側の負担が増え、加工済みデータを返す関数は特定用途に便利だが再利用性が下がる、というトレードオフを意識して設計する。

 

**組合せ例**: KNOW-F-0021(変換パイプライン関数の命名連鎖)のように、生データ取得(`getRawSalesRecords`)→加工(`getMonthlySalesSummary`)という段階を関数として分けておくと、両方の粒度を別々に再利用できる。これは第三章全体(戻り値設計)の締めくくりとして、次章(制御フロー)・第五章(エラー処理)へ進む前の設計判断の総括にあたる。

 

**確認事項**: 罠は「加工済みデータを返す関数」の内部に、他の場所でも欲しくなる中間加工処理(生データのフィルタリング等)が埋め込まれ、後から再利用しようとしても取り出せなくなること。境界値として、`getMonthlySalesSummary(db, "2026-13")`(存在しない月)のような不正な入力に対し、`count: 0, total: 0`という妥当なデフォルト値が返ることを確認する。

 

---

 

## 第四章 制御フローと早期returnの型(KNOW-F-0076〜0100)

 

関数の内部でどのように条件分岐・ループ・再帰を組み立てるかは、読みやすさと保守性を大きく左右する。本章では、ガード節・早期return・ネストの浅さ・再帰と反復の使い分けなど、制御フローを単純に保つための型を25種扱う。次巻BOOK-0358l(制御と分岐の型)の基礎編にあたる。

 

### KNOW-F-0076 ガード節による早期return基本形

 

**構造の型**:

```js

function processOrder(order) {

if (!order) return { ok: false, error: "order is required" };

if (order.items.length === 0) return { ok: false, error: "order has no items" };

if (order.total <= 0) return { ok: false, error: "invalid total" };

// ここから先は「正常な注文」だけを扱う本体処理

return { ok: true, confirmedAt: Date.now() };

}

```

 

**使いどころ**: 関数の冒頭で異常系・例外的なケースを次々に弾き、本体処理に到達する頃には「正常なデータだけ」を前提にできるようにしたいすべての関数。KNOW-F-0032(引数バリデーション位置)の制御フロー版であり、本章の最も基礎的な型にあたる。

 

**組合せ例**: KNOW-F-0045(引数バリデーションとエラー早期return)・KNOW-F-0058(早期returnとガード節の関係、戻り値視点)と三位一体で扱われる項目。KNOW-F-0077(ネストを浅くする)は本項を複数のif-elseネストと比較したときの利点を説明する。

 

**確認事項**: 罠はガード節が増えすぎて、本体処理より先にガード節だけで関数の大半を占めてしまうこと(その場合はKNOW-F-0108のバリデーション集約や別関数への抽出を検討する)。境界値として、`processOrder(null)`(order自体がない)が最初のガード節で正しく捕捉され、`order.items`への参照で例外を起こさないことを確認する。

 

---

 

### KNOW-F-0077 ネストを浅くする(else省略)

 

**構造の型**:

```js

// 悪い例: ネストが深い

function getShippingLabel(order) {

if (order.isValid) {

if (order.hasAddress) {

return `${order.address}宛`;

} else {

return "住所未設定";

}

} else {

return "無効な注文";

}

}

// 良い例: 早期returnでelseを省略しネストを浅くする

function getShippingLabel(order) {

if (!order.isValid) return "無効な注文";

if (!order.hasAddress) return "住所未設定";

return `${order.address}宛`;

}

```

 

**使いどころ**: if-elseのネストが2段以上になっている関数すべて。早期return(KNOW-F-0076)を使うと、`if (条件) { ... } else { ... }`の`else`ブロックを丸ごと省略でき、インデントの深さが減って読みやすくなる。

 

**組合せ例**: KNOW-F-0076の直接の帰結であり、KNOW-F-0097(ループ内の早期continueによるネスト削減)はループ内で同じ発想を適用したものである。

 

**確認事項**: 罠はelseを省略した結果、条件の網羅性(すべてのケースがカバーされているか)が見えにくくなること——最後のreturn文が「それ以外すべて」のケースを正しくカバーしているかを必ず確認する。境界値として、`order.isValid`と`order.hasAddress`の両方がfalseの場合に最初のガード節(`!order.isValid`)で正しく先に処理されることを確認する。

 

---

 

### KNOW-F-0078 条件の否定を先に処理して本体を単純化

 

**構造の型**:

```js

// 悪い例: 肯定条件のthen節に本体処理を書き、else節は空扱いに近い

function chargeCard(payment) {

if (payment.isAuthorized) {

// 本体処理が長く続く(数十行)

return doCharge(payment);

}

return { ok: false, error: "not authorized" };

}

// 良い例: 否定条件を先にガード節として処理する

function chargeCard(payment) {

if (!payment.isAuthorized) return { ok: false, error: "not authorized" };

// 本体処理はここから、否定条件は既に排除済み

return doCharge(payment);

}

```

 

**使いどころ**: 「正常系の処理が長く、異常系の処理が短い」関数すべて。異常系(否定条件)を先に短く片付けることで、長い本体処理が関数の末尾でインデントの浅い場所に置かれ、読み手が最後まで異常系のif文を意識せずに読み進められる。

 

**組合せ例**: KNOW-F-0076・KNOW-F-0077の実践的な適用基準であり、KNOW-F-0098(例外的経路とハッピーパスの視覚的分離)と同じ設計思想を共有する。

 

**確認事項**: 罠は否定条件が複雑になりすぎて(`!payment.isAuthorized || payment.isExpired && !payment.isRetryable`のような式)、それ自体が読みにくくなること——KNOW-F-0099(ドモルガン整理)や名前付きの中間変数への切り出しで対処する。境界値として、`payment.isAuthorized`が`undefined`(未設定)の場合に`!undefined`が`true`と評価され、安全側(未認可扱い)に倒れることを確認する。

 

---

 

### KNOW-F-0079 switch文とif-elseチェーンの使い分け

 

**構造の型**:

```js

// 同一の変数を複数の離散値と比較するならswitch

function describeStatus(status) {

switch (status) {

case "pending": return "処理待ち";

case "shipped": return "発送済み";

case "delivered": return "配達完了";

default: return "不明なステータス";

}

}

// 異なる変数・範囲の比較が絡むならif-elseチェーン

function describeScore(score) {

if (score >= 90) return "優";

else if (score >= 70) return "良";

else return "可";

}

```

 

**使いどころ**: 1つの値を複数の離散的なケースと比較する場合はswitch文(可読性が高く、KNOW-F-0089のdefault句と組み合わせて網羅性も確認しやすい)、範囲比較や複数の変数にまたがる条件はif-elseチェーンを使うという基準を立てる。

 

**組合せ例**: KNOW-F-0082(多重条件のテーブル化)はswitch文をさらにデータ駆動化した発展形であり、KNOW-F-0089(デフォルトケースの明示)はswitch文使用時に必ず守るべき補則である。

 

**確認事項**: 罠はswitch文で`break`を書き忘れ、意図せず次のcaseへ処理が「フォールスルー」してしまうこと(本項の例はreturnで抜けているため安全だが、副作用を伴うswitchでは要注意)。境界値として、`describeStatus(undefined)`(該当しない値)がdefault節で正しく処理されることを確認する。

 

---

 

### KNOW-F-0080 ループ内でのreturn/break/continueの使い分け

 

**構造の型**:

```js

function findFirstNegative(numbers) {

for (const n of numbers) {

if (n < 0) return n; // return: 関数全体を終了し値を返す

}

return null;

}

function countUntilNegative(numbers) {

let count = 0;

for (const n of numbers) {

if (n < 0) break; // break: ループだけを終了する

count++;

}

return count;

}

function sumPositives(numbers) {

let sum = 0;

for (const n of numbers) {

if (n < 0) continue; // continue: 今回の繰り返しだけをスキップする

sum += n;

}

return sum;

}

```

 

**使いどころ**: ループ内で条件によって処理を打ち切りたい/スキップしたい場面すべて。`return`は関数ごと終了(値を確定させて抜ける)、`break`はループだけ終了(ループ後の処理は続く)、`continue`はそのループ1回分だけスキップ、という3つの脱出手段を目的に応じて選ぶ。

 

**組合せ例**: KNOW-F-0097(ループ内の早期continueによるネスト削減)はcontinueの活用例であり、KNOW-F-0061(ジェネレータ/イテレータ)はループとreturnの組み合わせをyieldに置き換えた発展形である。

 

**確認事項**: 罠は`break`と`continue`を取り違えて使い、意図と異なる要素までスキップ/終了してしまうこと。境界値として、`findFirstNegative([])`(空配列)がループを1度も実行せずnullを返すこと、`sumPositives([])`が0を返すことを確認する。

 

---

 

### KNOW-F-0081 例外を制御フローに使わない原則

 

**構造の型**:

```js

// 悪い例: 例外を「見つかった」通知として使う(制御フローの乱用)

function findFirstEven(numbers) {

try {

numbers.forEach(n => { if (n % 2 === 0) throw n; });

} catch (found) {

return found;

}

return null;

}

// 良い例: 通常の制御構文(for-ofとreturn)で十分に表現できる

function findFirstEven(numbers) {

for (const n of numbers) {

if (n % 2 === 0) return n;

}

return null;

}

```

 

**使いどころ**: 例外(throw/catch)は「本当に例外的な事態」のためだけに使い、通常の分岐・早期終了(KNOW-F-0080)には使わないという原則。例外は多くの言語処理系でコストが高く、また`try-catch`の範囲を追う負担を読み手に強いる。

 

**組合せ例**: KNOW-F-0056(例外を投げるか戻り値で表現するかの判断基準)・KNOW-F-0101(例外と戻り値の使い分け基準)と同じ思想の制御フロー版であり、本項はその中でも「そもそも制御フローとして例外を使うべきでない」という最も基本的な注意点を扱う。

 

**確認事項**: 罠は「早期にループを抜けたいから」という理由だけで例外を使ってしまうこと(`break`や`return`で十分な場面がほとんど)。境界値として、`findFirstEven([])`(空配列)が例外を投げずnullを返すことを確認する(改善後の版はtry-catch自体が不要になる点も含めて検算する)。

 

---

 

### KNOW-F-0082 多重条件のテーブル化(条件分岐のデータ駆動化)

 

**構造の型**:

```js

// 悪い例: 条件分岐が長いif-elseチェーンで表現される

function getShippingFee(region) {

if (region === "north") return 800;

if (region === "south") return 700;

if (region === "east") return 600;

if (region === "west") return 900;

return 1000;

}

// 良い例: テーブル(オブジェクト)に条件と結果の対応をまとめる

const SHIPPING_FEE_TABLE = { north: 800, south: 700, east: 600, west: 900 };

function getShippingFee(region) {

return SHIPPING_FEE_TABLE[region] ?? 1000; // 該当なしは既定値

}

```

 

**使いどころ**: 「入力値→対応する結果」という単純な対応関係が、条件分岐(if-elseやswitch)として何十行にもわたって書かれている場面。データ(テーブル)として切り出すことで、条件が増えてもコードの行数(分岐ロジック)は増えず、テーブルの1行を追加するだけで済む。

 

**組合せ例**: KNOW-F-0079(switch文とif-elseの使い分け)からさらに一歩進んだ発展形であり、BOOK-0184の理-KAN-014(剰余関数)や理-KAN-026(パリティ写像)のような「入力を出力へ機械的に写す」関数の実装技法と発想が共通する。

 

**確認事項**: 罠はテーブルに存在しないキーを渡したとき、`undefined`が返るのか既定値が返るのかが曖昧になること(本項の例では`?? 1000`で明示している)。境界値として、`getShippingFee("north")`(存在するキー)・`getShippingFee("unknown")`(存在しないキー)の両方で意図した値が返ることを確認する。

 

---

 

### KNOW-F-0083 状態異常の早期検知(assert的なガード)

 

**構造の型**:

```js

function assertInvariant(condition, message) {

if (!condition) throw new Error(`invariant violated: ${message}`);

}

function popStack(stack) {

assertInvariant(stack.length > 0, "stack must not be empty before pop");

return stack.pop();

}

```

 

**使いどころ**: 「本来ここでは絶対に成り立っているべき前提条件」を明示的にチェックしたい場面。呼び出し側の誤用や、コードの他の場所での不整合(バグ)を、症状が離れた場所で表面化する前に、原因の近くで早期に検知する。

 

**組合せ例**: KNOW-F-0117(前提条件違反〈programmer error〉と実行時エラー〈operational error〉の区別)で述べる「プログラマの誤り」を捕捉する具体的な実装形であり、KNOW-F-0032(引数バリデーション)が「外部入力」を対象にするのに対し、本項は「内部の前提条件」を対象にする点で対になる。

 

**確認事項**: 罠はassertを本番環境でも常に実行し続けることでパフォーマンスに影響が出る場合があること(重い検証は開発・テスト環境限定にする選択肢も検討する)。境界値として、`popStack([])`(空のスタック)に対して`assertInvariant`が正しく例外を投げ、`stack.pop()`(undefinedを返すだけで気づかれにくい)まで処理が進まないことを確認する。

 

---

 

### KNOW-F-0084 再帰関数のベースケース設計

 

**構造の型**:

```js

function factorial(n) {

if (n < 0) throw new RangeError("n must be non-negative"); // 不正値のガード

if (n === 0 || n === 1) return 1; // ベースケース

return n * factorial(n - 1); // 再帰ケース(nが必ず減少する)

}

console.assert(factorial(4) === 24);

```

 

**使いどころ**: 再帰関数を設計するすべての場面。ベースケース(それ以上分解せず即座に答えを返す条件)を最初に明示し、再帰ケースでは必ず「問題を小さくしてから」自分自身を呼ぶことで、無限再帰を防ぐ。

 

**組合せ例**: BOOK-0184の理-KAN-023(再帰関数、階乗)の実装側対応にあたり、KNOW-F-0085(反復と再帰の使い分け)は再帰でなくループで書く選択肢との比較を扱う。

 

**確認事項**: 罠はベースケースの条件を書き忘れる、または再帰呼び出しの引数が「小さくならない」ケース(無限再帰、スタックオーバーフロー)。境界値として、`factorial(0)`(ベースケースちょうど)・`factorial(-1)`(不正値)がそれぞれ正しく1、例外になることを確認する。

 

---

 

### KNOW-F-0085 反復と再帰の使い分け

 

**構造の型**:

```js

// 再帰版: 読みやすいが、nが大きいとスタックオーバーフローの危険

function sumRecursive(n) {

return n <= 0 ? 0 : n + sumRecursive(n - 1);

}

// 反復版: nが大きくても安全、ループで同じ結果を得る

function sumIterative(n) {

let total = 0;

for (let i = 1; i <= n; i++) total += i;

return total;

}

console.assert(sumRecursive(100) === sumIterative(100));

```

 

**使いどころ**: 同じ結果を再帰でもループでも書ける処理において、どちらを選ぶかの判断基準を持つ場面。再帰は木構造やネストしたデータ(JSON、DOM)の処理で自然に書けるが、単純な繰り返し処理で入力サイズが大きくなりうる場合は反復(ループ)の方がスタックオーバーフローのリスクがなく安全である。

 

**組合せ例**: KNOW-F-0084(ベースケース設計)を前提とし、BOOK-0184理-KAN-022(反復適用関数)とKNOW-F-0084(理-KAN-023の実装対応)を比較検討する橋渡しの項目にあたる。

 

**確認事項**: 罠は再帰の深さがJavaScriptエンジンのコールスタック上限(実装依存だが数千〜数万段程度)を超え、`RangeError: Maximum call stack size exceeded`が発生すること。境界値として、`sumRecursive`に非常に大きな値(例えば100000)を渡すとスタックオーバーフローするのに対し、`sumIterative`は同じ値でも問題なく完了することを確認する(末尾再帰最適化がJavaScriptの主要実行系で保証されていない点に注意)。

 

---

 

### KNOW-F-0086 早期returnとリソース解放(finally)の両立

 

**構造の型**:

```js

function readAndProcess(resource) {

resource.open();

try {

if (!resource.isValid()) return null; // 早期returnしてもfinallyは必ず実行される

return resource.readAll();

} finally {

resource.close(); // 正常終了・早期return・例外のいずれでも必ず呼ばれる

}

}

```

 

**使いどころ**: ファイルハンドル・データベース接続・ロックなど、明示的に解放が必要なリソースを扱う関数で、途中に早期returnやthrowがある場合。`finally`ブロックは、try節の中でどの経路(正常終了・早期return・例外)を通っても必ず実行されるため、解放処理を1箇所にまとめられる。

 

**組合せ例**: KNOW-F-0076(ガード節による早期return)とKNOW-F-0111(finally句によるリソース確実解放)を橋渡しする項目であり、両者を同時に満たす設計の典型例である。

 

**確認事項**: 罠は`finally`ブロック内で新たな例外を投げてしまい、try節やcatch節で発生した元の例外が上書きされて失われること(finally内の処理は極力単純にする)。境界値として、`resource.isValid()`がfalseの場合(早期return)でも`resource.close()`が確実に呼ばれることをモックで検証する。

 

---

 

### KNOW-F-0087 条件式の複雑さを関数抽出で解消

 

**構造の型**:

```js

// 悪い例: 条件式が長く、意図が読み取りにくい

function canPurchase(user, item) {

if (user.age >= item.minAge && user.balance >= item.price && !user.isBanned && item.stock > 0) {

return true;

}

return false;

}

// 良い例: 条件を意味のある名前を持つ関数に抽出する

function isOldEnough(user, item) { return user.age >= item.minAge; }

function canAfford(user, item) { return user.balance >= item.price; }

function isInStock(item) { return item.stock > 0; }

function canPurchase(user, item) {

return isOldEnough(user, item) && canAfford(user, item) && !user.isBanned && isInStock(item);

}

```

 

**使いどころ**: 1つのif文の条件式が`&&`や`||`で3つ以上つながり、何を判定しているのか一読して分からなくなっている場面。各条件を独立した述語関数(KNOW-F-0016)として抽出すると、条件式自体がドキュメントのように読める。

 

**組合せ例**: KNOW-F-0016(述語関数の命名)の直接の応用であり、KNOW-F-0092(早期return多用時の関数分割シグナル)と同じ「複雑さの兆候を関数分割で解消する」思想を共有する。

 

**確認事項**: 罠は条件を関数へ抽出しすぎて、逆に呼び出しの連鎖を追う必要が生じ、全体像が把握しにくくなること(抽出は3〜4条件を超えたあたりから検討するのが目安)。境界値として、`canPurchase`の各条件を個別にfalseにしたテストケース(年齢不足のみ、残高不足のみ等)をそれぞれ用意し、抽出後も同じ結果になることを確認する。

 

---

 

### KNOW-F-0088 ループの終了条件の明示化(while(true)+break回避)

 

**構造の型**:

```js

// 避けたい例: 終了条件がbreakの中に埋もれて見えにくい

function findNextAvailableSlot(slots) {

let i = 0;

while (true) {

if (i >= slots.length) return null;

if (slots[i].available) return slots[i];

i++;

}

}

// 良い例: 終了条件をwhileの条件式自体に明示する

function findNextAvailableSlot(slots) {

let i = 0;

while (i < slots.length && !slots[i].available) i++;

return i < slots.length ? slots[i] : null;

}

```

 

**使いどころ**: ループの終了条件を設計するすべての場面。`while (true) { ... if (x) break; ... }`という形は柔軟だが、終了条件がループ本体のどこに隠れているか探さないと分からない。可能な限り、終了条件をwhileの条件式そのものに書けないか検討する。

 

**組合せ例**: KNOW-F-0061(ジェネレータ/イテレータ)で無限に続く可能性のある系列を扱う際にも、明示的な終了条件(または呼び出し側での`break`)の設計が同様に重要になる。

 

**確認事項**: 罠は終了条件の書き換えミスにより無限ループに陥ること(`i++`を書き忘れる、条件の不等号を逆にする等)。境界値として、`findNextAvailableSlot([])`(空配列)がループを1度も実行せず即座にnullを返すことを確認する。

 

---

 

### KNOW-F-0089 デフォルトケースの明示(switchのdefault必須化)

 

**構造の型**:

```js

function getStatusColor(status) {

switch (status) {

case "success": return "green";

case "warning": return "yellow";

case "error": return "red";

default:

throw new Error(`unexpected status: ${status}`); // 想定外の値を静かに無視しない

}

}

```

 

**使いどころ**: switch文を書くすべての場面。`default`節を省略すると、想定外の値が渡されたときに何も実行されずに関数がそのまま抜けてしまい(戻り値がundefinedになる等)、バグの発見が遅れる。`default`で明示的にエラーを投げるか、少なくとも安全な既定値を返すことを徹底する。

 

**組合せ例**: KNOW-F-0079(switch文とif-elseチェーンの使い分け)・KNOW-F-0095(条件分岐の網羅性検査)と対で扱われ、KNOW-F-0117(前提条件違反の区別)の考え方に基づけば、想定外の値の混入は多くの場合プログラマの誤りに近いため例外で止めるのが安全側の設計になる。

 

**確認事項**: 罠は将来新しいstatus値(例えば"pending")が追加されたときに、既存のswitch文の更新が漏れ、`default`節のエラーで初めて気づく(それ自体は「安全に失敗する」設計として機能している)。境界値として、`getStatusColor("unknown")`が`default`節に到達し例外を投げることを確認する。

 

---

 

### KNOW-F-0090 短絡評価を使った簡潔な条件記述と読みやすさの境界

 

**構造の型**:

```js

// 許容範囲: 単純なガード目的の短絡評価

function greet(user) {

return user && user.name ? `こんにちは、${user.name}` : "こんにちは、ゲストさん";

}

// 行き過ぎの例: 短絡評価に複数の副作用を詰め込む(避けるべき)

user && user.isActive && (user.lastSeen = Date.now()) && notifyUser(user);

```

 

**使いどころ**: `&&`・`||`を条件分岐の代わりに使う場面。「値が存在すればプロパティを参照する」といった単純なガード目的では簡潔で読みやすいが、複数の副作用(代入・関数呼び出し)を`&&`で連結する書き方は、実行順序や返り値の意味が読み取りにくくなるため避ける。

 

**組合せ例**: KNOW-F-0052(null回避のためのOptional的パターン)のオプショナルチェイニング(`?.`)・Null合体演算子(`??`)は、本項の短絡評価をより安全な形に置き換えた現代的な代替手段である。

 

**確認事項**: 罠は`&&`の左辺が「falsy」だが意図しない値(0や空文字列)である場合に、右辺が評価されず処理が飛ばされてしまうこと(`0 && doSomething()`は`doSomething`を呼ばない)。境界値として、`greet(null)`・`greet({})`(nameプロパティなし)の両方がゲスト向けの挨拶になることを確認する。

 

---

 

### KNOW-F-0091 三項演算子の適用範囲(単純な二択のみ)

 

**構造の型**:

```js

// 良い例: 単純な二択

const label = isActive ? "有効" : "無効";

 

// 避けたい例: 三項演算子のネスト(可読性が急落する)

const grade = score >= 90 ? "優" : score >= 70 ? "良" : score >= 50 ? "可" : "不可";

// 良い例: ネストが必要な複雑さならif-elseチェーンかテーブル化(KNOW-F-0082)に戻す

function getGrade(score) {

if (score >= 90) return "優";

if (score >= 70) return "良";

if (score >= 50) return "可";

return "不可";

}

```

 

**使いどころ**: 条件によって返す値・代入する値が1つずつの、単純な二択の場面。三項演算子は`if (x) { a } else { b }`より簡潔に書けるが、ネストさせると一気に読みにくくなるため、二択を超える分岐にはif-elseチェーン(KNOW-F-0079)やテーブル化(KNOW-F-0082)に戻す判断基準を持つ。

 

**組合せ例**: KNOW-F-0028(定数関数、BOOK-0184理-KAN-020場合分け関数)と発想が共通し、三項演算子のネストが2段を超えたら関数抽出(KNOW-F-0087)のシグナルとして扱う。

 

**確認事項**: 罠は三項演算子の中に代入や関数呼び出しなどの副作用を書き込み、条件式なのか実行文なのか区別しにくくなること。境界値として、`getGrade(90)`(境界値ちょうど)が「優」になることを確認する(`>=`と`>`の取り違えは典型的な境界値バグである)。

 

---

 

### KNOW-F-0092 早期return多用時の関数分割シグナル

 

**構造の型**:

```js

// 早期returnが7つ以上ある関数は、複数の責務が1つの関数に混在しているサイン

function validateAndSubmitOrder(order) {

if (!order) return { ok: false, error: "order missing" };

if (!order.customerId) return { ok: false, error: "customer missing" };

if (order.items.length === 0) return { ok: false, error: "no items" };

// ... さらに4つ以上のガード節が続く場合、責務分割を検討する

return submitOrder(order);

}

// 分割後: バリデーション専用の関数を切り出す

function validateOrder(order) { /* すべてのガード節をここに集約 */ }

function submitOrderIfValid(order) {

const error = validateOrder(order);

return error ? { ok: false, error } : submitOrder(order);

}

```

 

**使いどころ**: ガード節(KNOW-F-0076)の数が増え続けている関数を見直す場面。早期returnが多いこと自体は悪ではないが、7〜8個を超えたあたりから「その関数は本当に1つの責務だけを担っているか」を疑う目安として使う。

 

**組合せ例**: KNOW-F-0050(引数過多のシグナル)の制御フロー版であり、KNOW-F-0108(バリデーションエラーの集約)は分割後のバリデーション専用関数の戻り値設計として接続する。

 

**確認事項**: 罠は「早期returnが多い=常に悪い」と機械的に判断し、本当に多くの前提条件を検証する必要がある関数(セキュリティ検証など)まで無理に分割してしまうこと。境界値として、分割後の`validateOrder`と`submitOrderIfValid`を組み合わせた結果が、分割前の`validateAndSubmitOrder`と同じ入出力になることをテストで確認する(リファクタリング前後の振る舞い一致)。

 

---

 

### KNOW-F-0093 フラグ変数による制御フローの複雑化を避ける

 

**構造の型**:

```js

// 悪い例: フラグ変数でループの状態を管理する

function hasDuplicate(items) {

let found = false;

for (const item of items) {

if (seen.has(item)) { found = true; }

seen.add(item);

}

return found;

}

// 良い例: 見つかった時点で即座にreturnする(早期return、KNOW-F-0076)

function hasDuplicate(items) {

const seen = new Set();

for (const item of items) {

if (seen.has(item)) return true;

seen.add(item);

}

return false;

}

```

 

**使いどころ**: ループの中で「何かが起きたかどうか」を後で判定するためだけの真偽値変数(フラグ)を使っている場面。多くの場合、フラグが`true`になった時点で即座に`return`すれば、フラグ変数自体が不要になり、ループも早く終わらせられる。

 

**組合せ例**: KNOW-F-0080(ループ内でのreturn/break/continueの使い分け)の実践例であり、KNOW-F-0096(状態機械としての関数設計)はフラグ変数の管理がさらに複雑な場合(複数の状態を持つ場合)への発展的対処法を扱う。

 

**確認事項**: 罠はフラグ変数を早期returnに置き換えた結果、元々ループの後半で行っていた別の処理(集計など)がスキップされてしまい、意図しない仕様変更になること(単純な「見つけたら即終了」以外の目的でフラグが使われている場合は要注意)。境界値として、`hasDuplicate([])`(空配列)・`hasDuplicate([1])`(重複なし)がそれぞれfalseを返すことを確認する。

 

---

 

### KNOW-F-0094 コールバック地獄の回避(Promiseチェーン/async-await化)

 

**構造の型**:

```js

// 悪い例: コールバックのネストが深くなる(コールバック地獄)

fetchUser(id, (user) => {

fetchPosts(user.id, (posts) => {

fetchComments(posts[0].id, (comments) => {

console.log(comments);

});

});

});

// 良い例: async/awaitでネストのない直列処理に書き換える

async function loadFirstPostComments(id) {

const user = await fetchUserAsync(id);

const posts = await fetchPostsAsync(user.id);

const comments = await fetchCommentsAsync(posts[0].id);

return comments;

}

```

 

**使いどころ**: 非同期処理を複数連続して実行する必要がある場面。コールバックベースのAPIが深くネストすると、KNOW-F-0077(ネストを浅くする)の原則に反し、エラー処理(各階層で個別にエラーを扱う必要がある)も煩雑になる。async/awaitで書き直すことで、見た目上は同期処理のような直列の流れになる。

 

**組合せ例**: KNOW-F-0017(非同期関数の命名規約)・KNOW-F-0062(Promise/async関数の戻り値設計)と組み合わせて使う、非同期処理全体の制御フロー改善技法である。

 

**確認事項**: 罠はasync/await化した際に、本来並行実行できる処理(`fetchPosts`と無関係な別のAPI呼び出し)まで直列(`await`を連続で書く)にしてしまい、不要に遅くなること(独立した処理は`Promise.all`で並行化する)。境界値として、`loadFirstPostComments`で`posts`が空配列の場合(`posts[0]`が`undefined`になる)にエラーメッセージの分かりやすい例外が投げられることを確認する。

 

---

 

### KNOW-F-0095 条件分岐の網羅性検査(if-else if連鎖の抜け漏れ防止)

 

**構造の型**:

```js

function getSeasonFee(month) {

if (month >= 3 && month <= 5) return "春料金";

else if (month >= 6 && month <= 8) return "夏料金";

else if (month >= 9 && month <= 11) return "秋料金";

else if (month === 12 || month <= 2) return "冬料金"; // 12月・1月・2月を確実にカバー

else throw new Error(`invalid month: ${month}`); // 1〜12の範囲外を明示的に検知

}

```

 

**使いどころ**: if-else ifの連鎖を書くすべての場面で、入力の全範囲が漏れなくカバーされているかを確認する技法。最後に`else throw`のような「本来到達しないはずの経路」を置いておくと、条件の設計ミス(範囲の抜け漏れ、境界の重複)を実行時に検知できる。

 

**組合せ例**: KNOW-F-0089(switchのdefault必須化)のif-else版にあたり、KNOW-F-0083(assert的なガード)と同じ「本来起こらないはずの状態を明示的に検知する」思想を共有する。

 

**確認事項**: 罠は条件の境界がずれていて(`month <= 5`と`month >= 6`の間に隙間や重複がないか)、特定の入力がどの分岐にも該当しなかったり、複数の分岐に該当してしまったりすること。境界値として、`getSeasonFee(1)`・`getSeasonFee(2)`・`getSeasonFee(12)`(冬料金の3パターン)と`getSeasonFee(0)`・`getSeasonFee(13)`(範囲外、例外)をそれぞれ確認する。

 

---

 

### KNOW-F-0096 状態機械としての関数設計(制御フローの明示的状態化)

 

**構造の型**:

```js

const TRANSITIONS = {

idle: { start: "running" },

running: { pause: "paused", finish: "done" },

paused: { resume: "running" },

done: {},

};

function transition(currentState, event) {

const next = TRANSITIONS[currentState]?.[event];

if (!next) throw new Error(`invalid transition: ${currentState} + ${event}`);

return next;

}

console.assert(transition("idle", "start") === "running");

```

 

**使いどころ**: フラグ変数(KNOW-F-0093)を複数組み合わせても状態の組み合わせを表現しきれない、複雑な状態遷移を持つ処理(注文のステータス、UIの表示モード、通信のライフサイクル)。状態と、その状態で許可される遷移(イベント)をテーブル(KNOW-F-0082のデータ駆動化と同じ発想)として明示すると、if-elseの網羅性検査(KNOW-F-0095)の手間が大幅に減る。

 

**組合せ例**: BOOK-0184理-KAN-194(状態機械遷移関数、目録側で詳述)の実装対応にあたり、第五章KNOW-F-0122(入力検証エラーと状態不整合エラーの型分け)で「不正な状態遷移」をどう報告するかを扱う。

 

**確認事項**: 罠は許可されていない遷移(`transition("done", "start")`)が静かに`undefined`を返し、呼び出し側でエラーとして扱われないこと(本項の実装は`throw`で対処している)。境界値として、`TRANSITIONS`に定義のない状態(`transition("unknown", "start")`)を渡した場合にも同じエラー経路に入ることを確認する。

 

---

 

### KNOW-F-0097 ループ内の早期continueによるネスト削減

 

**構造の型**:

```js

// 悪い例: 条件を満たす要素だけを処理するためにネストする

function processActiveUsers(users) {

const results = [];

for (const user of users) {

if (user.isActive) {

if (user.hasEmail) {

results.push(sendEmail(user));

}

}

}

return results;

}

// 良い例: continueで対象外を先に除外し、本体処理のネストを1段にする

function processActiveUsers(users) {

const results = [];

for (const user of users) {

if (!user.isActive) continue;

if (!user.hasEmail) continue;

results.push(sendEmail(user));

}

return results;

}

```

 

**使いどころ**: ループ内で条件を満たす要素だけを処理したい場面。`if`のネストで対象を絞り込むのでなく、対象外の要素を`continue`で早期にスキップすることで、ループ本体の主要な処理(`sendEmail`の呼び出し)が最も浅いインデントに置かれる。

 

**組合せ例**: KNOW-F-0077(ネストを浅くする)のループ版であり、KNOW-F-0080(ループ内でのreturn/break/continueの使い分け)の実践例の一つである。

 

**確認事項**: 罠は`continue`を使ったことで、本来ループの最後に必ず実行すべき処理(カウンタの更新等)がスキップされてしまうこと(`continue`は「その回の残りの処理」をすべて飛ばす点に注意)。境界値として、`processActiveUsers([])`(空配列)が空配列を返すこと、全員が非アクティブの場合も同様に空配列になることを確認する。

 

---

 

### KNOW-F-0098 例外的経路とハッピーパスの視覚的分離

 

**構造の型**:

```js

function checkout(cart) {

// --- 異常系(ハッピーパスでない経路)をまとめて先に処理 ---

if (cart.items.length === 0) return { ok: false, error: "empty cart" };

if (!cart.paymentMethod) return { ok: false, error: "no payment method" };

// --- ここからハッピーパス(正常系の本筋) ---

const total = calculateTotal(cart.items);

const receipt = charge(cart.paymentMethod, total);

return { ok: true, receipt };

}

```

 

**使いどころ**: 関数の読み手が「まず正常系の一本道を追いたい」というニーズに応えるための構成技法。異常系のガード節をコメントやブロックの区切りで視覚的にひとまとめにし、ハッピーパス(正常系の主要な処理の流れ)をその後に続けて記述する。

 

**組合せ例**: KNOW-F-0076(ガード節)・KNOW-F-0078(否定条件を先に処理)の集大成にあたる項目であり、第五章KNOW-F-0101(例外と戻り値の使い分け基準)とあわせて、想定内エラー(ガード節側)と想定外エラー(例外)の役割分担を最終的に確定させる。

 

**確認事項**: 罠は「異常系をまとめる」ことにこだわりすぎて、本来個別に検証すべき条件同士の依存関係(KNOW-F-0038)を見落とすこと。境界値として、`checkout`にすべての条件を満たすカート(正常系)を渡した場合に、ガード節を1つも通らずハッピーパスまで到達することを確認する。

 

---

 

### KNOW-F-0099 条件のドモルガン整理による可読性向上

 

**構造の型**:

```js

// 分かりにくい例: 否定の複合条件

if (!(user.isActive && user.hasVerifiedEmail)) {

return "アカウントが未完了です";

}

// ドモルガンの法則で整理: !(A && B) は !A || !B と同値

if (!user.isActive || !user.hasVerifiedEmail) {

return "アカウントが未完了です";

}

```

 

**使いどころ**: `!(A && B)`や`!(A || B)`のような、括弧全体に否定がかかった条件式を書いてしまった場面。ドモルガンの法則(`!(A && B) === (!A || !B)`、`!(A || B) === (!A && !B)`)を使って否定を内側に展開すると、読み手が二重に否定を処理する負担を減らせる。

 

**組合せ例**: KNOW-F-0078(条件の否定を先に処理して本体を単純化)の可読性をさらに高める補助技法であり、KNOW-F-0090(短絡評価の適用範囲)とあわせて条件式全体の読みやすさを整える。

 

**確認事項**: 罠はドモルガンの法則を誤って適用し、`&&`と`||`の入れ替えを忘れること(`!(A && B)`を`!A && !B`と誤変換するのが典型的なミス)。境界値として、`user.isActive = true, user.hasVerifiedEmail = false`のケースで、変換前後の条件式が同じ結果(true、すなわちメッセージを返す)になることを実際に代入して確認する。

 

---

 

### KNOW-F-0100 制御フローの単一出口 vs 複数出口論争と実務判断

 

**構造の型**:

```js

// 単一出口(構造化プログラミングの古典的原則): 関数の最後に1つのreturnだけを置く

function classifyAgeSingleExit(age) {

let result;

if (age < 13) result = "子供";

else if (age < 20) result = "未成年";

else result = "成人";

return result; // 出口は1箇所

}

// 複数出口(早期return、本冊が基本的に推奨する形): 各分岐で直接return

function classifyAgeMultiExit(age) {

if (age < 13) return "子供";

if (age < 20) return "未成年";

return "成人"; // 出口は複数だが、各行が単純

}

```

 

**使いどころ**: 関数の出口(return文)を1箇所にまとめるべきか、複数箇所に分散させてよいかという、構造化プログラミング以来の古典的な論争に対する実務的な判断が必要な場面。本冊は第四章全体を通じて、ガード節による複数出口(早期return)を基本形として推奨してきたが、「関数の終了後に必ず実行すべき後処理が複数の出口すべてに重複する」ような場合は、単一出口またはKNOW-F-0086(finallyの活用)を選ぶ判断もありうる。

 

**組合せ例**: 本項は第四章の総括にあたり、KNOW-F-0076〜0099で扱った早期return系の技法すべてが「複数出口を採用する場合の具体的な設計技法」であったことを振り返る位置づけを持つ。第五章(エラー処理)に進む前の、制御フロー設計の最終確認項目である。

 

**確認事項**: 罠はどちらの流儀を採用するかチーム内で合意せず、ファイルごとに書き方が混在すること(可読性の観点では一貫性そのものが価値を持つため、プロジェクト単位でどちらを既定にするか明文化する)。境界値として、`classifyAgeSingleExit(13)`と`classifyAgeMultiExit(13)`(境界値ちょうど)が同じ"未成年"を返すことを確認し、単一出口版・複数出口版のどちらでリファクタリングしても振る舞いが変わらないことを保証する。

 

---

 

## 第五章 例外とエラーメッセージ設計の技(KNOW-F-0101〜0125)

 

エラーは「起きてはいけないもの」ではなく「設計すべきもの」である。本章では、例外と戻り値の使い分け、カスタムエラークラス、エラーメッセージの書き方、リトライ、ログとの分離など、エラーを丁寧に扱うための型を25種扱い、第k部(基本形)の最終章として次巻BOOK-0358l・BOOK-0358nへの橋渡しとする。

 

### KNOW-F-0101 例外と戻り値の使い分け基準(想定内エラー vs 想定外エラー)

 

**構造の型**:

```js

// 想定内エラー(業務ルール上、日常的に起こりうる): 戻り値で表現する

function withdraw(balance, amount) {

if (amount > balance) return { ok: false, error: "insufficient funds" };

return { ok: true, balance: balance - amount };

}

// 想定外エラー(プログラムの前提が崩れている、通常起こらないはず): 例外で止める

function withdrawUnsafe(account, amount) {

if (!account) throw new TypeError("account must not be null"); // 呼び出し側の実装ミス

return withdraw(account.balance, amount);

}

```

 

**使いどころ**: すべてのエラー処理設計の出発点。「残高不足」のように、その関数を正しく使っていても日常的に発生しうる結果は戻り値(KNOW-F-0055のResult型)で表現し、「account自体がnull」のように、呼び出し側の実装が誤っていなければ絶対に起こらないはずの状態は例外で即座に停止させる、という二層の使い分けを基準とする。

 

**組合せ例**: KNOW-F-0056(例外を投げるか戻り値で表現するかの判断基準、第三章)の詳細版であり、KNOW-F-0117(前提条件違反と実行時エラーの区別)は本項の基準をさらに精緻化した項目である。

 

**確認事項**: 罠は「想定内」と「想定外」の境界線がプロジェクトやチームで揺れること(残高不足を例外で表現するチームもあれば、accountがnullな場合も戻り値で表現したいチームもある)。境界値として、`withdraw(1000, 1000)`(残高ちょうど)が成功として扱われることを確認し、「不足」の判定が`>`であり`>=`でないことを検算する。

 

---

 

### KNOW-F-0102 カスタムエラークラスの設計

 

**構造の型**:

```js

class InsufficientFundsError extends Error {

constructor(balance, requested) {

super(`insufficient funds: balance=${balance}, requested=${requested}`);

this.name = "InsufficientFundsError";

this.balance = balance;

this.requested = requested;

}

}

try {

throw new InsufficientFundsError(500, 1000);

} catch (err) {

if (err instanceof InsufficientFundsError) {

console.log(`不足額: ${err.requested - err.balance}`);

}

}

```

 

**使いどころ**: 標準の`Error`だけでは表現しきれない、エラー固有の追加情報(不足額、対象ID等)を持たせたい場面。`Error`を継承したクラスを作ることで、`instanceof`によるエラー種別の判定が可能になり、catch節で種類ごとに異なる処理を分岐できる。

 

**組合せ例**: KNOW-F-0069(戻り値としてのエラーコード vs 例外オブジェクト)で述べた「例外オブジェクト方式」の本格的な実装形であり、KNOW-F-0113(境界層でのエラー変換)でカスタムエラーを外部向けの形式に変換する際の入力にもなる。

 

**確認事項**: 罠は`this.name = "InsufficientFundsError"`を設定し忘れ、`console.error`の出力や一部の環境でエラー種別が"Error"のまま表示されてしまうこと(クラス名の自動設定に頼れない実行環境がある)。境界値として、`err instanceof InsufficientFundsError`が`true`になり、かつ`err instanceof Error`も同時に`true`になる(継承関係が正しく機能している)ことを確認する。

 

---

 

### KNOW-F-0103 エラーコードの体系設計(接頭辞+連番)

 

**構造の型**:

```js

// 領域ごとに接頭辞を分け、連番で管理する(例: AUTH=認証, PAY=決済, VAL=入力検証)

const ErrorCodes = {

AUTH_001: "認証トークンが無効です",

AUTH_002: "認証トークンの有効期限が切れています",

PAY_001: "残高が不足しています",

VAL_001: "必須項目が未入力です",

};

class AppError extends Error {

constructor(code) {

super(ErrorCodes[code] ?? `unknown error code: ${code}`);

this.code = code;

}

}

```

 

**使いどころ**: エラーの種類が数十〜数百に及ぶ大規模なシステムで、ログ検索・多言語対応(KNOW-F-0120)・サポート対応(エラーコードをユーザーに伝えて問い合わせに使う)を効率化したい場面。接頭辞で領域を分類し、連番で個々のエラーを一意に識別できるようにする。

 

**組合せ例**: KNOW-F-0102(カスタムエラークラス)にコードを持たせる形で組み合わせるのが定石であり、KNOW-F-0120(多言語対応を見据えたエラーメッセージ設計)はコードとメッセージ文言を分離する発展形として本項を土台にする。

 

**確認事項**: 罠はコード体系を後から拡張する際に番号の欠番・重複が発生し、KNOW-F-0002やKNOW-F-0024で述べた「一貫性の機械検査」と同様、コード一覧の重複チェックを自動化しないと運用でずれが生じること。境界値として、`ErrorCodes`に存在しないコードが渡された場合(`new AppError("XXX_999")`)に、フォールバックメッセージ(`unknown error code: XXX_999`)が使われることを確認する。

 

---

 

### KNOW-F-0104 エラーメッセージのテンプレート化(誰が読むかで書き分け)

 

**構造の型**:

```js

function buildErrorMessage(code, context) {

const templates = {

VAL_001: (ctx) => `フィールド「${ctx.field}」は必須です`, // ユーザー向け: 具体的で行動可能

};

const devDetail = `[${code}] at ${context.location}, input=${JSON.stringify(context.input)}`;

return {

userMessage: templates[code]?.(context) ?? "入力内容をご確認ください",

devMessage: devDetail, // 開発者向け: 詳細で技術的

};

}

```

 

**使いどころ**: エラーメッセージを表示する相手(エンドユーザー・開発者・運用担当者)によって、必要な情報の粒度が異なることを踏まえて設計する場面。ユーザー向けメッセージは「次に何をすればよいか」を示す行動可能な文言、開発者向けメッセージは原因調査に必要な技術的詳細(発生箇所、入力値)を含める。

 

**組合せ例**: KNOW-F-0103(エラーコードの体系)を土台にテンプレートを紐付け、KNOW-F-0116(エラーメッセージへの機密情報混入防止)は本項のdevMessage側に機密情報を含めてしまわないよう注意を促す対になる項目である。

 

**確認事項**: 罠はユーザー向けメッセージに開発者向けの技術用語(スタックトレースやSQL文)がそのまま漏れ出すこと(セキュリティ・UXの両面で問題になる)。境界値として、テンプレートに存在しないコード(`buildErrorMessage("UNKNOWN", {})`)でもuserMessageが汎用的な既定文言にフォールバックし、空文字列や`undefined`が画面に表示されないことを確認する。

 

---

 

### KNOW-F-0105 スタックトレースの保持(エラーのラップと原因チェーン cause)

 

**構造の型**:

```js

async function loadUserSettings(id) {

try {

return await fetchSettings(id);

} catch (originalError) {

throw new Error(`failed to load settings for user ${id}`, { cause: originalError });

}

}

try {

await loadUserSettings(42);

} catch (err) {

console.error(err.message); // "failed to load settings for user 42"

console.error(err.cause); // 元の原因(ネットワークエラー等)

}

```

 

**使いどころ**: 下位の処理(ネットワーク通信、DB操作)で発生したエラーを、上位の処理の文脈(「誰の・何の処理で失敗したか」)を加えて再送出したい場面。ES2022以降の`Error`コンストラクタの第2引数`{ cause }`によって、元のエラー(原因)を失わずに文脈を追加できる。

 

**組合せ例**: KNOW-F-0112(エラーの再送出と文脈追加)の具体的な実装手段であり、KNOW-F-0119(エラー発生箇所の特定を助けるコンテキスト情報の付加)とあわせて、デバッグ時の原因追跡を容易にする三点セットを構成する。

 

**確認事項**: 罠は`cause`オプションをサポートしない古い実行環境(一部の古いNode.js/ブラウザ)での互換性を確認せずに使ってしまうこと。境界値として、`err.cause`が存在しない通常のエラー(causeなしで投げられたエラー)に対して`err.cause`へアクセスしても`undefined`が返るだけで例外にならないことを確認する。

 

---

 

### KNOW-F-0106 リトライ設計(一時的エラーと恒久的エラーの区別)

 

**構造の型**:

```js

async function withRetry(operation, { maxAttempts = 3, delayMs = 500 } = {}) {

for (let attempt = 1; attempt <= maxAttempts; attempt++) {

try {

return await operation();

} catch (err) {

const isTransient = err.transient === true; // 一時的エラーかどうかのフラグ

if (!isTransient || attempt === maxAttempts) throw err; // 恒久的、または最終試行なら諦める

await new Promise((resolve) => setTimeout(resolve, delayMs * attempt)); // 指数的な待機

}

}

}

```

 

**使いどころ**: ネットワークの瞬断やサーバーの一時的な過負荷のような「時間をおけば成功するかもしれないエラー」(一時的エラー)と、「入力が不正」「認証切れ」のような「何度試しても失敗するエラー」(恒久的エラー)を区別し、前者だけをリトライする設計。区別せずに全エラーをリトライすると、恒久的エラーに対して無駄な再試行を繰り返す。

 

**組合せ例**: KNOW-F-0071(冪等性)が前提条件になる——冪等でない操作(例えば「注文を1件作成する」処理)を無条件にリトライすると、二重注文のような副作用が発生しうるため注意する。KNOW-F-0121(タイムアウトエラーの設計)と組み合わせて使うことが多い。

 

**確認事項**: 罠は`delayMs`を固定値のままリトライし続け、障害中のサーバーに一斉リトライが集中する「サンダリングハード問題」を引き起こすこと(本項の例では`delayMs * attempt`で単純な増加を入れているが、実務ではジッター〈ランダムなゆらぎ〉を加えるとさらに安全である)。境界値として、`maxAttempts: 1`(リトライなし)の場合に1回失敗しただけで即座にエラーが伝播することを確認する。

 

---

 

### KNOW-F-0107 ログとエラーオブジェクトの分離(ログは記録、エラーは制御)

 

**構造の型**:

```js

function processPayment(payment) {

try {

return charge(payment);

} catch (err) {

logger.error("payment processing failed", { paymentId: payment.id, error: err.message }); // 記録

throw err; // 制御フローは変えず、そのまま呼び出し元に伝播させる

}

}

```

 

**使いどころ**: エラーが発生した際に「記録すること」と「呼び出し元に伝えること」という2つの異なる責務を混同しない場面。ログ出力(記録)はエラーの発生を残すための副次的な処理であり、エラーの伝播(制御フロー、throwやResult型)はプログラムの実行経路を決める本質的な処理である。両者を1つの関数内で行う場合も、役割を意識して分けて書く。

 

**組合せ例**: KNOW-F-0112(エラーの再送出と文脈追加)と組み合わせて、ログには詳細な技術情報、再送出するエラーには文脈を追加した簡潔な情報、という書き分けを行うことが多い。

 

**確認事項**: 罠は同じエラーが複数の階層で繰り返しログに記録され(呼び出し階層ごとにcatchしてログを出す)、実際の発生回数以上にログが水増しされること(ログは発生源に近い1箇所、または最終的にエラーを握りつぶす境界層の1箇所に絞るのが望ましい)。境界値として、`processPayment`が失敗した場合にログが必ず1回だけ記録され、かつ元の例外がそのまま呼び出し元まで伝播することを確認する。

 

---

 

### KNOW-F-0108 バリデーションエラーの集約(複数フィールドエラーをまとめて返す)

 

**構造の型**:

```js

function validateUserForm(input) {

const errors = [];

if (!input.name) errors.push({ field: "name", message: "名前は必須です" });

if (!input.email?.includes("@")) errors.push({ field: "email", message: "メールアドレスの形式が不正です" });

if (input.age < 0) errors.push({ field: "age", message: "年齢は0以上である必要があります" });

return errors; // 空配列なら合格、1件以上あれば全エラーを一度に呼び出し側へ返す

}

```

 

**使いどころ**: フォーム入力のように、複数の項目を一度に検証したい場面。KNOW-F-0076のガード節で「最初のエラーだけ」を早期returnしてしまうと、ユーザーは1つ直しては再送信し、また次のエラーに気づく、という繰り返しを強いられる。エラーを配列に集約して一度に返すことで、すべての問題箇所を一度に提示できる。

 

**組合せ例**: KNOW-F-0020(バリデーション関数の命名)の`validate`系関数の標準的な戻り値設計であり、KNOW-F-0054(オブジェクト返し)の応用として、`{ valid: boolean, errors: [...] }`のような形にラップすることも多い。

 

**確認事項**: 罠はガード節による早期return(KNOW-F-0076)の思想とバリデーション集約の思想が矛盾するように見えること——実際には「関数全体の異常系(inputがnullである等)は早期returnで弾き、その関数の主目的である複数フィールド検証だけは集約する」という使い分けであり、対立しない。境界値として、`validateUserForm({ name: "", email: "", age: -1 })`(全項目が不正)がちょうど3件のエラーを含む配列を返すことを確認する。

 

---

 

### KNOW-F-0109 try-catchのスコープを最小化する

 

**構造の型**:

```js

// 悪い例: try節が広すぎて、どの行が例外を投げうるか分からない

function loadAndFormat(path) {

try {

const raw = readFile(path);

const parsed = JSON.parse(raw);

const formatted = formatForDisplay(parsed); // 例外を投げない処理まで含まれている

return formatted;

} catch (err) {

return null;

}

}

// 良い例: 例外を投げうる箇所だけをtryで囲む

function loadAndFormat(path) {

let parsed;

try {

parsed = JSON.parse(readFile(path));

} catch {

return null;

}

return formatForDisplay(parsed); // tryの外、通常の制御フローとして扱う

}

```

 

**使いどころ**: try-catchを使うすべての場面。try節の範囲を必要最小限にすることで、「このtry-catchは何の例外を捕捉するために存在するのか」が一目で分かるようになり、意図しない例外(本来はバグとして表面化すべきもの)まで誤って握りつぶすリスクを減らす。

 

**組合せ例**: KNOW-F-0068(例外安全性、戻り値経路と例外経路の一貫性)の実装技法として使われ、KNOW-F-0110(エラーの握りつぶし禁止)とセットで運用することで、狭いtry節+適切なcatch処理という堅牢な形に収束する。

 

**確認事項**: 罠はtry節を狭くしすぎて、本来まとめて扱うべき一連の処理(トランザクション的な複数ステップ)がバラバラになり、途中で失敗した場合の後始末が複雑化すること(その場合はKNOW-F-0086のfinallyやトランザクション境界の設計を別途検討する)。境界値として、`loadAndFormat`に不正なJSON文字列を返すパスを渡した場合、`JSON.parse`の例外だけが捕捉され、`formatForDisplay`内の別の潜在的なバグが誤って握りつぶされないことを確認する。

 

---

 

### KNOW-F-0110 エラーの握りつぶし禁止(空catch回避)

 

**構造の型**:

```js

// 悪い例: 空のcatch(エラーが発生したこと自体が消える)

try {

riskyOperation();

} catch (err) {

// 何もしない — 最も危険なパターン

}

// 良い例: 最低限ログを残す、または意図的に無視する理由をコメントで明示する

try {

riskyOperation();

} catch (err) {

logger.warn("riskyOperation failed, continuing with default behavior", { error: err.message });

}

```

 

**使いどころ**: catch節を書くすべての場面での必須チェック項目。空のcatch節(`catch (err) {}`)は、エラーが発生したという事実そのものを完全に消し去り、後から「なぜか動作がおかしい」という原因不明のバグ調査を招く、最も避けるべきアンチパターンの一つである。

 

**組合せ例**: KNOW-F-0107(ログとエラーオブジェクトの分離)の最低限の実践として本項が位置づけられ、KNOW-F-0068(例外安全性)で「デフォルト値を返す」設計を選ぶ場合も、最低限のログ出力は必ず残すべきという注意点として接続する。

 

**確認事項**: 罠は「握りつぶすこと自体が意図的な設計」である場合(例えば、失敗してもユーザー体験に影響しない裏側の分析ログ送信)に、なぜ無視してよいのかの理由がコメントとして残されず、後任者が誤って「バグだ」と判断して余計な修正を加えてしまうこと。境界値として、意図的に無視する場合でも`// intentionally ignored: analytics failure should not block the main flow`のような理由コメントを必須にする運用を確認する。

 

---

 

### KNOW-F-0111 finally句によるリソース確実解放

 

**構造の型**:

```js

function withLock(lock, operation) {

lock.acquire();

try {

return operation();

} finally {

lock.release(); // 正常終了・例外のどちらでも必ずロックを解放する

}

}

```

 

**使いどころ**: ロック・ファイルハンドル・データベース接続・トランザクションなど、「開始したら必ず終了処理が必要」なリソースを扱うすべての関数。`finally`ブロックに解放処理を書くことで、`operation()`が例外を投げた場合でもロックが解放されずに残ってしまう(デッドロック)事態を防ぐ。

 

**組合せ例**: KNOW-F-0086(早期returnとリソース解放の両立)と同一の技法であり、本項はより一般化した「ロック・接続・トランザクション」全般への適用を扱う。

 

**確認事項**: 罠は`lock.acquire()`自体が例外を投げる可能性を考慮せず、その場合に`try`ブロックに入る前の失敗に対して`finally`の`lock.release()`が実行されてしまい、取得していないロックを解放しようとするエラーが二次的に発生すること(`acquire`は`try`の外、`release`だけを`finally`に置く本項の構造がこれを正しく回避している点を確認する)。境界値として、`operation()`が例外を投げた場合でも`lock.release()`が必ず呼ばれ、次の`withLock`呼び出しがデッドロックしないことをテストで確認する。

 

---

 

### KNOW-F-0112 エラーの再送出(re-throw)と文脈追加

 

**構造の型**:

```js

function loadConfigFile(path) {

try {

return JSON.parse(readFile(path));

} catch (err) {

// ただ再送出するのでなく、どのファイルの処理で失敗したかという文脈を追加する

throw new Error(`failed to load config file: ${path}`, { cause: err });

}

}

```

 

**使いどころ**: 下位層で発生した汎用的なエラー(`JSON.parse`が投げる`SyntaxError`のように、それ単体では「どのファイルか」が分からないエラー)を、呼び出し階層を1つ上がるごとに文脈情報を追加しながら再送出したい場面。

 

**組合せ例**: KNOW-F-0105(スタックトレースの保持)の`cause`オプションを使った実装がそのまま本項の技法にあたり、KNOW-F-0119(エラー発生箇所の特定を助けるコンテキスト情報の付加)と一体で運用される。

 

**確認事項**: 罠は再送出のたびにメッセージを積み重ねすぎて(`"failed to load config file: failed to parse: failed to read: ..."`のような多重連結)、かえって重要な情報が埋もれること——`cause`チェーンを使えば各層で簡潔なメッセージのまま原因を遡れるため、文字列連結よりも`cause`オプションを優先する。境界値として、`loadConfigFile`が存在しないパスを渡された場合(readFile自体が失敗する場合)にも同じcatch節で捕捉され、一貫した形式のエラーが投げられることを確認する。

 

---

 

### KNOW-F-0113 境界層でのエラー変換(内部エラー→外部向けエラー)

 

**構造の型**:

```js

// 内部層: 詳細なドメインエラー

class OutOfStockError extends Error { constructor(sku) { super(`out of stock: ${sku}`); this.sku = sku; } }

 

// 境界層(例: HTTPハンドラ): 内部エラーを外部向けの安全な形式に変換する

function handleCreateOrderRequest(req) {

try {

return { status: 200, body: createOrder(req.body) };

} catch (err) {

if (err instanceof OutOfStockError) {

return { status: 409, body: { error: "在庫切れの商品が含まれています" } }; // 内部詳細は隠す

}

return { status: 500, body: { error: "internal error" } }; // 未知のエラーは詳細を漏らさない

}

}

```

 

**使いどころ**: APIハンドラ・UIのイベントハンドラなど、システムの内部処理と外部(利用者、他システム)との境界にあたる層。内部で使うエラー(スタックトレース、内部の変数名を含む)をそのまま外部に露出させず、境界層で「利用者が理解でき、かつ機密情報を含まない」形式に変換してから返す。

 

**組合せ例**: KNOW-F-0102(カスタムエラークラス)で作った内部エラーの`instanceof`判定を境界層で使う典型例であり、KNOW-F-0116(エラーメッセージへの機密情報混入防止)は本項の変換処理が守るべき安全基準を扱う。

 

**確認事項**: 罠は`instanceof`による分岐が漏れ、未知のエラー型に対して`err.message`や`err.stack`をそのまま外部に返してしまうこと(本項の例では`else`節で汎用的な"internal error"にフォールバックしている点が対策になる)。境界値として、`OutOfStockError`以外の予期しないエラー(例えばTypeErrorのようなプログラミングミス由来)が発生した場合でも、ステータス500かつ詳細を含まない汎用メッセージになることを確認する。

 

---

 

### KNOW-F-0114 Result型とtry-catchの併用戦略

 

**構造の型**:

```js

// 外部ライブラリ(例外を投げる)をResult型でラップし、以降は例外を使わずに扱う

function safeParseJson(text) {

try {

return { ok: true, value: JSON.parse(text) };

} catch (err) {

return { ok: false, error: err.message };

}

}

// 以降の処理は例外を意識せず、Result型のチェックだけで進められる

function loadPreferences(text) {

const result = safeParseJson(text);

if (!result.ok) return { theme: "light" }; // 既定値にフォールバック

return { theme: "light", ...result.value };

}

```

 

**使いどころ**: `JSON.parse`のような、例外を投げる標準API・外部ライブラリの呼び出しを境界(できるだけ低いレイヤー)で一度だけtry-catchし、それより上位の自前コードはResult型(KNOW-F-0055)だけで統一的に扱いたい場面。例外とResult型を無秩序に混在させず、「例外は境界で吸収し、以降はResult型」という一方向の変換ルールを保つ。

 

**組合せ例**: KNOW-F-0055(Result型パターン)・KNOW-F-0109(try-catchのスコープ最小化)の複合適用例であり、KNOW-F-0113(境界層でのエラー変換)と対になる「入力側の境界」を扱う項目である。

 

**確認事項**: 罠はResult型に変換したはずなのに、コードの別の場所でまだ生のtry-catchが散在し、エラー処理の方式がプロジェクト内で統一されないこと。境界値として、`safeParseJson("")`(空文字列、構文エラー)が`ok: false`を返し、`loadPreferences`が例外を投げずに既定のtheme設定へフォールバックすることを確認する。

 

---

 

### KNOW-F-0115 非同期エラーのハンドリング(Promise.catch/async-await try)

 

**構造の型**:

```js

// then/catchチェーン方式

fetchData(url).then((data) => process(data)).catch((err) => console.error(err));

 

// async/await + try-catch方式(同期処理と同じ書き方でエラー処理できる)

async function loadAndProcess(url) {

try {

const data = await fetchData(url);

return process(data);

} catch (err) {

console.error(err);

return null;

}

}

```

 

**使いどころ**: 非同期処理(Promiseを返す関数)のエラーを捕捉するすべての場面。`.catch()`はPromiseチェーンのどこかで発生した拒否(reject)を捕捉し、`async/await`内の`try-catch`は同期処理と統一的な書き方でエラーを扱える。プロジェクト内でどちらかに書き方を統一しておくと読みやすさが安定する。

 

**組合せ例**: KNOW-F-0062(Promise/async関数の戻り値設計)・KNOW-F-0094(コールバック地獄の回避)と三点セットで扱う項目であり、KNOW-F-0106(リトライ設計)の`withRetry`関数の内部でも本項のtry-catchが使われている。

 

**確認事項**: 罠は`async`関数を呼び出したのに`await`せず、かつ`.catch()`も付けないこと(未処理のPromise拒否〈unhandled promise rejection〉となり、実行環境によっては警告やプロセス終了の原因になる)。境界値として、`fetchData`が失敗するURLを渡した場合に、then/catch方式・async-await方式のどちらでも同じエラーメッセージが捕捉されることを確認する。

 

---

 

### KNOW-F-0116 エラーメッセージへの機密情報混入防止

 

**構造の型**:

```js

// 悪い例: エラーメッセージにパスワードやトークンをそのまま含めてしまう

function authenticate(username, password) {

if (password !== stored[username]) {

throw new Error(`authentication failed for ${username} with password ${password}`); // 機密漏洩

}

}

// 良い例: 機密値そのものはメッセージに含めない

function authenticate(username, password) {

if (password !== stored[username]) {

throw new Error(`authentication failed for user: ${username}`); // パスワードは含めない

}

}

```

 

**使いどころ**: パスワード・トークン・個人情報・クレジットカード番号など、ログやエラーメッセージに残すべきでない値を扱う関数すべて。エラーメッセージやログは、開発時のデバッグ目的で作られることが多いが、本番環境ではログ収集基盤に長期間保存されるため、機密情報の混入はセキュリティインシデントに直結する。

 

**組合せ例**: KNOW-F-0104(エラーメッセージのテンプレート化)のdevMessage側でも同じ注意が必要であり、KNOW-F-0013(意味ハンガリアン)で述べた`rawInputHtml`のような「未検証・機密の可能性がある値」を示す命名習慣と組み合わせると、レビュー時に気づきやすくなる。

 

**確認事項**: 罠はスタックトレースや`JSON.stringify(input)`のような「入力全体をまるごとダンプする」デバッグコードを本番環境に残してしまい、意図せず機密情報を含めてしまうこと。境界値として、`authenticate("alice", "secret123")`が失敗した場合のエラーメッセージ文字列に`"secret123"`という部分文字列が一切含まれないことをテストで検査する(文字列検索による機械的なチェックが可能)。

 

---

 

### KNOW-F-0117 前提条件違反(programmer error)と実行時エラー(operational error)の区別

 

**構造の型**:

```js

// programmer error: 呼び出し側のコードが誤っている(修正すべきはコード)

function getElementAt(array, index) {

if (!Array.isArray(array)) throw new TypeError("array must be an Array"); // 型の誤りは常にバグ

return array[index];

}

// operational error: 外部環境に起因する(修正すべきは環境やリトライ等の運用対応)

async function connectDatabase(config) {

try {

return await db.connect(config);

} catch (err) {

throw new Error("database connection failed, will retry", { cause: err }); // 環境要因

}

}

```

 

**使いどころ**: エラーを捕捉したときに「これはコードのバグなのか、それとも外部環境の問題なのか」を区別し、対処方針(programmer errorは即座にクラッシュさせて開発者に気づかせる、operational errorはリトライやフォールバックで乗り切る)を分ける場面。

 

**組合せ例**: KNOW-F-0101(例外と戻り値の使い分け基準)・KNOW-F-0083(assert的なガード)で扱った「前提条件違反」の概念をエラー処理全体の文脈で再整理したものであり、KNOW-F-0106(リトライ設計)は主にoperational error側への対処技法にあたる。

 

**確認事項**: 罠はprogrammer error(本来テストで発見すべきバグ)まで本番環境でtry-catchによって握りつぶし(KNOW-F-0110)、症状を隠したまま放置してしまうこと——バグは早期に、大きな音を立てて失敗させる方が長期的には健全である。境界値として、`getElementAt(null, 0)`(配列でない値)が確実に例外を投げ、`connectDatabase`の接続失敗が「リトライ可能」な情報を持って伝播することの両方を確認する。

 

---

 

### KNOW-F-0118 デフォルト値によるエラー回避 vs 明示的失敗のどちらを選ぶか

 

**構造の型**:

```js

// 選択肢A: デフォルト値で静かに回避する(利便性重視)

function getPageSize(config) {

return config?.pageSize ?? 20; // 未設定なら黙って20件にする

}

// 選択肢B: 明示的に失敗させる(正確性重視)

function getRequiredApiKey(config) {

if (!config?.apiKey) throw new Error("apiKey is required in config"); // 黙って進めない

return config.apiKey;

}

```

 

**使いどころ**: 値が欠けているときに「妥当な既定値で処理を続けてよい」のか「その値がなければ処理そのものが無意味・危険」なのかを判断する場面。ページサイズのような表示上の設定は既定値で回避してよいが、APIキーのようなセキュリティ・整合性に関わる必須値は、欠けていることを隠さず即座に失敗させるべきである。

 

**組合せ例**: KNOW-F-0064(空配列/空オブジェクト返し)は選択肢Aの戻り値版であり、KNOW-F-0083(assert的なガード)は選択肢Bの制御フロー版にあたる。本項はその2つの技法をいつ使い分けるかの判断基準を提供する。

 

**確認事項**: 罠は「とりあえずデフォルト値を入れておけばエラーが起きない」という理由だけで、本来失敗させるべき箇所にまでKNOW-F-0064的な回避を適用してしまうこと(欠落に気づかないまま誤った設定で本番運用されるリスク)。境界値として、`getPageSize(undefined)`(config自体がない)が例外にならず20を返すこと、`getRequiredApiKey({})`(apiKeyだけがない)が確実に例外を投げることを確認する。

 

---

 

### KNOW-F-0119 エラー発生箇所の特定を助けるコンテキスト情報の付加

 

**構造の型**:

```js

function processRow(row, rowIndex, filename) {

try {

return transform(row);

} catch (err) {

throw new Error(

`failed to process row ${rowIndex} in ${filename}: ${err.message}`,

{ cause: err }

);

}

}

```

 

**使いどころ**: バッチ処理・一括インポートのように、同じ処理が大量のデータに対して繰り返し実行される場面。単に「処理に失敗しました」というエラーでは、数千行あるデータのどこで失敗したか特定できないため、行番号・ファイル名・ID等の「どのデータか」を示す文脈情報を必ずエラーに含める。

 

**組合せ例**: KNOW-F-0105(スタックトレースの保持)・KNOW-F-0112(エラーの再送出と文脈追加)の具体的な適用例であり、KNOW-F-0103(エラーコードの体系設計)と組み合わせて`code + context`の両方を持つエラー形式に発展させられる。

 

**確認事項**: 罠はコンテキスト情報を追加する際に、KNOW-F-0116(機密情報混入防止)に反して行データそのもの(個人情報を含む可能性がある)を丸ごとエラーメッセージに含めてしまうこと(行番号やIDのような「参照可能な識別子」にとどめ、内容そのものは含めないのが安全)。境界値として、`processRow`が1000行中の500行目で失敗した場合、エラーメッセージに`"row 500"`という具体的な位置情報が含まれることを確認する。

 

---

 

### KNOW-F-0120 多言語対応を見据えたエラーメッセージ設計(コードとメッセージの分離)

 

**構造の型**:

```js

// コードと言語別メッセージ辞書を分離する

const MESSAGES = {

ja: { VAL_001: (f) => `フィールド「${f}」は必須です` },

en: { VAL_001: (f) => `Field "${f}" is required` },

};

function createValidationError(code, field, locale = "ja") {

const message = MESSAGES[locale]?.[code]?.(field) ?? code;

const err = new Error(message);

err.code = code; // ローカライズされないコード自体はログ検索用に保持する

return err;

}

```

 

**使いどころ**: 将来的に複数言語での提供を見込むアプリケーション、または既に多言語対応が必要なプロダクト。エラーの識別には言語に依存しない`code`(KNOW-F-0103)を使い、ユーザーに見せる`message`だけをロケールに応じて切り替えることで、ログ・監視システム(コードで集計)とユーザー表示(メッセージで表示)の両方の要求を満たす。

 

**組合せ例**: KNOW-F-0103(エラーコードの体系設計)・KNOW-F-0104(エラーメッセージのテンプレート化)の両方を統合した発展形であり、本冊の第五章で扱ったエラー設計技法の集大成の一つにあたる。

 

**確認事項**: 罠は一部のエラーコードだけ翻訳辞書への登録が漏れ、特定の言語環境でのみ「コードがそのまま表示される」不具合が発生すること(本項の例では`?? code`のフォールバックがこれを防ぐが、根本的には登録漏れの機械検査〈全コード×全言語の網羅チェック〉が必要になる)。境界値として、`createValidationError("VAL_001", "email", "en")`が英語メッセージを、`locale`未指定の場合は`ja`が既定になることを確認する。

 

---

 

### KNOW-F-0121 タイムアウトエラーの設計

 

**構造の型**:

```js

function withTimeout(promise, timeoutMs) {

return Promise.race([

promise,

new Promise((_, reject) =>

setTimeout(() => reject(new Error(`operation timed out after ${timeoutMs}ms`)), timeoutMs)

),

]);

}

// 使用例: 5秒以内に応答がなければタイムアウトエラーとして扱う

await withTimeout(fetchData(url), 5000);

```

 

**使いどころ**: ネットワーク通信や外部プロセスの呼び出しのように、応答が返ってこない可能性がある処理すべて。何も対策しないと、応答を待ち続けて処理全体が無期限にハングする危険があるため、一定時間で強制的に失敗させ、KNOW-F-0106(リトライ設計)や代替処理につなげられるようにする。

 

**組合せ例**: KNOW-F-0106(リトライ設計)と組み合わせて「タイムアウトしたら一時的エラーとしてリトライする」設計にするのが典型であり、KNOW-F-0062(Promise/async関数の戻り値設計)の応用としてPromise.raceを使う技法を扱う。

 

**確認事項**: 罠は`setTimeout`で作ったタイマーを、`promise`側が先に完了した場合でもクリアし忘れ、不要なタイマーが残り続けること(本項の簡略版ではメモリリークの可能性がわずかに残るため、実務では`clearTimeout`を追加する発展形を検討する)。境界値として、`timeoutMs`より速く`promise`が解決した場合は正常な結果が返り、`timeoutMs`より遅い場合はタイムアウトエラーが先に投げられることの両方をテストで確認する。

 

---

 

### KNOW-F-0122 入力検証エラーと状態不整合エラーの型分け

 

**構造の型**:

```js

class ValidationError extends Error { // 入力そのものが不正(呼び出し前に分かる)

constructor(message) { super(message); this.name = "ValidationError"; }

}

class ConflictError extends Error { // 入力は正しいが現在の状態と矛盾する

constructor(message) { super(message); this.name = "ConflictError"; }

}

function reserveSeat(seatId, seatMap) {

if (typeof seatId !== "string") throw new ValidationError("seatId must be a string");

if (seatMap.get(seatId) === "reserved") throw new ConflictError(`seat ${seatId} already reserved`);

seatMap.set(seatId, "reserved");

}

```

 

**使いどころ**: 「入力の形式自体が不正(型・必須項目・範囲)」なエラーと、「入力の形式は正しいが、現在のシステムの状態と矛盾する(座席が既に予約済み、在庫が既にゼロ)」エラーを区別したい場面。前者はHTTPでいう400番台の「クライアントの入力ミス」、後者は409番台の「競合」に対応させるなど、扱いを分けることで呼び出し側の対処(入力をやり直す vs 最新の状態を再取得する)も変わる。

 

**組合せ例**: KNOW-F-0096(状態機械としての関数設計)の「不正な遷移」を報告する具体的なエラー型がConflictErrorにあたり、KNOW-F-0108(バリデーションエラーの集約)はValidationError側の複数化にあたる。

 

**確認事項**: 罠は2種類のエラーをどちらも同じ汎用`Error`で投げてしまい、境界層(KNOW-F-0113)で`instanceof`による適切なHTTPステータス振り分けができなくなること。境界値として、`reserveSeat(123, seatMap)`(数値、型不正)がValidationError、`reserveSeat("A1", 予約済みのseatMap)`がConflictErrorとして、それぞれ異なるエラー型で捕捉されることを確認する。

 

---

 

### KNOW-F-0123 エラーバジェット/フェイルセーフ的設計思想の関数への適用

 

**構造の型**:

```js

// フェイルセーフ: 個々のコンポーネントが失敗しても全体は安全な既定動作を続ける

function renderWidgets(widgets) {

return widgets.map((widget) => {

try {

return renderWidget(widget);

} catch (err) {

logger.warn(`widget ${widget.id} failed to render`, { error: err.message });

return renderFallbackWidget(widget.id); // 1つの失敗が全体を止めない

}

});

}

```

 

**使いどころ**: 複数の独立した処理単位(ウィジェット、プラグイン、外部サービス呼び出し)を集約する関数で、1つの失敗が全体の失敗につながってほしくない場面。個々の処理をtry-catchで包み、失敗した部分だけをフォールバック表示に差し替えることで、部分的な障害がシステム全体をダウンさせない設計にする。

 

**組合せ例**: KNOW-F-0107(ログとエラーオブジェクトの分離)・KNOW-F-0110(エラーの握りつぶし禁止、ここではログを残すことで「握りつぶし」でなく「意図的なフェイルセーフ」になっている点が重要)と組み合わせて安全に実装する。

 

**確認事項**: 罠はフェイルセーフを適用する範囲を誤り、本来は全体を止めて開発者に気づかせるべきprogrammer error(KNOW-F-0117)までフォールバック表示で隠してしまうこと(operational errorとの区別が本項の前提になる)。境界値として、`renderWidgets`に1つだけ壊れたウィジェットを含む配列を渡した場合、残りのウィジェットは正常に描画され、壊れたものだけがフォールバック表示になることを確認する。

 

---

 

### KNOW-F-0124 テスト容易性を高めるエラー設計(エラーを注入・検査しやすくする)

 

**構造の型**:

```js

// 依存を注入可能にし、テストで意図的に失敗させられるようにする

function createOrderService({ paymentGateway, inventory }) {

return {

placeOrder(order) {

if (!inventory.hasStock(order.itemId)) {

throw new ConflictError(`out of stock: ${order.itemId}`);

}

return paymentGateway.charge(order.total);

},

};

}

// テストコード側: 失敗するモックを注入してエラー処理を検証できる

const service = createOrderService({

paymentGateway: { charge: () => { throw new Error("gateway down"); } },

inventory: { hasStock: () => true },

});

```

 

**使いどころ**: エラー処理のコード(catch節、フォールバック処理)自体をテストで検証したい場面。外部依存(決済ゲートウェイ、DB)を直接呼び出す代わりに引数として注入する(依存性注入)ことで、テスト時に「意図的に失敗するモック」を渡し、正常系だけでなく異常系の挙動もテストできるようにする。

 

**組合せ例**: KNOW-F-0102(カスタムエラークラス)で定義したエラー型をテスト内で`instanceof`検証することが多く、KNOW-F-0055(Result型)を使っている場合はテストのアサーションが`result.ok === false`のような単純な形になり、さらにテストしやすくなる。

 

**確認事項**: 罠は依存を注入可能にする設計を怠り、外部APIを直接呼び出すコードのままではエラー時の挙動をテストで再現できず(本物のサービスをわざと落とすわけにはいかない)、エラー処理のコードが一度も実行されないまま本番デプロイされること。境界値として、`paymentGateway.charge`が失敗するモックを注入したテストで、`placeOrder`が投げる例外の型・メッセージが期待通りであることを確認する。

 

---

 

### KNOW-F-0125 エラー処理の一貫性チェックリスト(プロジェクト全体での統一)

 

**構造の型**:

```js

// 自己検査の疑似コード: プロジェクト全体のエラー処理規約への適合を点検する

function checkErrorHandlingConsistency(functionsList) {

const violations = [];

for (const fn of functionsList) {

if (fn.hasEmptyCatch) violations.push(`${fn.name}: 空のcatch節(KNOW-F-0110違反)`);

if (fn.throwsRawObject) violations.push(`${fn.name}: Errorでない値をthrow(KNOW-F-0102推奨違反)`);

if (fn.mixesResultAndThrow) violations.push(`${fn.name}: Result型と例外の混在(KNOW-F-0114違反)`);

}

return violations; // 空配列なら合格

}

```

 

**使いどころ**: 本冊第五章(KNOW-F-0101〜0124)で述べたエラー処理の技法群を、個々のレビューでの見落としに頼らず、プロジェクト全体で一貫させたい場面。命名の一貫性チェック(KNOW-F-0024)と対をなす、エラー処理版のチェックリストであり、lintルールや自動検査スクリプトへ落とし込むことを最終的な到達点とする。

 

**組合せ例**: 本項は本冊全体(第一〜五章、KNOW-F-0001〜0124)の締めくくりにあたる。命名(第一章)・引数(第二章)・戻り値(第三章)・制御フロー(第四章)・エラー処理(本章)という関数設計の五本柱すべてについて、個別の技法をチームの規約として明文化し機械検査可能にする、という同じ発想(KNOW-F-0024との対応)がここでも繰り返されている。

 

**確認事項**: 罠はチェックリストを作った時点で満足し、実際のコードベースに対する定期的な実行(CI組み込み等)を怠ること——KNOW-F-0024の確認事項で述べた「新ルール導入時の誤検知率確認」と同様、エラー処理チェックリストも導入初期は誤検知が出やすいため、段階的に厳格化する運用を確認する。境界値として、意図的に空catch節を1つ含むテスト用コードを`checkErrorHandlingConsistency`に渡し、確実に1件の違反として検出されることを確認する(検査ツール自身の自己検査)。

 

---

 

## 終章 基本形125種から先へ——制御・変換・堅牢化への一本道

 

ここまでの5章125項目は、いずれも1つの関数を設計するときに必ず通る4つの決定——「何と名付けるか(第一章)」「何を受け取るか(第二章)」「何を返すか(第三章)」「異常時にどう振る舞うか(第四・五章)」——を型として整理したものである。個々の項目は独立して読んでも成立するが(本大全の設計思想「段落独立請求項」)、実際の開発では複数の項目が同時に働く。

 

たとえば本冊のKNOW-F-0076(ガード節)・KNOW-F-0101(例外と戻り値の使い分け)・KNOW-F-0055(Result型)を組み合わせると、「引数を検証し(第二章)→異常系を早期returnで弾き(第四章)→成功/失敗を戻り値の型で統一的に表現する(第三章)」という、業務アプリケーションで最も頻出する関数の骨格が組み上がる。これは第二章から第五章までの技法が独立した部品でありながら、合成によってより大きな構造(BOOK-0184終章で扱った「合成・反復・分岐」の3操作)を作れることを実務コードの水準で確認したものである。

 

本冊で扱った基本形の先には、次の3つの方向への発展が待っている。

 

1. **制御と分岐の型(次巻BOOK-0358l)**: 第四章で基礎を示したガード節・早期return・状態機械の考え方を、ループの高度なパターン・複雑な状態遷移・イベント駆動設計へと拡張する。

2. **データ変換の型(BOOK-0358m)**: 第三章で扱った戻り値設計の考え方を、配列操作・写像/畳み込み(BOOK-0184の集約関数・畳み込み関数と接続)・文字列処理・数値精度の実務技法へと展開する。

3. **合成と堅牢化の型(BOOK-0358n)**: 本冊の全項目を「関数群」としてモジュール分割し、純粋関数化・テスト・デバッグ・計測へと接続する。KNOW-F-0124(テスト容易性)・KNOW-F-0125(一貫性チェックリスト)は、この次巻への最も直接的な予告にあたる。

 

脊椎対のBOOK-0358f(関数を正式に組む)では、本冊の技法がなぜ有効なのか——関数契約・純関数と副作用・参照透過性・「段落を崩しても通る」の解釈表——を原理から説明している。目録(本冊)で「どうやる」を身につけた後は、脊椎で「なぜ」を確認し、往復して理解を深めることを勧める。

 

---

 

## 参考: 本冊の構成情報

 

- 正式登録項目数: 125種(KNOW-F-0001〜KNOW-F-0125の全件に構造の型・使いどころ・組合せ例・確認事項の五点セット〈名称を含めれば五点〉を完備)

- 白カード(未執筆項目)数: 0種

- 章構成: 第一章 命名の技(KNOW-F-0001〜0025・25項目)/第二章 引数設計の技(KNOW-F-0026〜0050・25項目)/第三章 戻り値設計の技(KNOW-F-0051〜0075・25項目)/第四章 制御フローと早期returnの型(KNOW-F-0076〜0100・25項目)/第五章 例外とエラーメッセージ設計の技(KNOW-F-0101〜0125・25項目)

- コード例の方針: 全項目のコード例は依存ゼロ(外部ライブラリ不使用)の素のJavaScriptで統一し、多くの項目に`console.assert`または実行結果コメントによる簡易検算を併記した。

- 機械的検査: KNOW-F-0001〜0125のID連番に欠番・重複がないことを目次突合により確認済み(本文末尾の自己検査記録を参照)。

- 接続: 型見本=BOOK-0184(関数パターン目録I) / 脊椎対=BOOK-0358f(関数を正式に組む) / 次巻=BOOK-0358l(制御と分岐の型、KNOW-F-0126〜0250)。

- 安全枠の継承: 本冊はソフトウェアの関数設計のみを扱い、CATALOG_PC創造大全.md §3の安全枠(電気工事・PSU分解・OS実機導入・特許法務)には抵触しない。ここで示したコード例は教材用の簡略化であり、実運用のセキュリティ・パフォーマンス要件はプロジェクトごとに別途検討が必要である旨を明記する。

 

---

 

*本冊は関数設計の基本形125種について、名称・構造の型(依存ゼロのJavaScript断片)・使いどころ・組合せ例・確認事項(罠と検算・境界値)の五点セットを全項目に完備する形で執筆した。組合せ例で示した項目間の相互参照(KNOW-F-XXXX)は本文中の実在する項目にのみ張っており、BOOK-0184への参照(理-KAN-XXX)も同書に実在する項目にのみ対応させている。誇大な効能表現(「これで必ずバグがなくなる」等)は避け、各技法が防ぎやすくする問題の範囲を具体的なコード例と境界値の検算によって示す方針を一貫させた。実在しない研究者・論文・ライブラリの記載は行っていない。*

 

 




# BOOK-0358k PC創造大全 目録I 関数設計の基本形
  1. 目次
  2. 小説情報
  3. 縦書き
  4. しおりを挟む
  5. お気に入り登録
  6. 評価
  7. 感想
  8. ここすき
  9. 誤字
  10. 閲覧設定