在软件开发过程中,经常出现一种难解的情况:原本小而美的软件,为何总是会变得越来越复杂?基于这个问题,本文作者总结出了三大定律,它们是软件复杂性的“罪魁祸首”。
原文链接:https://maheshba.bitbucket.io/blog/2024/05/08/2024-ThreeLaws.html
作者 | Mahesh Balakrishnan
译者 | 弯月 责编 | 郑丽媛
出品 | 程序人生(ID:coder_life)
大多数软件工程师,尤其是从事基础设施系统工作的工程师,都会不可避免地陷入不必要的复杂性。究其原因,我认为主要是以下讨论的三条基本定律所致。
第一定律:
随着时间推移,设计良好的系统必然会退化为设计不良的系统
首先,我们给出一个主观定义:设计良好的系统,指的是在一段时间内易于修改的系统;而设计不良的系统,指的是很难修改的系统。
假设 X 是一款设计良好的系统。有人想要修改 X,根据定义,这项工作应该能够快速且轻松地完成,并假设修改后的系统为 X'。接下来,X' 的发展有两种可能性:
第一,继续保持良好设计,即可以再次快速且轻松地修改为另一个系统 X'';
第二,变成设计不良的状态,即很难修改。举个例子,假设有一个设计良好的数据库使用了 RocksDB,并拥有整洁的存储引擎 API。此时,有人添加了一个 getLevelSize 调用,于是这个数据库就很难再轻松地变成非 LSM 存储引擎了。
所以对于系统来说,设计良好只是不稳定且短暂的状态;而设计不良则是稳定且持久的状态。因此在现实中,各个系统会不断退化为设计不良的状态。代码的二阶导数总是负数:代码的变化速度会随着时间推移而下降。
总结:根据这一定律,大多数系统都会随着时间变成设计不良的系统,导致大多数工程师从事开发的也是设计不良的系统。
第二定律:
复杂性是一道护城河(充斥着漏洞百出的抽象)
设计一个良好的抽象需要应用程序在提供实用性与隐藏实现细节之间取得微妙的平衡——当各个系统为了市场份额而相互竞争时,这种微妙的平衡就会被打破,设计者会开始选择提供应用程序所需的一切。
这种选择带来的影响有利有弊:通过吸引应用程序开发者来增加市场份额;同时各个竞争系统很难替换不同的实现。
纵观全球,一些取得了巨大成功的系统 API 都面临一个问题:几乎无法以任何其他方式实现,例如 ZooKeeper 介于顺序和线性化之间的一致性,基于 TCP/IP 的临时节点语义,以及 Kafka 的幂等性生产语义。
总结:根据这一定律,大多数成功或流行的系统都是设计不良的系统,因此大多数工程师从事开发的也是设计不良的系统。
第三定律:
软件复杂性没有基本上限
在现实世界中,由大型团队经长年累月构建的系统,其复杂性仅受限于人类的创造力。最终系统由开发人员的能力、理念和个人癖好决定,每个人都身处复杂的激励机制中。
举个例子,为什么有些副本数据库用自己的 Gossip 层来检测故障,而不是依赖 Kubernetes?
(1)可能是因为技术负责人 A 和开发人员 B 同意使用 Gossip 来进行故障检测,但在 B 编写完代码后,A 意识到容器化的环境并不适合,但经理 C 已经批准了 B 的升职加薪,于是 A 在办公室政治的压力下被迫妥协。
(2)或者这个系统如此设计,是因为 B 认为非容器化的环境是一个很好的选择。
(3)又或者,B 的博士论文讨论的就是基于 Gossip 的协议。
这些原因都有可能导致系统出现一些“有趣的”交互。每个现有系统可能都包含若干你一无所知的 DoS 攻击,就像一个充满复杂性定时炸弹的宫殿,而这些炸弹都是在你进入项目多年之前埋下的。
总结:根据这一定律,设计不良的系统具有无限的复杂性,而工程师在这些系统上工作时会特别痛苦。
那么,我们应该如何应对这种状况呢?在我的职业生涯中,我采用了一种特别的方法,那就是从头开始构建新系统,尽管这种方法的难度非常大。
推荐阅读:
▶被裁 4 个月后,一名印度程序员的“复仇”:怒删前司 180 台虚拟服务器,造成 67.8 万美元损失,被判两年八个月监禁!
▶一个尘封55年的Bug!由17岁学生开发、风靡了半个世纪的经典游戏,被退休程序员发现关键Bug
▶史上首位!17岁中专女生“爆冷”:拿下数学竞赛全球第12名,打败一众名校生和AI参赛者
由 CSDN 和 Boolan 联合主办的「2024 全球软件研发技术大会(SDCon)」将于 7 月 4 -5 日在北京威斯汀酒店举行。
由世界著名软件架构大师、云原生和微服务领域技术先驱 Chris Richardson 和 MIT 计算机与 AI 实验室(CSAIL)副主任,ACM Fellow Daniel Jackson 领衔,BAT、微软、字节跳动、小米等技术专家将齐聚一堂,共同探讨软件开发的最前沿趋势与技术实践。