译: 简单性
蟠木朽株在 2009 年 5 月,Google 举办了一场内部的「设计巫术(Design Wizardry)」小组讨论会,演讲者有我和 Jeff Dean、Mike Burrows、Paul Haahr、Alfred Spector、Bill Coughran。 以下是略加编辑的我的演讲记录。尽管一些细节已经过时,但在今时今日,核心主旨可能比那时候更显重要。
简单胜于复杂
越简单的东西就越容易理解,也就更容易构建、调试和维护。容易理解是最重要的,无法理解就无法进行其他任何后续步骤。
看看 google.com 的网页,只有一个文本框,输入查询内容,获取结果。这个设计非常简洁,也是 Google 成功的主要原因。早期的搜索引擎界面要复杂的多。如今,它们要么模仿我们的界面,要么感觉非常难用。
这就是 google.com。但是它背后是什么呢?GWS(Google Web Server),它复杂吗?该如何调用?我查看了一个正在运行的 GWS 实例的参数列表,里面有数万个字符的 Configuration flags 和几百个参数,还有一些后端机器的名称和配置,以及一些属性的启用和禁用。其中大部分可能是正确的,我保证其中一些是错误的,或者至少是过时的。
所以,我的问题是:设计出 google.com 的公司怎么可能和设计出 GWS 的公司是同一家公司呢?答案是,GWS 的配置结构并不是设计的,它是软件迭代过程中自然发展出来的。自然发展的产物必然是不简单的,它会复杂地离谱。每个部分、每个变化可能都很简单,但组合起来就会变得非常复杂。
复杂性对系统的影响是呈现指数级增长的。在一个像 Google 这样的系统中,它是由多个不同的组件组合起来的,每次你使一个组件变得更复杂,其中一部分复杂性就会反映到其他组件中。久而久之,系统的复杂性就失控了。
复杂性普遍存在
许多年前,Tom Cargill 从贝尔实验室研究部休假一年,到开发部门工作。他加入了一个小组,组内每个子系统的代码都被打印成册,存放在每个办公室的架子上。Tom 发现其中一个子系统几乎是完全冗余的,它的大多数服务在其他系统中实现了。因此,他花了几个月的时间让这个系统变得可有可无,删除了 15,000 行代码,完成后,他从所有人的架子上移除了一整册代码。这样降低了系统的复杂性,减少了代码量和测试、维护的工作量。他的同事们都很高兴。
但是有一个问题。在绩效评估期间,他了解到管理层有一个衡量生产力的指标:代码行数。Tom 的生产力为负。事实上,由于他太成功了,他所在的小组的生产力都为负。他夹着尾巴回到了研究部门。
他吸取了教训:复杂性是普遍存在的,简化不会有回报。
你可以嘲笑这个故事:「我们不会根据代码行数进行绩效评估」。
但是我们距离这个地步并不远。谁会因为删除 Google 的代码而得到晋升呢?我们陶醉于现有的庞大而复杂的代码中,新员工很难掌握它,我们不得不投入了大量的资源来培训、指导,以便他们能够应付它。我们为自己能够理解和自由修改这些代码而自豪。
Google 是一个民主的企业,所有人都可以查看代码,以对修改、完善和增加功能。但是每次增加内容时,复杂性也会随之递增。引入新库,会增加复杂性;添加新的存储封装,也会增加复杂性;在子系统中添加选项,会增加配置的复杂度。而当你使核心模块(如网络库)复杂化时,你就把整个系统都变得更复杂了。
复杂性就这样累积起来了,而且其成本实际上是呈指数级增长的。
另一方面,简单需要付出努力——但是可以在实际开始之前就进行。设计一个简单的系统很难,但更容易构建和维护。通过避免复杂性,简单性的效益是指数级的。
请原谅我的唯我论,但请看一下查询日志系统。虽然它远非完美,但它旨在成为——并且现在仍然是——谷歌唯一一个能够解决其所针对的特定核心问题的系统。因为它是唯一的,所以它保证了稳定性、安全性、使用的统一性以及大规模的经济效益。如果每个团队都使用自己的日志基础设施,Google 就不可能有今天的成就。
但是这个教训的重要性未能得到广泛的认可或应用。各个团队不断提出新的存储系统、新的工作流程管理器、新的库、新的基础设施。
所有的重复模块和快速增长的复杂性正在扼杀我们,因为复杂性在降低我们的效率。
在 Google,我们有许多工程原则。保持代码可读性、确保代码可测试、不要惹恼 SRE、提升代码性能。
简单性从未出现在原则中。但事实是:简单性比任何一项都重要。越简单的设计可读性越好,越简单的代码越容易测试,越简单的系统越容易向 SRE 阐释,并在发生故障时更容易修复。
此外,简单的系统运行速度更快。
请注意,我在这里指的是系统,而不是代码。有时,但并非总是,为了提升性能会书写复杂的代码,这可能是无法避免的。但是复杂的系统永远不会变更快,它们有更多的组件,很难梳理优化它们之间的相互调用来提升性能。复杂性导致效率低下。
简单性比性能更重要。因为复杂性对系统的影响呈指数级飙升,通过增加 2% 的复杂性(或 1% 甚至 0.1%)来获得 2% 的性能提升完全是得不偿失的。
但是,等等。我们的资源利用率 Code Red(颜色表示问题的严重性)呢?
我们没有利用率问题,因为我们的系统太慢了。我们有利用率问题,因为我们的系统太复杂了。我们不了解系统的性能表现,无论是单个还是所有的。我们不知道怎么描述它们之间的相互调用。
应用程序的编写者并不完全了解基础设施。
基础设施的编写者并不完全了解网络。
或者说应用程序也是如此,等等。
为了弥补这一点,每个人都过度优化,增加无数的配置选项,不断的调整。这让一切变得更加难以理解。
产品之所以能成功推出,只能通过建立壁垒来将其与复杂性隔离开来,但是这只会增加更多的复杂性。
这是一个恶性循环
所以,请认真思考你正在做的事情,可以更简单吗?你真的需要这个功能吗?你可以通过简化、删除、合并或共享来让事情变得简单吗?和相关团队进行沟通了解,一起设计一个更简单、统一的架构,而无需相互防御。
在创建新系统时,应该充分了解和利用已有的系统,而不是试图避开或忽视它们。如果现有系统不能满足你的要求,那么问题可能在你设计的系统上,而不是那个系统。
如果确实需要一个新的组件,请确保它的通用性。不要构建仅能解决自己团队问题的基础设施。
构建复杂系统很容易。在匆忙发布时,编码比重新设计更简单、更快。但是长远来说,技术债务会不断积累,你会输给它。
代码库中的代码行数比一年前增加了 50%。明年呢?五年后呢?
如果我们不控制复杂性,总有一天,它不会是利用率 Code Red。事情会变得非常复杂,系统非常缓慢,直到停止运行。这就是所谓的 Code Black。
Origin: https://commandcenter.blogspot.com/2023/12/simplicity.html