六、回顾和总结

Retrospective and Conclusions

Cover Image

这趟旅程终于快要结束了。就像我一开始提到的一样,这趟旅程也许没什么惊喜,平淡无奇。但我希望所有的这些背景历程能够帮助你在错误模型方面取得更多的进展。

总结一下,我们最终的模型:

  • 具备一个良好的架构,能够细粒度地提供隔离,并在失败时提供恢复能力。
  • 区分 Bug 和可恢复错误。
  • 对于所有的 Bug,使用合约、断言,以及放弃来处理。
  • 对于可恢复错误,使用精简的受检查异常模型来处理,它还有强大的类型系统和语言语法的支持。
  • 汲取了返回错误码的部分优点(比如局部检查)来提高可靠性。

虽然这是一个持续了多年的旅程,但一直到我们的项目被砍掉时,我们还是在不断地做出改进。有些改进没有写入上面的列表中,因为我们还没有足够的经验来表明它们一定能成功。多希望我们能够走的更远、把那些功能都真正发布出来啊!特别是,我真的很想把下面这一点放入我们的最终总结当中:

  • 默认使用非空类型,从而消除大量的不可空标注。

放弃,以及我们大量使用放弃的程度,在我看来是我们在错误模型方面最成功的赌注。我们经常能够及早发现 Bug,在它们还很容易调试的时候修掉。基于放弃的错误和可恢复错误大约比例为 10:1,这使得受检查的异常很少见,开发人员也能够接受使用受检查的异常。

尽管我们没能成功的发布这套系统,还是有一些经验可以带到其他的项目中去的。

例如,在把 Internet Explorer 重写为 Microsoft Edge 时,我们在一些地方采用了放弃。最关键的一处就是内存不足,这是由一个 Midori 工程师实现的。就像我上文中提到的那样,老的代码在内存不足时还会尝试继续一瘸一拐地走下去,而此时它通常都是在做错误的事情。我的理解是,放弃能够发现相当多的潜在 Bug,我们在移植现有代码到 Midori 上时经常会遇到。另一个很棒的地方在于,放弃更像是一种架构层面的准则,可以在不同语言的现有代码中使用。

细粒度隔离的体系基础非常关键,然而许多系统对这种架构都只有非正式的概念。在浏览器中,内存不足时采用放弃工作的很好,原因之一就是大多数浏览器都已经把单独的标签页放在独立的进程中了。浏览器在很多方面都在模拟一个操作系统,这也是其中之一。

最近,我们还在探索把这些准则——包括合约——带入C++。同样,对于 C#,我们也有某些功能带入其中的具体提议。我们还在非常积极地改进一份把非空检查带入 C# 的提议。我希望这些提议一切顺利,但是需要承认的是,这些语言并不是从一开始就遵循同样的错误处理准则,因此这些特性未必能够做到完美无缺。同样需要注意的是,整个隔离和并发模型对于放弃来说同样至关重要。

我希望,我持续地分享这些知识,能够让更多人了解、采用这些想法。

当然,正如我提到的那样,Go、Rust 和 Swift 为我们提供了非常棒的、适合系统开发的错误模型。我也许还是有一点小挑剔,但事实是它们要比 Midori 刚启动时工业界的所有模型都要好。这真是一个系统程序员的好时代!

下次我会谈一谈我们使用的语言。尤其是,我们会看到,Midori 是如何使用包括架构、语言支持和库在内的神奇药水来驯服垃圾收集器的。期待与你下次再见!