你好,我是冴羽

AI 写代码越来越猛了,但它懂软件工程的基本定律吗?

它不懂。

AI 可以写出语法正确的代码,但它缺少人类程序员用血泪换来的工程经验。

这些经验被总结成了 56 条软件工程定律

AI 需要学,你更需要学。 因为最终拍板决策的,还是你。

今天我把这 56 条定律全部整理出来,告诉你:

哪些是 AI 写代码时最容易踩的坑,哪些能帮你做出更好的工程决策。

1. 架构设计:3 条救命定律

架构设计三大定律

1.1. 康威定律:你的系统就是你的组织结构

康威定律(Conway‘s Law):组织设计的系统会反映其自身的沟通结构。

这是我见过最准的定律。

如果你的团队分成前端组、后端组、测试组,那你的系统一定会变成:前端调后端 API,后端写接口,测试写用例。看起来很合理?

问题来了:当你需要做一个跨端的功能时,三个组要开会、对接、扯皮。效率直接崩盘。

更好的做法是什么? 按业务线组队——每个小队有前后端和测试,负责一个完整功能。这样沟通成本降到最低。

康威定律告诉我们:先设计组织,再设计系统。 不然你的架构一定会被组织结构拖累。

1.2. 盖尔定律:复杂系统都是从简单系统进化来的

盖尔定律(Gall‘s Law): 能够运行的复杂系统,必然是从能够运行的简单系统演化而来的。

我见过太多团队,一上来就设计超级复杂的架构:微服务、消息队列、分布式事务、服务网格…… 结果半年过去了,系统还没跑起来。

盖尔定律说得很直白:你想一步到位设计复杂系统?不可能成功。

正确的做法是:先做一个能跑的简单版本,然后根据实际需求逐步演化。

  • 不要一开始就上微服务,先做单体应用
  • 不要一开始就做分布式,先做单机版
  • 不要一开始就做高可用,先让功能跑起来

能跑的简单系统,比设计精美的复杂系统有价值 100 倍。

1.3. CAP 定理:分布式系统的不可能三角

CAP 定理(CAP Theorem): 分布式系统只能同时保证一致性、可用性和分区容错性中的两个。

这是分布式系统的铁律:一致性(C)、可用性(A)、分区容错性(P),你只能选两个。

实际上,网络分区(P)是一定会发生的,所以你只能在 C 和 A 之间选:

  • 选 CP(一致性 + 分区容错):牺牲可用性。比如银行转账,宁可系统暂时不可用,也要保证数据一致。
  • 选 AP(可用性 + 分区容错):牺牲一致性。比如社交网络的点赞数,允许短时间内不一致,但系统必须一直可用。

很多新手设计分布式系统时,幻想三个都要。 CAP 定理告诉你:醒醒,不可能。

2. 代码质量:5 条黄金原则

代码质量五大原则

2.1. 童子军规则:让代码比你发现时更好

童子军规则(The Boy Scout Rule): 让代码比你发现时更好。

这是我最喜欢的一条规则。

你不需要大规模重构,只需要:每次改代码时,顺手优化一点点。

  • 看到重复代码?抽个函数
  • 看到烂命名?改个好名字
  • 看到没注释的复杂逻辑?加两行说明

一年下来,代码质量会有质的飞跃。而且不会像大规模重构那样引入新 bug。

2.2. YAGNI 原则:不要写你用不到的代码

YAGNI 原则(You Aren‘t Gonna Need It):不要添加当前不需要的功能。

很多程序员喜欢“未雨绸缪”:这个功能现在用不到,但以后可能会用,先写上吧。

结果呢?90% 的“以后可能用”永远不会用。 你写的代码变成了技术债务,增加维护成本,还可能引入 bug。

YAGNI 原则告诉你:只写当前需要的代码,不要猜测未来。

2.3. DRY 原则:不要重复自己

DRY 原则(Don‘t Repeat Yourself):每一项知识都必须有单一、明确、权威的表示。

