未知的未知

我们进行了一些测试。测试固然重要,它们能让我们对自己的软件及其正确性更有信心。

然而,测试套件并不能证明我们应用程序的正确性。我们必须探索截然不同的方法来证明某些东西是正确的(例如形式化方法)。

在运行时,我们会遇到一些在设计应用程序时从未测试过,甚至从未考虑过的场景。

根据我们迄今为止所做的工作以及我过去的经验,我可以指出一些盲点:

  • 如果数据库连接断开会发生什么?sqlx::PgPool 会尝试自动恢复吗?还是从那时起,所有数据库交互都会失败,直到我们重新启动应用程序?
  • 如果攻击者试图在 POST/subscriptions 请求的主体中传递恶意负载(例如,极大的负载、尝试执行 SQL 注入等),会发生什么?

这些通常被称为已知的未知问题:我们已知但尚未调查的缺陷,或者我们认为它们与实际无关,不值得花时间处理。

只要投入足够的时间和精力,我们就能摆脱大多数已知的未知问题。

不幸的是,有些问题我们以前从未见过,也没有预料到,它们就是未知的未知问题。

有时,经验足以将未知的未知问题转化为已知的未知问题:如果你以前从未使用过数据库,你可能从未想过连接中断时会发生什么;一旦你见过一次,它就变成了一种熟悉的故障模式,需要时刻注意。

通常情况下,未知的未知问题是我们正在开发的特定系统特有的故障模式。

它们存在于我们的软件组件、底层操作系统、我们正在使用的硬件、我们开发流程的特性以及被称为“外部世界”的巨大随机性来源之间的交汇处。

它们可能出现在以下情况:

  • 系统超出其正常运行条件(例如,异常的流量峰值)
  • 多个组件同时发生故障(例如,数据库进行主从故障转移时,SQL 事务被挂起)
  • 引入了改变系统平衡的变更(例如,调整重试策略)
  • 长时间未引入任何变更(例如,应用程序数周未重启,然后开始出现各种内存泄漏)
  • 等等

所有这些场景都有一个关键的相似之处: 它们通常无法在实际环境之外重现。

我们该如何做好准备,以应对由未知陌生人造成的中断或错误?