每名开发人员都会遇到的 8 条编程法则

简介: 本文最初发布于 Level Up Coding。

多年来,我观察到了一些在工程过程中反复出现的基本模式和陷阱。有趣的是,它们与工程博客上无休止争论的话题无关。例如,我不记得哪一次我的团队因为对 SOLID 原则理解不足而导致错过了交付期限。偶尔,我会遇到一条“法则”,它完美描述了我所经历的问题。令人恼火的是,这些便利的工程定律却往往在播客、有声读物和博客的边角隐蔽处。所以我把它们整理成一个清单,其中列出了我最喜欢的 8 条编程法则,你肯定也会在现实生活中遇到它们。

1)墨菲第二定律

墨菲定律[1]是这个榜单上最著名、最广为人知的定律,它通常被表述为:

“凡事只要可能出错,那就一定会出错。”

不过,真要说触及所有工程师痛处的还要数墨菲第二定律:

“任何解决方案都有自己的问题“

或者,没有什么事情像看起来那么简单[2]。墨菲第二定律雄辩地总结出了以下观察结果:作为工程师,我们接触的任何东西都会增加系统的风险,因此,可以通过避免系统更改来降低风险。

运用之道

随着我成长为一名成熟的工程师,我花在编程上的时间越来越少。事实上,我已经慢慢地开始认为,编写新代码是一种系统性风险;它增加了复杂性、可维护性,可能还有 Bug。考虑到墨菲定律,我有以下建议:

首选流程变革和供应商软件,而不是自主开发的解决方案。

避免陷入快速解决方案陷阱,因为你以后不得不回过头来改进。第一次就把它做好。

测试。测试。测试。测试覆盖率越高,应用程序就越能适应复杂的环境。

2)康威定律

1967 年,梅尔文·康威揭示了这样一个道理[3]:

“设计系统的架构受制于产生这些设计的组织的沟通结构。”

或者,更直截了当地:

“如果你让 4 个小组开发编译器,那么你就会获得 4 个编译器。”

康威定律的影响很大,因为软件工程师常常必须与分散在世界各地的同事一起构建系统。例如,我在一家大型托管银行工作的时候,曾参与开发过一个有很多服务的交易系统。除了两个服务之外,其余服务都是通过内部消息总线进行通信。然而,莫名其妙的,这两个服务通过互联网上的公共 API 进行通信。

image.png

就像大脑功能作为子组件运行一样,任何时空上分散的劳动力也是如此。

我接着发现,通过互联网进行通信的服务是美国团队和印度团队唯一重叠的地方。系统架构基本上是两个半球:左边是美国的微服务,右边是印度的服务,它们之间有一个最小 API。从根本上说,这个 API 就是大西洋。

运用之道

在所有科技领域中,关于康威定律的补救措施,有一个最好的说法是逆康威模式(Inverse Conway Maneuver)。换句话说,通过改进团队和组织结构来促成所需的架构[4]。在这方面,亚马逊的双披萨团队可能算是最著名的例子了,故事是这样的:

2001 年,Amazon.com 是一个紧耦合的大型单体,维护难度很大[5]。

该网站被重建为多个微服务,每个微服务由一个专门的团队支持。因此,团队按照业务线(如购物车、推荐、广告)而不是技术线(如数据库、QA、开发)进行了重组。

T 团队保持较小的规模——人员数量以两个披萨能让团队所有人吃饱为限。公司和网站同时经历了一次重构。

这很好,但你可能没有能力开展公司范围的组织结构大调整。不用担心,有几种方法可以让你的组织,或者至少是你的团队,摆脱康威定律:

最重要的工作应该在时区重叠的时间内完成。我并不是说西海岸的同事要赶每天早上 6 点的接触点,但是真正关键的会议和结对开发应该安排在团队中大多数人都能参加的时间。

在招聘和组织工作中考虑到这种限制因素。虽然这很可能是你无法控制的,但你可以尝试向你的经理们传达康威定律。

接受它。如果你所在的组织是分布式的,那么或许你们的系统也应该是分布式的。避免与组织结构不协调的系统架构。

3)演示定律

也被称为演示过程中的墨菲定律,它指出,无论你排练得多么好,无论你排练了多少次,你在演示时总是会出错!我在这里就不详细说明为什么会发生这种情况了——关于这一点,请查阅资料[9-11] 。

image.png