重复代码是万恶之源。

当你复制粘贴代码时,你创造了 两个需要维护的地方。改一个地方,另一个地方忘了改,bug 就来了。

DRY 不只是说代码,还包括配置、文档、业务逻辑。 任何知识都应该只有一个权威来源。

2.4. KISS 原则:保持简单

KISS 原则(Keep It Simple, Stupid): 设计和系统应该尽可能简单。

简单不是简陋,是清晰。

一个好的设计,应该让人一眼就能看懂:这个函数做什么?这个类负责什么?这个模块解决什么问题?

如果你的代码需要长篇注释才能看懂,那说明设计太复杂了。

2.5. 过早优化是万恶之源

过早优化(Premature Optimization):过早优化是万恶之源。

这是高德纳(Donald Knuth)说的。

很多程序员喜欢在写代码时就考虑性能:这里用 HashMap 会不会更快?这里用位运算会不会更省内存?

结果呢?代码变得难以理解,但性能提升微乎其微。

正确的做法是:先让代码跑起来,再用性能分析工具找瓶颈,最后针对性优化。 不要凭感觉优化。

3. 团队协作:4 条残酷真相

3.1. 布鲁克斯定律:给延期项目加人只会更晚

布鲁克斯定律(Brooks‘s Law): 给延期的软件项目增加人手只会让它更晚完成。

这是最反直觉的定律之一。

项目延期了,老板说:加人!多招几个开发! 结果项目更晚了。

为什么?

  • 新人需要时间熟悉项目,这段时间他们产出为零
  • 老人要花时间带新人,产出下降
  • 沟通成本指数级增长:3 个人有 3 条沟通路径,10 个人有 45 条

布鲁克斯定律告诉我们:人月不是可以互换的。 9 个女人不能在 1 个月内生出孩子。

3.2. 林格尔曼效应:团队越大,个人越摸鱼

林格尔曼效应(The Ringelmann Effect): 随着团队规模增大,个人生产力会下降。

这是心理学实验证明的:团队人数越多,每个人的努力程度越低。

在 2 人团队中,每个人会拿出 90% 的努力。在 10 人团队中,每个人只拿出 50% 的努力。

为什么? 因为责任分散了:反正有别人在干,我少干点也没事。

所以最好的团队规模是多少? 贝佐斯说:两个披萨能喂饱的团队。 大概 5-8 人。

3.3. 巴士因子:团队的脆弱性指标

巴士因子(Bus Factor):失去多少团队成员会让项目陷入严重困境的最小数量。

这是一个残酷的问题:如果你的核心开发被车撞了,项目还能继续吗?

如果答案是“不能”,那你的巴士因子就是 1。这意味着你的团队极其脆弱。

怎么提高巴士因子?

  • 代码审查:让多人了解每块代码
  • 文档:把关键知识写下来
  • 结对编程:知识自然传播
  • 轮岗:让每个人都接触不同模块

巴士因子越高,团队越健康。

3.4. 帕金森定律:工作会填满所有可用时间

帕金森定律(Parkinson‘s Law): 工作会膨胀以填满完成它所需的全部时间。

给你 1 周时间做一个功能,你会用满 1 周。给你 1 个月时间,你会用满 1 个月。

为什么? 因为人会不自觉地放慢节奏、增加细节、过度打磨。

怎么破? 用更短的迭代周期:不要给 1 个月时间,给 1 周时间,逼自己聚焦核心功能。

4. 项目管理:3 条时间定律

4.1. 九十九十定律:最后 10% 的工作需要另一个 90% 的时间

九十九十定律(The Ninety-Ninety Rule):前 90% 的代码占用前 90% 的开发时间,剩余 10% 的代码占用另外 90% 的时间。

这是每个程序员都经历过的噩梦。

项目进度到 90% 时,你觉得马上就能上线了。结果:边界情况、异常处理、性能优化、bug 修复…… 又花了跟之前一样长的时间。

