多年来,我观察到了一些在工程过程中反复出现的基本模式和陷阱。有趣的是,它们与工程博客上无休止争论的话题无关。例如,我不记得哪一次我的团队因为对 SOLID 原则理解不足而导致错过了交付期限。偶尔,我会遇到一条“法则”,它完美描述了我所经历的问题。令人恼火的是,这些便利的工程定律却往往在播客、有声读物和博客的边角隐蔽处。所以我把它们整理成一个清单,其中列出了我最喜欢的 8 条编程法则,你肯定也会在现实生活中遇到它们。
墨菲定律[1]是这个榜单上最著名、最广为人知的定律,它通常被表述为:
“凡事只要可能出错,那就一定会出错。”
不过,真要说触及所有工程师痛处的还要数墨菲第二定律:
“任何解决方案都有自己的问题“
或者,没有什么事情像看起来那么简单[2]。墨菲第二定律雄辩地总结出了以下观察结果:作为工程师,我们接触的任何东西都会增加系统的风险,因此,可以通过避免系统更改来降低风险。
随着我成长为一名成熟的工程师,我花在编程上的时间越来越少。事实上,我已经慢慢地开始认为,编写新代码是一种系统性风险;它增加了复杂性、可维护性,可能还有 Bug。考虑到墨菲定律,我有以下建议:
1967 年,梅尔文·康威揭示了这样一个道理[3]:
“设计系统的架构受制于产生这些设计的组织的沟通结构。”
或者,更直截了当地:
“如果你让 4 个小组开发编译器,那么你就会获得 4 个编译器。”
康威定律的影响很大,因为软件工程师常常必须与分散在世界各地的同事一起构建系统。例如,我在一家大型托管银行工作的时候,曾参与开发过一个有很多服务的交易系统。除了两个服务之外,其余服务都是通过内部消息总线进行通信。然而,莫名其妙的,这两个服务通过互联网上的公共 API 进行通信。
就像大脑功能作为子组件运行一样,任何时空上分散的劳动力也是如此。
我接着发现,通过互联网进行通信的服务是美国团队和印度团队唯一重叠的地方。系统架构基本上是两个半球:左边是美国的微服务,右边是印度的服务,它们之间有一个最小 API。从根本上说,这个 API 就是大西洋。
在所有科技领域中,关于康威定律的补救措施,有一个最好的说法是逆康威模式(Inverse Conway Maneuver)。换句话说,通过改进团队和组织结构来促成所需的架构[4]。在这方面,亚马逊的双披萨团队可能算是最著名的例子了,故事是这样的:
这很好,但你可能没有能力开展公司范围的组织结构大调整。不用担心,有几种方法可以让你的组织,或者至少是你的团队,摆脱康威定律:
也被称为演示过程中的墨菲定律,它指出,无论你排练得多么好,无论你排练了多少次,你在演示时总是会出错!我在这里就不详细说明为什么会发生这种情况了——关于这一点,请查阅资料[9-11] 。
如果这在世界一流工程师马斯克身上会发生,那么在你身上也会发生(https://www.reddit.com/r/ProgrammerHumor/comments/e0bkok/universal_law_of_demos/)
接受演示经常会不顺利的事实,做好防范:
由于演示从来都无法完全按计划进行,你实际上可以利用这一点来发挥自己的优势。如果有什么东西不能正常工作,如你的 IDE 出了问题,你无法重现一个错误,诸如此类。那么,你可以利用演示定律,试着把它展示给一个朋友。通常,在谈论这个问题的时候,你会发现解决方案,或者问题会神奇地消失。
格雷沙姆定律来自 19 世纪的经济学,它指出:
“劣币驱逐良币” [6],或者更通俗地说“坏的挤走好的”。
Ben Hosking 在[7]中对格雷沙姆定律在软件工程中的应用做了很好的描述,我把它简单地归结为:
廉价的软件实际上非常昂贵[8]。
你希望三者兼而有之,但实际上应该把重点放在质量(Godd)上(https://andrewcoppolino.com/blog/fast-good-cheap-pick-two/)
在理想世界里,每个项目都很快,很便宜,而且还做得很好。然而,在现实中,我们只能追求 3 项中的 2 项,要明智地选择。在某些情况下,我们不得不仓促赶工,但根据格雷沙姆定律,“便宜”是一个谎言。那是技术债务。你应该总是追求把事情做好。
在 Daniel Kahneman 的《思考,快与慢》一书中[13],估计谬误是指人类在提前计划时表现出相当大的乐观偏差,导致对完成一项任务所需的时间估计不足。你可能经常会碰到这种情况。例如,最近你是否有什么小差使原本打算用一个小时完成,最后却让你耗费了半天时间?事实上,对于任何任务估计,一般的建议是先将最初的估计翻倍甚至翻三倍,然后你才会对其实际完成时间有一个大致的认识。
计划谬误的精彩描绘(https://medium.com/geekculture/how-the-planning-fallacy-trips-you-up-3248b7e3978e)
以下是计划谬误的几个实际的例子[14]:
该定律是最近才提出来的,可以追溯到一名谷歌人的博客[12]。该定律指出:
当一个 API 有足够多的用户,
你在契约中承诺了什么并不重要:
系统中所有看得见的行为
都会有某个人依赖……
XKCD 漫画就是最好的例证:
与墨菲定律类似,你必须注意,人们会以你意想不到的方式使用系统。因此,必须尽量缩小其范围。构建一个让用户可以用两种类似的方式做同一件事的 API?这会让用户感到困惑吗?尽量让接口一目了然、固执己见、简单易用,以至于幼儿园的小朋友都能使用。
最近,我在设计一个 API 时遇到了海勒姆定律描述的情况。简单起见,假设它获取一个用户列表:
fetchUsers() -> {Allan Apple, Bill Banana, Chris Carrot ...}
注意到用户是有顺序的了吗?排序过程是隐式的,因为是在数据库中完成的,API 契约中没有顺序保证。然而,考虑到海勒姆定律,我意识到,最终会有人依赖于这个顺序。因此,我在构建时将它作为 API 契约的一个默认参数fetchUsers(sort=True)。
帕累托法则也被称为收益递减定律,或 80/20 原则,其适用范围很广。例如,根据 1989 年的估计,世界上最富有的 20%的公民拥有世界上 80%的财富(多么奇怪)。或者,20%的工作场所危险源导致了 80%的伤害。在软件领域,这体现在几个方面,我将直接引用维基百科的说法,因为它说得很好:
在计算机科学中,帕累托法则可以应用于优化工作。例如,微软公司指出,修复报告最多的错误中的 20%,可以消除特定系统中相关错误和崩溃的 80%。Lowell Arthur表示,“20%的代码包含了 80%的错误。找到它们,修复它们!" 人们还发现,一般来说,一款软件的 80%可以在分配的总时间的 20%内写完。反之,最难的 20%的代码需要 80%的时间。通常,这个因素是软件编码中COCOMO估算的一部分。
要利用好帕累托法则,你可以采取以下措施:
尽早将最棘手的工程挑战暴露出来很重要。80%的工作可能都潜伏在这里。
一个很好的方法是承担更多的责任,这将使你专注于最重要的挑战,而不是细节。
我并不是说你应该同时处理多项任务,这通常很低效。我的意思是,不要在任何一项任务上花费超过一周的时间。当然,不是所有的任务都能在一周内完成,这就是问题的关键。如果给你的时间无限,你就会找活来干,这通常会导致镀金。然而,如果知道你要把它交给一个队友,那么你就必须确定什么最重要——也许只是创建一个包含 CRUD 方法的 REST API,或者仅仅是设置构建管道。通过快速参与和退出,你将在多个项目中完成 80%的工作。当你的同事花了整整一个月的时间把一件事情做到 100%的时候,你会把四件事情做到 80%,在某种意义上,你的生产力提高了大约 3 倍。我可以告诉你,当我成为一名高级开发人员时,我在许多项目中做出了贡献,这比我在之前的工作中从头到尾做一件事更有价值;在我看来,宽度>深度。
图片来源:https://unsplash.com/photos/OopPIi_A428
又称复杂性守恒定律,其思想是,每个系统都有一个固有的不可约减的复杂性,如果要处理它,要么系统变得更复杂,要么交由用户来完成。Larry Tesler 认为,最好是花点工程时间来改进系统,而不是指望用户这么做。这是有道理的——如果你的应用有一百万用户,那么即使一个工程师花费一个月的时间从一项操作中减掉了几次点击,就可以为百万用户节省数百万次点击。
在我自己的生活中,这种情况每天都在发生。当我和谷歌家居说,打开灯,改变它们的颜色。我必须给它两个单独的命令:
嘿,谷歌,把灯开到 50%……(等待 5 秒)……嘿,谷歌,把灯调为白光。
当然啦,在人工智能中支持复合命令难度很大,因此,用户吸纳了这种复杂性。
这本身不是一条定律,但感觉应该包括在内。当一个解决方案(Y)的提出没有充分考虑实际问题(X)的背景,就会导致更好的解决方案(Z)被忽视,浪费精力。考虑一下这样一个例子:
老板:“请加大这一页的字体。”(建议解决方案 Y)
工程师:“好的。”
老板(第二天):“你能把它改回来吗?用户说太大了。”
工程师:“好吧——我们一开始为什么要改?”
老板:“我们的一个用户用的是旧版本的 IE,字体渲染有问题。”(真正的问题 X)
工程师:“他就不能用 Chrome 吗?”(备选方案 Z)
在上面的例子中,只要工程师问几个澄清式问题,就可以避免浪费精力。老板对解决方案(Y)的执着使他看不到可能更好的解决方案(Z)。
在现实生活中,XY 问题通常始于一些听起来可疑的事情。像“请把字体改大”这样的请求不是一个问题陈述,而是一个解决方案陈述。真正的问题是“此页面在旧的 IE 浏览器上显示不正常”。遗憾的是,有时候需要工程师来提取上下文信息,因为经常会缺少需求和工单。但好消息是,这通常并不难——只要说“让我们复盘下——我们要解决的问题是什么”,99%的情况下你都能成功。
你是怎么想的?我漏掉了什么重要的东西吗?我有什么地方理解的不对吗?欢迎留言,以便我可以修改这篇文章。
1.https://en.wikiquote.org/wiki/Murphy%27s_law
3.https://en.wikipedia.org/wiki/Conway%27s_law
4.https://www.thoughtworks.com/en-us/radar/techniques/inverse-conway-maneuver
5.https://thenewstack.io/led-amazon-microservices-architecture/
6.https://www.britannica.com/topic/Greshams-law
8.https://dev.solita.fi/2020/06/16/cheap-software-is-expensive.html
9.https://wiki.c2.com/?DemoMeltdown
10.https://theappslab.com/2009/07/17/murphys-law-of-demos/
11.https://levelup.gitconnected.com/the-4-laws-of-the-software-demo-b74b79ca79e3?gi=5ec80c8efa29