在任何软件项目中,目标都是创造稳定的东西。我们不希望它在用户面前崩溃。我们也不希望我们的网站显示“内部应用程序错误”而不是网页。我们希望我们的软件能够正常工作,而不是失败。这是一个完全合理且合乎逻辑的愿望,但为了实现这一目标,我们必须让我们的软件尽可能脆弱。这听起来可能违反直觉,但事实就是如此。您的应用在开发中越 脆弱 ,在生产中就越 健壮 。
埃米尔·库斯图里卡 (Emir Kusturica) 的《黑猫,白猫》(1998)
所谓脆弱,我指的是 Fail Fast 哲学,它与 Fail Safe 相反。我相信您知道其中的区别,但无论如何让我通过示例提醒您。这是故障安全:
public int size(File file) {
if (!file.exists()) {
return 0;
}
return file.length();
}
此方法应该计算并返回文件大小。它首先检查文件是否存在。如果不存在,该方法返回零。实际上,该文件不存在,因此没有大小。我们可以抱怨文件不存在,但这是为了什么?为什么要发出声音?让我们保持安静并返回零。我们不会失败,因为我们试图让应用程序保持运行。这称为故障安全。
相反,这就是 Fail Fast 的样子:
public int size(File file) {
if (!file.exists()) {
return 0;
}
return file.length();
}
我们找不到文件?我们不隐瞒这个事实。我们将这种情况公之于众。我们尖叫和哭泣。我们抛出异常。我们 希望 应用程序崩溃、中断和失败,因为有人给了我们一个不存在的文件。我们抱怨和抗议。这称为快速失败。
哪种哲学,如果我们到处都遵循它,将使我们的软件健壮且具有故障恢复能力?只有第二个——快速失败。
为什么?因为故障发生得越快越容易,修复起来也就越快。而且修复会更简单,也更明显。 Fail Fast 是一种更好的可维护性方法。代码变得更清晰。跟踪故障要容易得多。即使是最微小的问题,所有方法都准备好中断并抛出异常。
在此示例中,如果该方法返回零,则不清楚文件是否存在且其大小实际上为零,或者其名称是否错误而只是找不到。 Fail Safe 方法 隐藏了 问题并使代码更难维护,这就是它难以稳定的原因。
一开始,在生产过程中,我们会遇到很多崩溃和错误。但是所有这些都将是可见的并且易于理解。我们将修复它们并用单元测试覆盖它们。每个修复都会使我们的软件更 稳定 ,并更好地被测试覆盖。
考虑到 Fail Safe 方法设计的软件在开始时看起来会更稳定,但它会迅速退化并不可避免地变成无法维护的混乱。
考虑到 Fail Fast 方法设计的软件在开始时会经常崩溃,但每次修复都会提高其稳定性,并最终变得非常稳定和健壮。
这就是为什么脆弱性是稳健性的关键成功因素。