假设我正在编写一个库,该库以某种格式将一个doubles序列存储到一个文件中。这种格式要求双打是单调增加的。
现在,一些用户不会仔细阅读手册,也不会编写类似的bug前端
store(3.0)
store(3.1)
store(0.3)
store(7.8)
图书馆能做的就是
- 调用
store(0.3)
时出错 - 试着通过正确的猜测来纠正错误,例如,实际上是
store(3.3)
- 更正错误并向
stderr
写入消息 - […]
(1)的优点是用户不会错过它。不过,如果代码运行很长时间(在我的上下文中这是常见的情况),用户不会对程序中止感到太高兴。(2) 会消除这种情况,但可能会鼓励滥用图书馆。
是否有任何语言的政策主张一种方法胜过另一种方法?
无论使用何种语言,我的一般建议是始终快速失败。这将错误定位到问题的实际来源,即抛出错误或异常并退出(可能允许程序员捕捉异常,具体取决于语言)。类似地,一些带有已检查异常的语言可能会迫使程序员添加对格式错误的输入的检查。
原因很简单——错误显示的问题的实际来源越远,程序就越难调试。假设程序员的意思不是3.3
(而不是0.3
),你帮他纠正了它——好吧,程序会继续运行,但在某个时候3.3
的值会显现出来,并可能导致其他问题。也可能是这些值的来源是某种有错误的排序算法——在这种情况下,库不会失败,这只会使调试排序算法和确定失败的真正原因变得更加困难。
它还与任何对代码进行单元测试的尝试打交道——应该失败的代码不一定会在正确的地方失败。这只会让代码变得神奇,而且作为开发过程的一部分,管理起来更加困难。
除了简单地失败并迫使用户或客户端程序重新启动交互之外,还有一种选择——您可以以事务方式进行操作,使库在失败后保持一致状态,允许用户从最后一个有效输入开始(例如)。不过,这应该使用适当的回滚语义来实现,以确保数据的一致性。
总之:失败要快,失败要早。