所以做项目排期时,永远不要相信“还剩 10%”。 把剩余时间乘以 2 才是真实的。

4.2. 侯世达定律:永远比你预期的更久

侯世达定律(Hofstadter‘s Law):完成一件事所花的时间总是比你预期的要长,即使你已经考虑了侯世达定律。

这是一个递归定律。

你预估 1 周,实际用了 2 周。下次你学聪明了,预估 2 周,结果还是延期。

为什么? 因为你永远无法预见所有意外:需求变更、依赖服务出问题、自己生病、突然来的紧急任务……

侯世达定律告诉我们:做排期时,把你的预估再乘以 2-3 倍。 这不是悲观,是现实。

4.3. 古德哈特定律:指标变成目标就失效了

古德哈特定律(Goodhart‘s Law):当一个指标成为目标时,它就不再是一个好指标。

公司说:我们要提高代码质量,所以要求代码覆盖率达到 80%。

结果呢?大家开始写无意义的测试,只为了提高覆盖率数字。 代码质量没提高,反而浪费了时间。

古德哈特定律告诉我们:不要把指标当成目标。 指标只是工具,真正的目标是背后的价值。

5. 系统设计:4 条陷阱定律

系统设计四大陷阱

5.1. 抽象泄漏定律:所有抽象都会泄漏

抽象泄漏定律(The Law of Leaky Abstractions):所有重要的抽象在某种程度上都是有漏洞的。

你用 ORM 操作数据库,以为不需要懂 SQL 了?错。

当你遇到性能问题时,你必须知道 ORM 生成了什么 SQL,是否有 N+1 查询,索引是否生效。

抽象是为了简化,但它无法完全隐藏底层细节。 关键时刻,你还是要懂底层。

5.2. 特斯勒定律:复杂性守恒

特斯勒定律(Tesler‘s Law): 每个应用都有其固有的不可简化的复杂性,这些复杂性只能转移,不能消除。

你想让用户界面简单?那后端逻辑就会变复杂。

你想让后端简单?那前端或者用户就要承担复杂性。

复杂性不会消失,只会转移。 你的工作是决定:把复杂性放在哪里最合适?

一般来说:让专业的人承担复杂性。 程序员承担技术复杂性,让用户界面保持简单。

5.3. 第二系统效应:第二版往往过度设计

第二系统效应(Second-System Effect):小而成功的系统往往会被过度设计、臃肿的替代品所取代。

第一版系统成功了,团队信心爆棚,开始做第二版:这次我们要把所有想法都加进去!

结果:功能臃肿、架构复杂、开发周期长、bug 一堆。 第二版反而失败了。

典型案例:很多创业公司的第二版产品。 第一版简单粗暴但有效,第二版想做大而全,结果死在半路上。

5.4. 分布式计算的 8 个谬误

分布式计算的谬误(Fallacies of Distributed Computing):分布式系统新手设计者常犯的八个错误假设。

新手设计分布式系统时,常犯这 8 个错误假设:

  1. 网络是可靠的 → 错,网络会断
  2. 延迟为零 → 错,网络调用很慢
  3. 带宽无限 → 错,带宽有限
  4. 网络是安全的 → 错,会被攻击
  5. 拓扑不变 → 错,服务器会上下线
  6. 只有一个管理员 → 错,分布式系统有多个管理员
  7. 传输成本为零 → 错,传输数据有成本
  8. 网络是同构的 → 错,不同服务用不同技术栈

设计分布式系统时,必须考虑这 8 点。 否则生产环境一定出问题。

分布式计算8个谬误

6. 测试与调试:3 条铁律

6.1. 林纳斯定律:足够多的眼睛,bug 无处藏身

林纳斯定律(Linus‘s Law):只要有足够多的眼睛,所有 bug 都是浅显的。

这是开源软件成功的秘密。

一个人写代码,bug 可能藏很久。但如果有 100 个人看代码,bug 很快就会被发现。

