“Dying is Awesome”更受青睐吗?

时间:2009-02-23 04:33:18

标签: .net exception architecture exception-handling crash

最近我参加了Jeffrey Richter关于.NET的培训课程。他提到了一种编码“死亡很棒”的策略。也就是说,即使在程序或事件循环的根部也不要写“catch(Exception ex)”。如果抛出一些未处理的异常,只需让进程死掉。

我不确定这是对的。就个人而言,我更喜欢将“try {...} catch(Exception ex) {log and try to recover}”包装在最高级别的执行中。实际上,如果从asXx抛出任何异常,ASP.NET不会死亡。如果它因异常而死亡,那么一个银弹请求可能会使整个服务无效。

您怎么看?

16 个答案:

答案 0 :(得分:37)

我认为这取决于您运行的应用程序类型以及“死亡”的后果。对于许多客户端应用程序,死亡是很棒的。对于服务器,通常不是那么多(并且吞咽和日志是合适的)。没有一个通用的解决方案。

答案 1 :(得分:22)

也称为进攻性编程。

您应该查看“Offensive Programming: Crash Early, Crash Often”。

这是一种与Defensive Programming的标准完全不同的意识形态:

  

[防御性编程]旨在   确保a的持续功能   一块软件尽管如此   不可预见的使用该软件。

我个人喜欢“早期崩溃,经常崩溃”的理念。

我见过太多了:

try  
{  
    // ... Huge block of code goes here  
}  
catch(Exception ex)  
{  
   // Do nothing...  
}  

这比崩溃更糟糕。如果处理异常,那么一点点防御性编程就可以了。

答案 2 :(得分:8)

这一切都取决于你如何处理异常。如果只在发生真正异常的事件时抛出异常(而不是在数据库查询没有返回结果或者格式不正确时),那么你真的不需要捕获异常。由于您的程序无法恢复,因此您可以从中恢复的任何内容都不是例外,而是错误。

答案 3 :(得分:8)

听起来像Guruspeak

这听起来像是 gurus 所宣传的另一个通用指南,这本身并不是一个糟糕的建议。但是,该指南可以很容易地应用于不属于它的地方。我认为上面用过的关键词是“编码策略”,因为这种策略在某些领域非常有用,但在其他领域却非常有用。

死亡 非常棒 - 如果你有许多紧密耦合的组件,其状态相互依赖,那么异常很容易就是一个灾难性的事件。但是,您的目标之一应该是以一种单一故障不必降低整个系统的方式进行编码(通知目标)。

您如何看待以下应用程序死于普通例外:

  • 医疗器械
  • 发电厂
  • 入侵检测系统

对于你在try / catch中捕获的异常 - 你真的应该期待它们并处理它们。对于所有其他情况,最好快速失败到预测的运行级别。那么,如果你在网络或网络处理程序,为什么不让当前的操作死?你真的需要整个应用程序下载吗?

如果您正在开发一个关键任务且具有公共界面的应用程序,这将变得越来越重要。如果有可用的例外情况可能会导致应用程序崩溃,那么这会成为黑客黑客攻击的一种攻击方式,意图导致拒绝服务攻击。

滥用这种策略的边缘情况有点太大,不值得赞扬。更好的方法是解决您的域名问题。了解这个状态正在发生什么,并将适当的部分应用到您的问题。

警告:我在服务器端系统上工作,正常运行时间和安全性至关重要。

编辑:我想我对“进程模具”的含义感到困惑 - 这是对整个应用程序或运行线程的引用等吗?

答案 4 :(得分:8)

Karl Seguin说明了以下关于异常处理的内容:

  1. 仅处理您可以实际执行某些操作的异常
  2. 您无法对绝大多数例外做任何事情
  3. 该主题的介绍。

答案 5 :(得分:6)

这是非常微软的。

MS希望您将所有未处理的异常抛给WER。 (Windows错误报告,它是您在应用程序崩溃时将错误发送到Microsoft的对话框)

通过这种方式,您可以获得使用指标,并可以专注于导致客户悲痛的关键未处理异常。我相信这个想法会迫使你去思考例外的来源。

但我完全同意你的看法。即使你重新抛出之后,你总是会在根处捕获未处理的,记录发生的事情。唯一的问题是如果你的未处理的ex是内存不足,在这种情况下你的日志调用可能会失败,因为JIT不能分配更多的内存等。我认为C ++程序通过占用内存泡来解决这个问题,在未处理的异常上释放它,然后运行非常严格的日志例程以尝试优雅地失败。

答案 6 :(得分:3)

我不熟悉里希特的材料,但我认为理念/理由是,在绝大多数情况下,程序无法从未处理和意外的异常中恢复。

然而,让程序在用户面前死去并不是一个好主意 - 它留下了非常糟糕的印象。我更喜欢将未处理的异常记录到数据库,通知开发人员,并跟踪它们以确保它们得到修复。

然后,我再次出售一个产品,所以我在这方面有点偏颇!

答案 7 :(得分:3)

