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
エラー処理の温故知新 / history of error handling technic
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
nakaryo
May 01, 2026
Programming
2k
7
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
エラー処理の温故知新 / history of error handling technic
nakaryo
May 01, 2026
More Decks by nakaryo
See All by nakaryo
Ruby で gRPC を使おう / ruby-grpc
ryotanakaya
1
140
ギフティの技術ブログ 再出発とこれから / restart of giftee tech blog 2024
ryotanakaya
0
350
再利用パターン / Pattern of code reuse
ryotanakaya
0
200
エンジニアリングエッセイのススメ
ryotanakaya
0
510
ソフトウェアアーキテクチャについて 語るときに 僕の語ること
ryotanakaya
2
1.7k
エンジニアと要件定義
ryotanakaya
4
1.2k
Go と並行処理
ryotanakaya
0
410
ワクワク!Rubyクイズ!!
ryotanakaya
0
1.6k
増え続けるトランザクションデータと向き合う
ryotanakaya
0
550
Other Decks in Programming
See All in Programming
技術記事、 専門家としてのプログラマ、 言語化
mizchi
13
5.9k
Inside Stream API
skrb
1
710
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
320
「なぜそう決めたのか」を残し続ける仕組み ― Notion AI カスタムエージェント × Slack連携による設計判断の自動記録 - NIKKEI Tech Talk #47
niftycorp
PRO
0
170
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
2
650
Javaの型とAI時代に型が大事な理由 / java types and type in AI era
kishida
2
130
Skillsは効率化、Agentsは"自分の拡張"——Builder時代のエージェント編成(CC Night 2026)
wemra
1
130
Snowflake Summitでの新機能 CoCo / CoWork / snowflake-summit-2026-overall-what-new-coco
tatsuhiro
1
130
脅威をエンジニアリングの糧にして――現場編 / Turning Threats into Engineering Fuel — Field Edition
nrslib
0
280
「エンジニアインターン、どうやって取った?」準備のリアルを語るLT会 Progate BAR
akiomatic
0
130
肥大化するレガシーコードに立ち向かうためのインターフェース分離と依存の逆転 / JJUG CCC 2026 Spring
hirokunimaeta
0
550
DynamoDBには集計系のクエリがないけどなんとかしたい
musan
1
140
Featured
See All Featured
The Pragmatic Product Professional
lauravandoore
37
7.3k
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
840
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
1.7k
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
Why You Should Never Use an ORM
jnunemaker
PRO
61
9.9k
Optimizing for Happiness
mojombo
378
71k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
160
How to train your dragon (web standard)
notwaldorf
97
6.7k
Building the Perfect Custom Keyboard
takai
2
790
Paper Plane
katiecoart
PRO
1
51k
Unsuck your backbone
ammeep
672
58k
Transcript
エラー処理の温故知新 エラー処理の温故知新 エラー処理の温故知新 エラー処理の温故知新 Nakaya Ryota 2026.05.01 giftee TechBash 1
自己紹介 なかりょー @ 株式会社ギフティ バックエンドエンジニア ▸ 前職はバックオフィス ERP ベンダーで上流メイン ▸
Go / Ruby / Java ▸ AI に翻弄される今日この頃 ▸ 2
みなさん、エラー処理やってますか? 3
プログラムは必ず失敗する 人間と同じで、プログラムも必ず失敗する ▸ ファイルがない ▫ ネットワークが落ちる ▫ 入力値が不正 ▫ NULL
ポインター ▫ 型が食い違う ▫ etc... ▫ 様々な理由でエラーは発生する ▸ 4
そもそもエラーとは何か エラーとは、プログラムの期待と現実のギャップである ▸ 「このファイルは存在するはず」 → なかった ▫ 「この値は正の整数のはず」 → 負の値だった
▫ 「このサーバーは応答するはず」 → タイムアウトした ▫ つまり、プログラムが置いた前提や仮定が崩れた瞬間がエラー ▸ 前提は必ずどこかで崩れる — だからエラー処理が必要になる ▸ 5
ドメインエラー vs 非ドメインエラー ドメインエラー 非ドメインエラー 入力値が不正 ▸ 実行の前提条件が満たされていない ▸ 認証・認可の失敗
▸ etc ▸ メモリ不足(OOM ) ▸ ネットワーク障害 ▸ NULL ポインター参照 ▸ etc ▸ 6
エラーハンドリング、どう書いていますか? 各言語がどんな答えを出してきたのか、歴史を振り返りながら考えてみましょう プログラムを書くとは、エラーハンドリングを書くことでもある ▸ 皆さんはエラーハンドリングをどのように書いていますか? どのようなことを意識していますか? ▸ Ruby だと Exception
を使うのが常識になっていますよね? ▸ Exception を体系的に設計できていますか? ▫ 7
C 言語の時代 8
C 言語の時代 — エラーは値だった if (open(...) < 0) { perror("open");
} C 言語と Unix 哲学の世界 ▸ エラーというのは値だった → プログラムのロジックで処理するもの ▸ 関数やプログラムは成功・失敗を数値で表現する ▸ 0 なら正常、0 以外なら異常 ▫ ✔ シンプル ▸ ✘ 戻り値をチェックし忘れるリスクがある ▸ ✘ 正常系と異常系が混ざる ▸ 9
Exception の時代 10
Exception の時代 try { readFile(); } catch (IOException e) {
... } C++ 、Java 、Python 、Ruby など現代主流の言語に見られる ▸ 例外機構自体はもっと以前からあったが、90 年代の言語が普及に寄与 ▫ ✔ 正常系と異常系のフローを分けて書ける ▸ ✔ 大域脱出するため、チェック漏れのリスクがない ▸ 11
Exception の課題 どこでどういう例外が発生するのかを把握するのが難しい ▸ 関数定義をパッと見ただけではわからない ▫ プログラム全体を見ないと、どこで何がハンドリングされているのかわからない ▫ → 設計難易度が高い
▫ 結果、別の形のリスクが生まれる ▸ スローされたまま誰もキャッチしない ▫ 意図せず握りつぶされる ▫ 12
Java の検査例外 void foo() { bar(); // HogeException をキャッチするかスローしないとコンパイルエラー }
void bar() throws HogeException { ... } ✘ コンパイルエラー — foo() は HogeException を処理していない 関数がどういう例外をスローしうるかをシグネチャで表現する ▸ 13
Java の検査例外 — 正しい記述 A. キャッチして処理する void foo() { try
{ bar(); } catch (HogeException e) { // ここで回復処理 } } B. スローを伝播する void foo() throws HogeException { bar(); // 呼び出し元に責任を委譲 } どちらかを選ばないとコンパイルが通らない → 処理漏れを防ぐ ▸ 14
検査例外のトレードオフ 伝播コストがかかる ▸ 全員がキャッチ・スローを書いて伝播させなければならない ▫ ラップしてリスローするコードが至るところに生まれる ▫ API 変更に弱い ▸
例外の種類を増やすと、呼び出し側全員がキャッチを書く必要がある ▫ 高階関数やラムダ式、関数型記法との相性が悪い ▫ 失敗可能性を明示することと、失敗から回復できることは別問題だった ▸ 15
現代の別解:Go のエラーハンドリング 16
技術の進化は螺旋 f, err := os.Open("file.txt") if err != nil {
return err } 2009 年に生まれた Go は、エラーを値として返すという 古典的な方法をあえて選んだ ▸ 17
Go の思想 "Errors are values (エラーは値である)" — Rob Pike go.dev/blog/errors-are-values
- Why does Go not have exceptions? — Go FAQ - 「例外」がないからGo 言語はイケてないとかって言ってるヤツが本当にイケてない件 例外は使わない(panic はあるけど、回復不能な異常時のみ) ▸ エラーは「摩訶不思議なもの」でも「例外的なもの」でもない ▸ ファイルがない・入力値がおかしいのは日常的な事象 ▫ だから特別な制御構造(例外)ではなく、通常の値として扱うべき ▫ 常にその場で処理するか、呼び出し元に返す ▸ 「魔法を減らせ」 ▸ 18
なぜ値リターンに戻ったのか Exception はシグネチャに現れず、どこで何が飛ぶかわからない ▸ デバッグが難しい — throw 元と catch 先が離れがち
▸ "Cleaner, more elegant, and wrong" — Raymond Chen ▫ 制御フローが追いにくい — 暗黙の大域脱出が隠れている ▸ ドメインエラーと非ドメインエラーの使い分け ▸ ドメインエラー:予期される事象 → 制御構造(ロジック)で扱う ▫ 非ドメインエラー(OOM, NPE ) :制御できない → 大域脱出 ▫ 異なる性質の事象なので、対処方法を明示的に使い分ける ▫ そもそも goto 文はマジカルでよくないと教わったのに、 例外だけ例外的に扱うのどうなん? ▸ 19
オフトピック:Clean Code の見解 『Clean Code 』の中でボブおじは、 値リターンはコードの可読性を下げるからお勧めしないと書いている ▸ 正常系がストレートに読める方がコードの意図が掴みやすい ▸
ただし、イディオムの違いによる可読性は宗教論争になりがちで、 これもご多分に漏れない ▸ 20
エラーを型で扱う時代 21
エラーを型で扱う fn read_file() -> Result<String, Error> Rust 、Haskell 、Scala 、Swift
、Kotlin など ▸ 成功すれば String が、失敗すれば Error が返る。それ以外はありえない ▸ 失敗する可能性が型に現れる ▸ 値(データ)ではなく型(プログラムの構造)として表現 ▫ 値はハンドリングしなくても良いが、型はハンドリングを強制する ▫ 22
値として扱う vs 型として扱う Go — 値は無視できる f, err := os.Open("file.txt")
// err を無視しても // コンパイルは通る doSomething(f) Rust — 型は強制する let result = read_file(); // Result を開かないと // 中身を使えない do_something(result); // 型エラー 値はチェックするもしないも開発者の自己責任 ▸ 型はコンパイラが処理を強制する — うっかり無視できない ▸ 23
Result 型のハンドリング match read_file() { Ok(content) => println!("{}", content), Err(e)
=> eprintln!("Error: {}", e), } match で全パターンを網羅しないとコンパイルエラー ▸ Ok だけ書いて Err を省略 → コンパイルエラー ▸ 「処理し忘れ」がそもそも起こりえない構造になっている ▸ ただし、意図的に捨てることは可能( let _ = read_file(); ) ▸ Java の検査例外と違い、どの階層で処理するかは開発者が自由に選べる ▸ 24
型によるエラー表現の特徴 うっかり無視はできないが、意図的に捨てることはできる ▸ Java の検査例外:各階層に「処理 or 宣言」を強制 ▫ Rust の
Result :失敗の可能性を示すが、どこで処理するかは自由 ▫ ✔ コンパイラが処理漏れを検出できる — 例外より明示的 ▸ ✔ エラーを合成でき、関数型とも相性が良い ▸ ✘ 記述量は増えることもある ▸ 25
まとめ エラー処理に銀の弾丸はない — だからこそ面白い エラー処理の仕組みと思想は言語ごとに異なる ▸ 最近の言語トレンドはエラーを型で表現する方向へ ▸ それぞれの特性を理解して、正しく向き合おう ▸
26