这就是为什么代码审查这么重要。 不要一个人闷头写代码,让团队成员互相审查。

6.2. 柯尼汉定律:调试比写代码难一倍

柯尼汉定律(Kernighan‘s Law):调试代码的难度是编写代码的两倍。

这是一个残酷的事实。

如果你写代码时用尽了你的智商,那调试时你的智商就不够用了。

所以不要写太聪明的代码。 写简单、清晰、容易理解的代码,这样调试时才不会崩溃。

6.3. 农药悖论:重复的测试会失效

农药悖论(Pesticide Paradox):重复运行相同的测试,随着时间推移会变得越来越无效。

就像害虫会对农药产生抗性,代码也会“适应”测试。

你写了一套测试,最初能发现很多 bug。但随着时间推移,这套测试发现的 bug 越来越少。

为什么? 因为你的代码已经针对这些测试进行了优化,新的 bug 出现在测试覆盖不到的地方。

所以要定期更新测试用例,增加新的测试场景。

7. 性能优化:2 条关键定律

7.1. 阿姆达尔定律:并行化的极限

阿姆达尔定律(Amdahl‘s Law): 并行化带来的加速受限于无法并行化的工作部分。

假设你的程序有 90% 可以并行,10% 必须串行。

你用 100 个 CPU 并行执行,理论上应该快 100 倍?错。

因为那 10% 串行部分无法加速,所以最多只能快 10 倍。

阿姆达尔定律告诉我们:优化性能时,先优化串行瓶颈,再考虑并行化。

7.2. 梅特卡夫定律:网络价值与用户数的平方成正比

梅特卡夫定律(Metcalfe‘s Law):网络的价值与用户数量的平方成正比。

这不是性能定律,但对产品设计很重要。

一个社交网络有 10 个用户,价值是 100。有 100 个用户,价值是 10,000。

这就是为什么社交产品有“网络效应”。 用户越多,产品越有价值,越能吸引新用户。

8. 认知偏误:5 条思维陷阱

认知偏误五大陷阱

8.1. 邓宁-克鲁格效应:越无知越自信

邓宁-克鲁格效应(Dunning-Kruger Effect):你对某事了解越少,往往越自信。

刚学会 React 的新手:React 太简单了,我全懂了!

用了 3 年 React 的老手:React 的坑太多了,我还有很多不懂……

这就是邓宁-克鲁格效应:新手过度自信,专家充满怀疑。

所以当你觉得某个技术“很简单”时,可能只是因为你还没遇到真正的难题。

8.2. 汉隆的剃刀:不要归咎于恶意

汉隆的剃刀(Hanlon‘s Razor):能用愚蠢或疏忽解释的,就不要归咎于恶意。

产品经理改需求,你觉得:他是故意整我!

其实很可能只是:他没想清楚。

大部分问题不是因为恶意,而是因为疏忽、误解、信息不对称。

汉隆的剃刀告诉我们:先假设对方是善意的,多沟通,少猜忌。

8.3. 确认偏误:只看想看的信息

确认偏误(Confirmation Bias):倾向于偏爱支持我们现有信念或想法的信息。

你觉得 Vue 比 React 好,所以你只看 Vue 的优点,忽略 Vue 的缺点。

你觉得微服务是银弹,所以你只看微服务的成功案例,忽略微服务的复杂性。

确认偏误让我们看不到真相。 对抗它的方法是:主动寻找反对意见,质疑自己的假设。

8.4. 沉没成本谬误:不要为过去的投入买单

沉没成本谬误(Sunk Cost Fallacy):因为已经投入了时间或精力而坚持某个选择,即使放弃对你更有利。

你花了 3 个月写一个框架,后来发现有更好的开源方案。但你不想放弃:我都花了 3 个月了,不能白费!

这就是沉没成本谬误。 过去的投入已经无法收回,不应该影响未来的决策。

