简单之道

Dec 22, 2023 00:00 · 1960 words · 4 minute read Engineering

Rob Pike

原文:https://commandcenter.blogspot.com/2023/12/simplicity.html


简单胜于复杂。

简单的东西更易于理解、构建、调试和维护。易于理解是最重要的,因为带来的好处多多。看看 google.com 的界面,只有一个文字框,输入后回车就能得到有用的结果。那是相当简洁的设计,也是 Google 能够成功的主要原因之一。早期搜索引擎的界面复杂得多,而如今要么模仿我们,要么很难用。

但是 google.com 背后的东西呢?GWS(Google Web Server)又如何?我看了一个正在运行的 GWS 实例的参数列表,有成千上万个配置选项和几百种参数:有些配置后端有些启用或禁用属性。其中大多数可能是正确的,但我保证有些是错误或失效的。

我们不禁要问,google.com 和 GWS 是同一家公司设计出来的吗?答案是 GWS 的配置结构并非设计而来,它自然地发展。每个部分、每次变化可能都很简单,但组合起来就复杂到令人发指。

复杂度是做乘法的。在像 Google 这样由多个组件组装而成的系统中,每当你使其中一部分变得更复杂,一些额外的复杂度会反映在其他组件上。这就是复杂度失控。

这也是普遍存在的。

很多年前,Tom Cargill 从贝尔实验室的研究部门去了开发部。他加入的团队每个子系统的代码都会被打印出来装订成册放在每个办公室的书架上。Tom 发现其中一个子系统完全是多余的,它大部分服务已经在其他地方实现了。所以他花了几个月时间删了 15000 行代码,搞定后从每个人的书架上移走了那本册子。他简化了系统的复杂度,代码量、测试和维护工作都减少了,同事们都很喜欢。

但出问题了,在绩效考核中,代码行数也是一个衡量产出的指标。Tom 的产出是负的。。。实际上,因为删的太多,他所在的整个组的产出都变负了。他只能夹着尾巴回到了研究部门。

他被上了一课:复杂性无处不在,简单没有回报。

你可以嘲笑这事,虽然我们不以代码行数来考核绩效,但也是五十步笑百步,谁在 Google 会因为删除代码而升职?我们沉迷于如今庞大又复杂的代码,新员工很难掌握,公司投入了大量资源来培训和指导他们适应。而我们却以能够理解和修改这些代码为荣。

Google 是民主的:代码对所有人开放,大家都可以查看、修改、优化和添加。但每次新增一些东西,就会增加复杂度;引入一个新的库,也会增加复杂度;添加一个存储的封装,还是会增加复杂度。向子系统增加一个选项,就使配置变复杂了。当你动了网络库这样的核心模块,整个系统都会变得更复杂。

复杂度带来的成本是以指数级增长的。

另一方面,简单是要付出心血的,但这些代价都在前期。设计简单的系统很难,但是搭建和维护起来容易得多。因为避免了复杂性,简单带来的收益也是指数级的。

看看日志查询系统,它并非完美,但设计初衷就是 Google 解决特定核心问题的唯一系统(现在仍是)。因此它必须保证稳定性、安全性、使用统一和低开销。如果每个团队都推出自己的日志基础设施,Google 不可能取得今天的成就。

但成功的经验并没有被推广和学习,各个团队仍在不断推出新存储系统、工作流管理器、新库、新架构。

那些重复工作和快速增长的复杂度正在拖累我们。

Google 有许多工程原则:代码要可读、可测试;不要惹毛 SRE;越快越好。

简单从来都不在其中。但实际上,简单比任何原则都来的重要。简单的设计更易于理解;简单的代码更易于测试;简单的系统更易于向 SRE 解释以及修复问题。

此外,简单的系统跑得更快。

注意我这里说的是系统,不是代码。有时为了速度是要增加代码复杂度的,这无法避免。但是复杂的系统一定不快,它们有着太多的组件且难以理解,更别说使它们快起来了。复杂导致低效。

简单甚至比性能更重要。因为复杂度的乘数效应,通过增加 2% 的复杂度带来 1~2% 的性能提升,完全得不偿失。

我们的生产代码利用率低是因为系统太慢太复杂了。我们不理解单个组件或整个系统会如何运行,说不清楚它们之间的交互。应用开发者没有完全理解底层基础设施。底层开发人员没有完全理解网络,等等等等。

为了修补,每个人都添加了一堆配置选项和过度调整,这使得一切都变得更难以理解。产品想要发布,只能通过围绕产品构建防护墙来隔离外部的复杂性——这只会增加更多的复杂度。

这是个恶性循环。

所以请三思你在做的事。它可以变成更简单吗?真的需要这个功能吗?通过简化、删除、合并和复用,能否使其变得更好?与相关团队聊聊,了解如何与他们合力设计一个更简单、共享的架构,而不是相互抵触。

理解已有的系统,并在它们的基础上构建。如果现有的系统无法满足你的需求,也许问题出在了系统设计上。如果确实要构建一个新组件,确保它具有普适性,不要只想着解决你自己团队的问题。

构建复杂的系统很容易,赶工时,编码比重新设计更简单、更快。但是技术债会累积起来,长此以往必然会失败。

代码仓库中的代码量比一年前增加了一半,那再过一年呢?五年后呢?

如果我们不能控制住复杂度,总有一天系统会慢到停止运转。