软件工程的五个经验法则

这篇文章聊聊软件工程里一些常见的经验规律(大家通常叫它们“定律”)。虽然这个领域有很多这样的定律,但在这篇文章里,我会重点讲五个我觉得特别有用的。

1、康威定律
我觉得第一个也是最重要的定律是康威定律。计算机科学家梅尔文·康威是这么说的:
设计系统的组织,最终设计出来的系统结构会跟这个组织的沟通结构一样。

如果你还没在大公司或大团队里工作过,康威定律可能一开始听起来有点奇怪。至少我刚开始工作的时候就是这么觉得的。不过,公司里信息怎么流动、项目怎么规划、团队怎么组织,这些都会让康威定律在现实中变得特别明显。

康威定律最常见的两个极端例子是:

  1. 大团队 → 整体式架构:如果公司有一个很大的工程团队,通常会用整体式架构。
  2. 小团队 → 微服务架构:如果公司有很多小团队,而且这些团队的职责分得不太清楚,最后往往会搞出一堆没啥活力的微服务。

当然,这两个极端之间还有很多可能性。这不光跟团队大小有关。如果团队的职责很明确,通常能做出很紧凑的服务。但如果多个团队的职责有重叠,那不同服务之间可能会出现重复的逻辑,因为“共享”功能很少会自己冒出来。同样,如果团队之间有特定的沟通依赖,那最后做出来的服务依赖图也会反映这些沟通线路,哪怕从技术角度看这些依赖其实没必要。

康威定律在业界特别火,很多产品和团队管理的书都建议用“逆康威策略”——就是调整工程团队或整个部门的结构,来强化你想要的软件架构。

2、海伦定律
海伦定律是软件工程师和计算机科学家海伦·K·赖特提出的:
如果一个 API 有足够多的用户,那你承诺什么都不重要:系统的所有可观察行为都会被某些人依赖。

这条定律对大规模系统特别有洞察力。一旦系统达到一定规模,总会有用户依赖系统的具体实现细节,而不是严格按照接口定义来用。赖特自己是从她的经历中得到这个灵感的:
我之前是 Google 的软件工程师,后来成了 Adobe 的首席科学家。我做过大规模代码变更工具和基础设施,花了好几年改进 Google 的核心 C++ 库。这个观察来自于我发现,哪怕是最简单的库改动,也会导致某个遥远的系统出问题。

另一个例子是去年的一篇文章,Abenezer Belachew 提到 Golang 社区在维护语言时也考虑到了这条定律:


func (e *MaxBytesError) Error() string {
    // 由于海伦定律,这段文字不能改
    return "http: request body too large"
}

和康威定律一样,海伦定律在软件项目达到一定规模后也会经常出现。

3、古德哈特定律
这条定律最早是经济学家查尔斯·古德哈特在货币政策背景下提出的:
一旦你为了控制某个统计规律而施加压力,它就会崩溃。

不过,它经常被更简单地总结为:
当一项指标变成目标时,它就不再是好指标了。

这条定律在软件工程里也特别有用,而且适用于很多其他领域。比如,如果你只关注提高代码覆盖率,那开发人员可能会写一些没啥用的测试,对提高整体质量没啥帮助。再比如,如果把绩效评估和关闭的工单数挂钩,团队可能会只解决简单问题,而忽略复杂的技术债务。更严重的例子是,如果“架构合规性”只看是否用了某些框架或模式,工程师可能会为了达标而硬塞进去,忽略了长期的可维护性。总之,指标的初衷——确保软件的高质量——最终会被达到目标的压力掩盖。

4、雅各布定律
这条定律是由网络可用性顾问和人机交互研究员 Jakob Nielsen 提出的:
用户会根据他们之前在其他网站上的经验来预测你的网站会怎么工作。所以改设计的时候,尽量少改,保持易用性。

这个原则本来是针对网站用户体验的,但我觉得它适用范围更广。雅各布定律其实反映了人类行为心理学在软件工程中的应用。无论你是设计网站 UI、公开 HTTP API 还是发布开源 Python 库,如果你的软件偏离了用户习惯的模式,哪怕那些模式本身不一定更好,用户也可能会觉得不爽。

5、莱纳斯定律
这条定律是软件工程师和开源倡导者 Eric S. Raymond 为了纪念Linus Torvalds 提出的:
只要有足够多的眼睛盯着,所有 bug 都会被发现。

在他的文章《大教堂与集市》里,Raymond 对比了两种自由软件开发模式。“大教堂”模式是把源代码控制在一小群人手里,直到正式发布;而“集市”模式则是全程公开。Raymond 认为,Linux 内核的创始人 Linus Torvalds 是“集市”模式的先驱。文章的核心观点——“莱纳斯定律”——是说,当更多人能查看和测试源代码时,bug 会更快被发现和修复。换句话说,“只要有足够多的眼睛,所有 bug 都是浅显的。”

这条定律在加密算法和安全软件领域特别重要,因为这些领域需要公开审查来发现潜在漏洞。相比之下,那些吹嘘“专有”解决方案的公司可能依赖保密,而不是严格的同行评审——这种方法可能会让隐藏的 bug 一直存在。