正确的做法是:评估未来的收益,而不是过去的投入。 如果开源方案更好,就果断切换。

8.5. 帕累托法则:80% 的问题来自 20% 的原因

帕累托法则(Pareto Principle): 80% 的问题来自 20% 的原因。

  • 80% 的 bug 来自 20% 的代码
  • 80% 的性能问题来自 20% 的瓶颈
  • 80% 的用户价值来自 20% 的功能

帕累托法则告诉我们:找到那关键的 20%,集中火力解决。不要平均用力。

帕累托法则80/20

9. 其他重要定律

9.1. 隐姆定律:所有行为都会被依赖

隐姆定律(Hyrum‘s Law):当 API 用户足够多时,系统的所有可观察行为都会被某人依赖。

你设计了一个 API,文档说:返回值的顺序不保证。

但用户发现返回值总是按字母顺序排列,于是他们的代码依赖了这个顺序。

某天你改了实现,顺序变了,用户的代码就炸了。

隐姆定律告诉我们:任何可观察的行为,都会被人依赖。 所以改 API 时要格外小心。

9.2. 波斯特尔定律:发送时保守,接收时宽容

波斯特尔定律(Postel‘s Law):发送时要保守,接收时要宽容。

这是网络协议设计的黄金法则,也适用于 API 设计。

  • 发送时保守:严格遵守规范,不要发送模糊的数据
  • 接收时宽容:尽量兼容各种输入,不要轻易报错

这样系统才能健壮,才能长期演化。

9.3. 林迪效应:存在越久,越可能继续存在

林迪效应(The Lindy Effect):某样东西使用的时间越长,它继续被使用的可能性就越大。

JavaScript 已经存在 28 年了,它还会存在很久。

上周出的新框架?可能明年就没人用了。

林迪效应告诉我们:选技术栈时,优先选经过时间考验的。 不要追新,追稳。

9.4. 坎宁安定律:获得正确答案的最好方法是发布错误答案

坎宁安定律(Cunningham‘s Law):在互联网上获得正确答案的最好方法不是提问,而是发布错误答案。

你在论坛问:React 的最佳实践是什么? 没人回答。

你发帖说:React 的最佳实践是全局状态! 一堆人跳出来反驳,告诉你正确答案。

这是互联网的真相:人们更愿意纠正错误,而不是回答问题。

10. AI 和你都该记住的事

这 56 条定律,不是让你死记硬背,而是让你:在用 AI 写代码或做工程决策时,能想起来有前人总结过类似的经验。

AI 不懂这些,但你必须懂:

  • 项目延期时,想起布鲁克斯定律,不要盲目加人
  • 设计架构时,想起盖尔定律,先做简单版本
  • 写代码时,想起 YAGNI 原则,不要过度设计
  • 做排期时,想起侯世达定律,把时间预估翻倍
  • 遇到分歧时,想起汉隆的剃刀,假设对方是善意的

AI 可以写代码,但它不会权衡。 它不知道什么时候该用微服务,什么时候该用单体。它不知道什么时候该优化性能,什么时候该保持简单。它不知道什么时候该重构,什么时候该维持现状。

这些定律是前人用血泪换来的经验,能帮你和 AI 少踩很多坑。

但也要记住:定律不是教条,要结合实际情况灵活运用。 有时候打破定律,反而是正确的选择。

软件工程没有银弹,只有权衡。 这 56 条定律,是帮你做出更好权衡的工具。

AI 在学,你也在学。但最终做决策的,是你。

我是冴羽,10 年笔耕不辍,专注前端领域,更新了 10+ 系列、300+ 篇原创技术文章,翻译过 Svelte、Solid.js、TypeScript 文档,著有小册《Next.js 开发指南》、《Svelte 开发指南》、《Astro 实战指南》。

欢迎围观我的“网页版朋友圈“,关注我的公众号:冴羽(或搜索 yayujs),每天分享前端知识、AI 干货。

标签: none

添加新评论