如果这在世界一流工程师马斯克身上会发生,那么在你身上也会发生(https://www.reddit.com/r/ProgrammerHumor/comments/e0bkok/universal_law_of_demos/

运用之道

接受演示经常会不顺利的事实,做好防范:

做最低限度演示 —— 在可以传达想法/应用/功能的前提下,尽可能减少展示内容。

实际的演示过程会比你预想的长。

至少提前 20 分钟到场,打开在线会议,准备好 PPT。没有什么比一屋子的工程师为如何打开在线会议而争论不休更令人厌恶的了。

准备一个备份演示。想象一下,你即将展示一个新的网站,而在演示前 5 分钟,AWS 出现了故障。你能在本地机器上运行几个页面吗?是否有一个部署在不同地区的低配环境等等......要为最坏的情况做好准备。

小黄鸭调试法

由于演示从来都无法完全按计划进行,你实际上可以利用这一点来发挥自己的优势。如果有什么东西不能正常工作,如你的 IDE 出了问题,你无法重现一个错误,诸如此类。那么,你可以利用演示定律,试着把它展示给一个朋友。通常,在谈论这个问题的时候,你会发现解决方案,或者问题会神奇地消失。

4)格雷沙姆定律

格雷沙姆定律来自 19 世纪的经济学,它指出:

“劣币驱逐良币” [6] ,或者更通俗地说“坏的挤走好的”。

Ben Hosking 在[7]中对格雷沙姆定律在软件工程中的应用做了很好的描述,我把它简单地归结为:

廉价的软件实际上非常昂贵[8]。

image.png

你希望三者兼而有之,但实际上应该把重点放在质量(Godd)上(https://andrewcoppolino.com/blog/fast-good-cheap-pick-two/

运用之道

在理想世界里,每个项目都很快,很便宜,而且还做得很好。然而,在现实中,我们只能追求 3 项中的 2 项,要明智地选择。在某些情况下,我们不得不仓促赶工,但根据格雷沙姆定律,“便宜”是一个谎言。那是技术债务。你应该总是追求把事情做好。

5)计划谬误

在 Daniel Kahneman 的《思考,快与慢》一书中[13],估计谬误是指人类在提前计划时表现出相当大的乐观偏差,导致对完成一项任务所需的时间估计不足。你可能经常会碰到这种情况。例如,最近你是否有什么小差使原本打算用一个小时完成,最后却让你耗费了半天时间?事实上,对于任何任务估计,一般的建议是先将最初的估计翻倍甚至翻三倍,然后你才会对其实际完成时间有一个大致的认识。

image.png

计划谬误的精彩描绘(https://medium.com/geekculture/how-the-planning-fallacy-trips-you-up-3248b7e3978e

以下是计划谬误的几个实际的例子[14]:

悉尼歌剧院原计划于 1963 年完工。但事实是,它的缩小版在十年后的 1973 年才开放。最初的成本估计为 700 万美元,但因为延期成本增加到了 1.02 亿美元。

波士顿中央大道下的“大隧道”工程比计划晚了 7 年才完成,预算为 28 亿美元(1988 年),实际耗资 80.8 亿美元。

加州高铁仍在建设中,预计将超支数百亿美元,与主要城市的连接被推迟到农村段完成后。

运用之道

对任何被认为“应该很快/很容易”的东西持怀疑态度。

在任何时候,在给出最后期限时,务必谨慎地用试探性的问题来回应。例如,“如果 QA 团队在第一轮就碰到了 Bug,那么时间表会有什么变化?”像这样的基本问题可以帮助我们发现那些事后看来很明显的误区和盲区。

当有疑问时,将估计加倍。当应别人要求进行估计时,至少要按最初估计的两倍。有时候,我会按三倍,然后在对方的说服下改为两倍。

6)海勒姆定律

该定律是最近才提出来的,可以追溯到一名谷歌人的博客[12]。该定律指出:

当一个 API 有足够多的用户,

你在契约中承诺了什么并不重要:

系统中所有看得见的行为

都会有某个人依赖……

XKCD 漫画就是最好的例证:

image.png

https://xkcd.com/1172/

运用之道

与墨菲定律类似,你必须注意,人们会以你意想不到的方式使用系统。因此,必须尽量缩小其范围。构建一个让用户可以用两种类似的方式做同一件事的 API?这会让用户感到困惑吗?尽量让接口一目了然、固执己见、简单易用,以至于幼儿园的小朋友都能使用。

最近,我在设计一个 API 时遇到了海勒姆定律描述的情况。简单起见,假设它获取一个用户列表:

fetchUsers() -> {Allan Apple, Bill Banana, Chris Carrot ...}

注意到用户是有顺序的了吗?排序过程是隐式的,因为是在数据库中完成的,API 契约中没有顺序保证。然而,考虑到海勒姆定律,我意识到,最终会有人依赖于这个顺序。因此,我在构建时将它作为 API 契约的一个默认参数fetchUsers(sort=True)。

7)帕累托法则

帕累托法则也被称为收益递减定律,或 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 倍。我可以告诉你,当我成为一名高级开发人员时,我在许多项目中做出了贡献,这比我在之前的工作中从头到尾做一件事更有价值;在我看来,宽度>深度。

