海勒姆定律--关于软件工程的一个观点

简而言之,这个观点就是这样:

如果应用程序接口的用户数量足够多,你在合同中承诺什么并不重要:

你的系统的所有可观察行为都会有人依赖。

在过去几年中,我在地球上最复杂的软件系统之一中进行了底层基础架构迁移,并对接口与其实现之间的差异有了一些看法。我们通常认为,界面是与系统交互的抽象概念(就像汽车的方向盘和踏板),而实现则是系统工作的方式(车轮和发动机)。这样做有很多好处,其中最主要的原因是,大多数有用的系统很快就会变得过于复杂,单个人或团体无法完全理解,而抽象对于管理这种复杂性至关重要。

定义正确的抽象层次是一个完全独立的讨论(参见 《人月神话》),但我们倾向于认为,一旦定义了抽象,它就是具体的。换句话说,从理论上讲,接口应该在系统的消费者和实现者之间提供清晰的分隔。在实践中,随着系统使用量的增加,用户开始依赖于通过接口有意暴露出来的实现细节,或者通过经常使用而了解到的实现细节,这种理论就会瓦解。斯波斯基的 "抽象泄露定律 "体现了消费者对内部实现细节的依赖。

如果将其推向逻辑的极端,就会产生以下观点,俗称 "隐式接口定律":只要有足够多的使用,就不存在所谓的私有实现。也就是说,如果一个接口有足够多的消费者,他们就会有意无意地共同依赖于接口实现的方方面面。这种效应限制了对实现的更改,因为现在实现必须同时符合显式记录的接口和通过使用捕获的隐式接口。我们通常把这种现象称为 "bug-for-bug 兼容性"。

隐式接口的创建通常是逐渐发生的,接口消费者一般不会意识到它的发生。例如,一个接口可能对性能没有任何保证,但用户往往会期望它的实现能达到一定的性能水平。这些期望会成为系统隐含接口的一部分,而系统的变化必须保持这些性能特征,才能继续为用户服务。

并非所有用户都依赖于相同的隐式接口,但只要有足够多的用户,隐式接口最终就会与实现完全匹配。此时,接口已不复存在:实现已成为接口,对其进行任何更改都将违背消费者的期望。运气好的话,广泛、全面和自动化的测试可以检测到这些新的期望,但却无法改善它们。

隐式界面是大型系统有机增长的结果,虽然我们可能希望这个问题不存在,但设计师和工程师在构建和维护复杂系统时最好还是考虑一下这个问题。因此,请注意隐式界面是如何限制你的系统设计和演进的,并且要知道,对于任何相当流行的系统来说,隐式界面比你想象的要深入得多。

海勒姆是谁?

我是谷歌的一名软件工程师,从事大规模代码变更工具和基础架构方面的工作。在此之前,我花了五年时间改进谷歌的核心 C++ 库。当最简单的库变更也会导致某个遥远系统出现故障时,我就会提出上述看法。

虽然这可能是我提出的观点,但将其命名为 "海勒姆定律 "并在更广泛的范围内普及这一概念的功劳要归功于泰特斯-温特斯(Titus Winters)。