Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
OSSのコードベースにneverthrowを漸進的に 導入して、AIにも人間にも優しい エラー...
Search
IkedaNoritaka
May 22, 2026
1.1k
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
OSSのコードベースにneverthrowを漸進的に 導入して、AIにも人間にも優しい エラーハンドリングを実現する
IkedaNoritaka
May 22, 2026
More Decks by IkedaNoritaka
See All by IkedaNoritaka
マルチテナントSaaSでのRLS導入に際し、並列でDevinを動かし高い品質のコードをパワフルにプロダクションへ反映させた事例
noritakaikeda
3
2.5k
Supabaseに支えられて可能となった AIコーディング時代の新しい開発プロセス 事例の紹介
noritakaikeda
2
410
機能的凝集の概念を用いて 複数ロール、類似の機能を多く含むシステムの フロントエンドのコンポーネントを適切に分割する
noritakaikeda
16
7.7k
Featured
See All Featured
Un-Boring Meetings
codingconduct
0
310
The SEO identity crisis: Don't let AI make you average
varn
0
480
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.2k
Neural Spatial Audio Processing for Sound Field Analysis and Control
skoyamalab
0
320
AI Search: Where Are We & What Can We Do About It?
aleyda
0
7.6k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.1k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.8k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.7k
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
160
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
160
A Soul's Torment
seathinner
6
2.9k
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
0
530
Transcript
OSSのコードベースに neverthrowを漸進的に 導入して、 AIにも人間にも優しい エラーハンドリングを実現する 株式会社ROUTE06 IkedaNoritaka 2026/05/22 TSKaigi 2026
・NoritakaIkeda ・X(Twitter): @omotidaisukijp ・ROUTE06 Acsim事業部 ・フロントエンド寄りのフルスタック ・TSKaigi2024ではLTで登壇、TSKaigi2025 では機能的凝集度の話をしました 自己紹介 2
はじめに OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する
クイズ — どの関数がエラーになる可能性がある ? 以下のシグネチャを見て、エラーになりうる関数はどれ ? 3 1. neverthrowとは OSSのコードベースに
neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する ① fetchUser ② calculateTax ③ saveOrder ④ わからない ⑤全ての箇所
答え 4 1. neverthrowとは OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する ④シグネチャからは わからない TypeScript
では、失敗の可能性は型に出ない - fetchUser / calculateTax / saveOrder の3つすべて throw する可能性がある - 戻り値の型 (User / Money / OrderId) からは失敗の可能性が読めない - → 今日はこの「シグネチャだけではわからない」状態を直す話
今日話すこと neverthrowを用いて、 AIにとっても人間にとっても読みやすいエラー設計を目指す - Result型は、失敗した型を定義できるので、エラーを握り潰さない - .andThen() チェーンによって、逐次処理のコードの可読性が上がる - チームでよく議論し、学習コストを乗り越える
- AIのモデルが進化し、 AIに過剰なガードレールをしかずに neverthrowを使える neverthrowを導入したことで、 - AIが安易にエラーを握りつぶさないため、デバッグが用意になり、開発が楽になった 5 はじめに OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する
目次 - neverthrowとは: - Result型で失敗の型をシグネチャに出す - なぜResult型が必要な場面があるのか - 実際のプロジェクトに導入した際の Tips:
- AIによる漸進的な導入を行う - チームで理解を深める - .andThen() チェーンが使える場所を見極める 6 はじめに OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する
1. neverthrowとは なぜResult型を使うのか 7
neverthrowとは 関数の失敗を throw ではなく戻り値として返すことで、エラーの可能性を型に出すライブラリ。 - throw する代わりに Result<T, E> を返す
- Result 型は Rust など多くの言語で採用されているエラー表現パターン 8 1. neverthrowとは OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する
Result型とは Result<T, E> は、成功なら T、失敗なら E のどちらか一方が必ず入っている値 - ok(value) で成功、err(error)
で失敗 を作る - 値を取り出すには必ず match や andThen を呼ぶ - 非同期処理 (Promise) を Result として扱える ResultAsync<T, E> 9 1. neverthrowとは OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する
なぜResult型が必要な場面があるのか try/catch では「失敗の可能性」「失敗の 種類」が型に出ない - throw は goto 的、catch の引数の型は
unknown - 握りつぶしが書きやすい (catch {} / return null) - 呼び出し側、 AI、半年後の自分が困る 10 1. neverthrowとは OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する
2. 実際のプロジェクトに導入した際の Tips Result型を使った運用と成果 11
我々のプロジェクトで必要だった場面 プロジェクト : Liam - ERD可視化ツール https://liambx.com/ - DB設計エージェント ←
本日はこっちのプロダクト対象 12 2. 実際のプロジェクトに導入した際の Tips OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する
我々のプロジェクトで必要だった場面 liam にも、握りつぶしによる苦しみが実際にあった - 実例① 5種類の失敗が全部 null で返る関数 - 実例②
JSON.parse と バリデーション失敗が同じデフォルト 13 2. 実際のプロジェクトに導入した際の Tips OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する
実例① — 5種類の失敗が全部 null で返る downloadFileContent: 戻り値が Promise<string | null>
- 失敗パターンは 5種類あるのに、全部 null で返している - console.error は出すが、呼び出し側からは 原因が見えない - 「動くけど、不具合が出た時に原因不明」 14 2. 実際のプロジェクトに導入した際の Tips OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する 📎 github.com/liam-hq/liam/.../github/src/api.server.ts
実例① — Result化後の変化 戻り値を Promise<Result<string, Error>> に 変える - すべての失敗が
Error として返る - 呼び出し側は match で失敗の理由が読め る - スタックトレース・原因が保持される - 例だと省略しているが、エラーごとに型を変 えられる 15 2. 実際のプロジェクトに導入した際の Tips OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する 📎 github.com/liam-hq/liam/.../github/src/api.server.ts
実例② — JSON parse と検証失敗が同じ空デフォルト JSON.parse 失敗 と スキーマ検証失敗 を同じ空
デフォルトで返していた - 呼び出し側は「 JSONが壊れている」か 「Liam形式じゃない」か区別できない - 16 2. 実際のプロジェクトに導入した際の Tips OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する 📎 github.com/liam-hq/liam/.../schema/src/parser/liam/index.ts
実例② — Result化後の変化 JSON.parse 失敗 と スキーマ検証失敗 を同じ空 デフォルトで返していた -
parseJson.andThen(parseSchema) で段 階を分離 17 2. 実際のプロジェクトに導入した際の Tips OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する 📎 github.com/liam-hq/liam/.../github/src/api.server.ts
AIによる漸進的な導入を行う 全置換は失敗する。 4ステップで段階的に進めた - ① 自前ラッパー @liam-hq/neverthrow を作る - ②
1〜2パッケージで人間が代表例を書く - ③ AI (Devin) に他パッケージへ横展開 - ④ ESLint で後戻り禁止 18 2. 実際のプロジェクトに導入した際の Tips OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する // configs/eslint/no-throw-error-plugin.js ThrowStatement(node) { if (node.argument?.callee?.name === 'Error') { context.report({ message: 'Use neverthrow Result types instead.', }) } } // configs/eslint/base.js 'no-restricted-imports': ['error', { paths: [{ name: 'neverthrow', message: 'Use @liam-hq/neverthrow instead' }], }] 📎 github.com/liam-hq/liam/.../configs/eslint/no-throw-error-plugin.js
エラー型を Errorに統一した薄いラッパーパッケージの設計 @liam-hq/neverthrow は本家を薄く包んだ自前パッケージ - 主目的は OSS 公開時の依存パッケージ集約 - defaultErrorFn
を自動で当てて unknown 漏れを防ぐ - import 先が一意になり、 AI に指示が出しやすい 19 OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する // @liam-hq/neverthrow/src/fromPromise.ts export function fromPromise<T>( promise: Promise<T>, errorFn?: (error: unknown) => Error, ) { return ResultAsync.fromPromise( promise, errorFn ?? defaultErrorFn, // ← unknown 漏れを防ぐ ) } // defaultErrorFn.ts export const defaultErrorFn = (error: unknown): Error => error instanceof Error ? error : new Error(String(error)) 📎 github.com/liam-hq/liam/.../neverthrow/src/fromPromise.ts 2. 実際のプロジェクトに導入した際の Tips
実験 — シグネチャと Skill が AI 生成コードに与える影響 同じ機能を Claude Code
に書かせて 2 パターン比較した - 共通: countDependencies (package.json の依存数を数える関数 ) - A: throw/null 返しの API (getFileContent) を使わせる - B: Result 返しの API (downloadFileContent) + チーム作法 Skill - プロンプトは同一 / 検証目的は AI に伏せる / PR #4096 #4097 20 1. neverthrowとは OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する
結果 — AI 生成コードの 4 つの質的変化 シグネチャ + Skill で
AI が書くコードの「形」が変わる 21 1. neverthrowとは OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する 観点 A (throw/null) B (Result + Skill) ① .andThen チェーン なし (手続き型 if文) 5 ステップ連鎖 (動詞が並ぶ) ② 手動 narrowing (typeof/null/'in') 4 段 0 段 (valibot で代替) ③ JSON.parse の扱い try/catch fromThrowable で包む ④ 失敗の原因情報 固定文字列に縮約 cause で元エラー保存 ⑤実際のPR https://github.com/liam-hq/liam/pull/4096 https://github.com/liam-hq/liam/pull/4097
コードの劇的な変化 — 動詞が並ぶ宣言型へ A: 早期 return と手動 narrowing の連続 22
1. neverthrowとは OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する
コードの劇的な変化 — 動詞が並ぶ宣言型へ B: .andThen で動詞が並ぶ 23 1. neverthrowとは OSSのコードベースに
neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する
チームで理解を深める Lint をすり抜ける誤用は必ず起きる。ペアプロで一 個ずつ直す - isErr() で if 文の山にしてしまう -
Result を返しているのに中で throw を呼んで しまう 24 OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する // Liamの実際のコード async function readTokenFrom(name: string): Promise<TokenPayload | null> { const raw = (await cookies()).get(name)?.value if (!raw) return null const plaintext = unpackCookieValue(raw) if (plaintext.isErr()) return null // ← 陥りがち const payloadJson = parsePayload(plaintext.value) if (payloadJson.isErr()) return null // ← 陥りがち // ... if 文の山 } 📎 github.com/liam-hq/liam/.../app/libs/github/cookie.ts 2. 実際のプロジェクトに導入した際の Tips // 修正後: andThen でチェーンに return unpackCookieValue(raw) .andThen((plain) => parsePayload(plain)) .andThen((json) => fromValibotSafeParse(TokenPayloadSchema, json))
誤用例 — Result を受け取って throw に戻してしまう Result の世界は境界まで運ぶ。途中で throw に戻すと型が
嘘になる - AIがやりがち : `if (result.isErr()) throw result.error` で Result を破壊 - 正しい: そのまま Result で返すか、 `.andThen` でつなぐ - 境界で throw が必要なら eslint-disable + 理由コメントを書 く 25 OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する // ❌ やりがちな誤用 function processOrder(id: string): Result<Order, Error> { const orderResult = fetchOrder(id) if (orderResult.isErr()) { throw orderResult.error // Result を返すと宣言してるのに throw } return ok(orderResult.value) } // ✅ 正しい: Result をそのまま流す (境界まで開かない) function processOrder(id: string): Result<Order, Error> { return fetchOrder(id) } // ✅ 境界で開く時だけ throw に変換 (eslint-disableで意図明示) // eslint-disable-next-line no-throw-error/no-throw-error -- LangGraph retry needs throw if (result.isErr()) throw result.error 2. 実際のプロジェクトに導入した際の Tips
.andThen() チェーンが使える場所を見極める Result は全ての場所に向いてはいない。刺さる場所を見極め る - 【刺さる】複数ステップが順に並ぶビジネスロジック - 【刺さらない】 DOM操作・リソース管理・フレームワーク
制御フロー - 「内側 Result / 外側 throw / 境界でラップ」が基本 26 OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する // ✅ 刺さる: ビジネスロジックの連鎖 return validateInput(raw) .andThen(checkUserExists) .andThen(hashPassword) .andThen(saveToDb) .andThen(sendWelcomeEmail) // → 成功パスが上から読み下せる、失敗の種類で分岐できる // ❌ 刺さらない : DOM副作用の連鎖 return updateHeader(data) .andThen(() => updateBody(data)) // header失敗で body も スキップ? .andThen(() => updateFooter(data)) // 本来は部分成功 OKなはず // → 副作用は andThen で繋ぐ意味がない、 try/catchで個別に 2. 実際のプロジェクトに導入した際の Tips
.andThen() と isErr() early return の使い分け どちらも Result の短絡だが、向き不向きがある -
チェーンが効く : 純粋な変換が並ぶ、中間値を使わない - early return が効く: 中間値を使う、 async混在、副作 用を挟む 27 OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する // ✅ チェーンが効く : 純粋な変換が並ぶ return validateInput(raw) .andThen(checkExists) .andThen(save) // ✅ early return が効く: 中間値を両方使いた い const r1 = await fetchOrder(id) if (r1.isErr()) return r1 const r2 = await fetchUser(r1.value.userId) if (r2.isErr()) return r2 return ok({ order: r1.value, user: r2.value }) // ← 両方の値を返す 2. 実際のプロジェクトに導入した際の Tips
今日話すこと neverthrowを用いて、 AIにとっても人間にとっても読みやすいエラー設計を目指す - Result型は、失敗した型を定義できるので、エラーを握り潰さない - .andThen() チェーンによって、逐次処理のコードの可読性が上がる - チームでよく議論し、学習コストを乗り越える
- AIのモデルが進化し、 AIに過剰なガードレールをしかずに neverthrowを使える neverthrowを導入したことで、 - AIが安易にエラーを握りつぶさないため、デバッグが用意になり、開発が楽になった 28 はじめに OSSのコードベースに neverthrowを漸進的に導入して、 AIにも人間にも優しいエラーハンドリングを実現する