8)泰斯勒定律

image.png

图片来源:https://unsplash.com/photos/OopPIi_A428

又称复杂性守恒定律,其思想是,每个系统都有一个固有的不可约减的复杂性,如果要处理它,要么系统变得更复杂,要么交由用户来完成。Larry Tesler 认为,最好是花点工程时间来改进系统,而不是指望用户这么做。这是有道理的——如果你的应用有一百万用户,那么即使一个工程师花费一个月的时间从一项操作中减掉了几次点击,就可以为百万用户节省数百万次点击。

在我自己的生活中,这种情况每天都在发生。当我和谷歌家居说,打开灯,改变它们的颜色。我必须给它两个单独的命令:

嘿,谷歌,把灯开到 50%……(等待 5 秒)……嘿,谷歌,把灯调为白光。

当然啦,在人工智能中支持复合命令难度很大,因此,用户吸纳了这种复杂性。

运用之道

避免增加用户负担的解决方案;观察用户如何使用系统,并设法发现不足。

总是选择花更多的时间在“正确方法”上,而不是“快速方法”上,即格雷沙姆定律。

像用户一样思考——你愿意使用你正在构建的功能吗?

买 8 赠 1——XY 问题

这本身不是一条定律,但感觉应该包括在内。当一个解决方案(Y)的提出没有充分考虑实际问题(X)的背景,就会导致更好的解决方案(Z)被忽视,浪费精力。考虑一下这样一个例子:

老板:“请加大这一页的字体。”(建议解决方案 Y)

工程师:“好的。”

老板(第二天):“你能把它改回来吗?用户说太大了。”

工程师:“好吧——我们一开始为什么要改?”

老板:“我们的一个用户用的是旧版本的 IE,字体渲染有问题。”(真正的问题 X)

工程师:“他就不能用 Chrome 吗?”(备选方案 Z)

运用之道

在上面的例子中,只要工程师问几个澄清式问题,就可以避免浪费精力。老板对解决方案(Y)的执着使他看不到可能更好的解决方案(Z)。

在现实生活中,XY 问题通常始于一些听起来可疑的事情。像“请把字体改大”这样的请求不是一个问题陈述,而是一个解决方案陈述。真正的问题是“此页面在旧的 IE 浏览器上显示不正常”。遗憾的是,有时候需要工程师来提取上下文信息,因为经常会缺少需求和工单。但好消息是,这通常并不难——只要说“让我们复盘下——我们要解决的问题是什么”,99%的情况下你都能成功。

你是怎么想的?我漏掉了什么重要的东西吗?我有什么地方理解的不对吗?欢迎留言,以便我可以修改这篇文章。

目录
相关文章
|
前端开发 JavaScript
常见的8个前端防御性编程方案
常见的8个前端防御性编程方案
146 0
|
Java
编程中最难的就是命名?这几招教你快速上手(4)
编程中最难的就是命名?这几招教你快速上手
79 0
编程中最难的就是命名?这几招教你快速上手(4)
|
3月前
|
算法 Java 程序员
在Java的编程世界里,多态不仅仅是一种代码层面的技术,它是思想的碰撞,是程序员对现实世界复杂性的抽象映射,是对软件设计哲学的深刻领悟。
在Java的编程世界里,多态不仅仅是一种代码层面的技术,它是思想的碰撞,是程序员对现实世界复杂性的抽象映射,是对软件设计哲学的深刻领悟。
68 9
|
4月前
|
SQL Rust 算法
开发与运维编程问题之常见的编程范式的声明式编程如何解决
开发与运维编程问题之常见的编程范式的声明式编程如何解决
|
6月前
|
算法 程序员
编程遗产:祖传代码
编程遗产:祖传代码
|
6月前
|
程序员 计算机视觉
程序员的“防御性编程”
最近都在聊程序员要做好“防御性编程”,"防御性编程"的概念从之前的“保护程序”一下子变成了现在的“保护程序员”,一字之差,千差万别。
程序员的“防御性编程”
|
Java 程序员 编译器
编程中最难的就是命名?这几招教你快速上手(1)
编程中最难的就是命名?这几招教你快速上手(1)
79 0
编程中最难的就是命名?这几招教你快速上手(1)
编程中最难的就是命名?这几招教你快速上手(2)
编程中最难的就是命名?这几招教你快速上手
47 0
编程中最难的就是命名?这几招教你快速上手(2)
|
关系型数据库
编程中最难的就是命名?这几招教你快速上手(3)
编程中最难的就是命名?这几招教你快速上手
55 0
|
敏捷开发 算法 安全
如何写出高质量代码:特征、编程实践技巧和软件工程方法论
如何写出高质量代码:特征、编程实践技巧和软件工程方法论