Failures We Don't Model Correctly
Not every failure is an error; failures are violations of contracts between parts of a program, and the chosen error pattern should communicate who owns that violation.
重點摘要
Treat failures as contract violations: preconditions, postconditions, failure semantics.
Choose OrThrow/OrNull/OrElse/try* based on boundary and ownership of the failure.
Avoid broad catching; let failures propagate to the boundary that can handle them.
The essay reframes errors as contract violations between a function and its caller, defined by preconditions, postconditions, and failure semantics. It categorizes violations into user input (expected, handled with safe-first APIs), programmer errors (internal bugs that should surface), and environmental failures (I/O, network, hardware that need explicit handling). Kotlin’s standard library and kotlinx.coroutines offer patterns—OrThrow, OrNull, OrElse, try*—which communicate different ownership and expectations. The correct choice depends on the boundary: trusted internal code can reasonably throw on broken assumptions, while untrusted inputs or external systems benefit from type-safe results. The author warns against false safety: broadly swallowing exceptions hides real problems. Instead, catch only well-understood cases, let other errors travel to the boundary that can interpret them, and reserve unsafe variants as deliberate, opt-in choices. Thoughtful API design should make failure semantics explicit, not implicit.
我们未正确建模的失败
并非所有失败都是错误;失败通常是程序各部分之间合约的违反,错误处理方式应明确谁对该违反负责。
重點摘要
以合约为中心:前置条件、后置条件与失败语义。
根据边界与责任选择 OrThrow、OrNull、OrElse 或 try* 模式。
不要泛用捕获异常,让错误流向能处理的边界。
本文将错误重构为函数与调用者之间的合约违反,定义为前置条件、后置条件和失败语义,并区分使用者输入(可预期、应以安全优先处理)、程序员错误(内部 bug,应尽快显现)与环境性失败(I/O、网络、硬件等,需要显式处理)。Kotlin 标准库与 kotlinx.coroutines 提供 OrThrow、OrNull、OrElse 与 try* 等模式,用以表达不同的责任与期望。关键在于识别边界:受信任的内部数据可通过抛出异常来表明违约,而不受信任或外部来源应返回类型安全的失败结果。作者警示避免“虚假的安全感”——广泛吞掉异常会掩盖真实问题;应仅对明确且可接受的错误进行选择性忽略,并让其他错误传播到能够处理与评估它们的边界。
我們未正確建模的失敗
不是每種失敗都是錯誤;失敗通常是程式各部分之間合約的違反,而錯誤處理模式應該傳達誰為此負責。
重點摘要
以合約思維處理:前置條件、後置條件與失敗語意。
根據邊界決定使用 OrThrow、OrNull、OrElse 或 try*。
避免廣泛吞掉例外,讓錯誤傳到能處理的邊界。
本文主張把錯誤視為函式與呼叫端之間的合約違反,並以前置條件、後置條件與失敗語意來描述合約。文章將違約來源分為使用者輸入(可預期、應以安全優先處理)、程式設計錯誤(內部 bug,應讓其顯現)與環境失敗(I/O、網路、硬體等需明確處理)。Kotlin 標準庫與 kotlinx.coroutines 提供 OrThrow、OrNull、OrElse 與 try* 等模式,分別表達不同的責任與預期。重點在邊界判斷:受信任的內部資料可直接以拋例外表示違約,而不受信任或外部資料則應以型別安全的失敗回傳。作者警告不要以廣泛捕捉例外換取虛假的安全,應僅忽略特定可接受的錯誤,並將其他錯誤傳遞到能賦予其意義的界面。