如果你不能充分地处理这个问题 - 如果除了拒绝某种形式的错误输入(这包括你试图从磁盘或网上读取的东西)之外的任何东西你可能都不能 - 那么你应该死。除非你100%确定你可以安全地继续,否则不要。

但是,我不会简单地让一个例外。抓住它并收集尽可能多的信息。如果您的程序操作某种文档,将其保存为在新名称下 - 它可能已损坏,您不想覆盖原始文档。

答案 8 :(得分:2)

没有什么比堆栈跟踪更快地破坏用户信心。至少,捕获异常并记录尽可能多的信息。然后向用户提供友好的消息以及如何解决问题或报告要支持的问题的说明。

这里有人担心继续处于不确定的状态。如果这是一个Web应用程序,那么除非您过度依赖会话和应用程序状态,否则这不是问题。如果这是一个Windows应用程序,则可以随意退出(在给予用户保存的机会之后)。

答案 9 :(得分:2)

由于你不知道Exception的每个子类是什么,你根本不知道捕获它们是可以的。因此,您应该关注自己的业务:捕获您知道和关心的异常,这些异常主要是您为自己的程序明确创建的异常,或者是为您正在使用的库调用创建的异常。特别是,捕获Exception类只是懒惰,糟糕的编程 - 基本上,你说“我不关心问题是什么,不要告诉我;只是这样做。”看看java程序如何处理异常,因为异常处理实践通常很不错。

答案 10 :(得分:1)

您的客户期望什么?

这一切都回到了那一步。如果客户可以处理程序死亡并且可以重新启动它,那就这样吧。

有时候,最好让一个进程死掉并创建另一个进程来处理请求。

有时,最好尝试解决问题。

答案 11 :(得分:1)

我说你应该总是有一个根异常捕获器...特别是如果你可以在异常中输入某种信息,说明出了什么问题,代码或其他东西并将其打印给用户。然后,用户可以随时询问您(或支持或其他什么)出了什么问题并提供一些信息......而不是“它因保护错误而崩溃”

答案 12 :(得分:1)

根本不处理任何例外情况有一个好处。如果出现问题,您宁愿崩溃并且用户抱怨,而不是让程序继续处于不确定状态。

例如,如果您正在编写实时交易系统,并且出现意外错误,那么最好让它崩溃。否则,您的程序可能继续进行并进行愚蠢的交易。用户会立即抱怨“WTF?”,但至少你不会损失数百万美元。

答案 13 :(得分:1)

这里有很棒的答案,尤其是Simucal。我只想补充一点:

攻击性编程非常适合调试。根据我的经验,“早期失败,经常失败”可以被认为就像为代码中的错误设置陷阱一样。当出现问题时 - 无论是内存泄漏,内存踩踏,意外的NULL等等 - 如果程序立即失败(通过相关的调试数据,如callstack),通常会更容易看到问题。

防御性编程非常适合生产环境。一旦你的应用程序出货,你可能不希望你的最终用户看到一个很好的小对话框,说“foo()处理未处理的异常。”如果您的应用程序处于测试阶段并且您仍在收集调试信息,那可能会很棒,但如果您要发送一个稳定的应用程序,您可能只是希望在极少数情况下确实失败的情况下不会打扰具有神秘输出的用户。 / p>

有时你可以双管齐下。我经常按以下方式编写C代码:

void foo(char* data) {
    ASSERT(data);
    if (!data) { return; }
    // ... work with data
}

如果在测试环境中编译此代码,则assert语句会捕获错误条件。如果它是在生产环境中编译的,那么预处理器会删除断言,而foo()会无声地失败。

异常比断言更具表现力和灵活性,并且有各种方法来管理它们,使得应用程序在测试环境中尽早失败,并在生产环境中记录错误时突然出现。根据项目的类型,这种设计可能对您有意义。

答案 14 :(得分:0)

尝试捕捉所有内容的问题是,您经常最终“处理”您不知道如何从中恢复的内容。用户得到一个错误的印象,事情进展顺利,但在内部你转向瑞士奶酪,最终以非常奇怪的方式打破。

另一方面,如果他们没有某种报告方式,那么将例外情况抛给用户并不是那么有用

  • 当您向MS注册时,新的Windows服务会提供该功能。
  • 安装drwatson还可以捕获用户手动发送给您的数据(转储文件)。

如果您提供服务库并且它正在运行中,如果您的服务因整个服务器混乱内存或设置而混乱,那么服务器可能会在异常被引发时真正关闭。

通过合同API将倾向于提供一种方式来说'我能做到这一点',然后是一种“做它”的方法,并且许多API如MS文件打开将允许您在提出异常和返回异常之间进行更改错误代码。

答案 15 :(得分:0)

您始终可以设置自定义错误处理程序,并忽略捕获您不准备处理的异常。如果符合正确的条件,试图从未知数中恢复可能也会产生负面影响。但话又说回来,这确实取决于异常是什么以及你如何处理它们。

另一方面 - 我认为人们会对整个“异常是邪恶的”心态感到不知所措。它们是一种工具,如果使用得当,可以获得惊人的额外津贴。然而,许多人通过使用catch(Exception)包装root来滥用它们。