前两天在"构建之法"群里,邹欣老师抛了一个问题。
大意是说,建筑上可以用预制件来大大简化流程——预制墙板、预制房间,甚至整个模块直接吊装到位,现场拼起来就行。软件世界也有"预制件"啊,各种开源库、第三方模块、npm 包,调用一个函数就搞定了,看起来没啥区别。
但邹老师话锋一转——CPU 仍然要执行每一个外部模块的每一条具体指令。
群里安静了一小会儿。
这句话乍一看像是一句技术陈述,但你仔细咂摸,会发现它里面藏着一个挺让人不舒服的事实。
我顺着这个思路往下想了很久,越想越觉得不对劲。今天把这段思考过程分享出来,顺便聊聊邹老师那篇让我反复读了三遍的文章——《软件的分形维度》。
一、你以为你在"拆蛋糕",其实你在"测海岸线"
邹老师文章的核心概念,借的是曼德勃罗那个著名的比喻——海岸线分形。

什么意思呢?你拿一把大尺子去量英国海岸线,量出来是某个数字。你换一把更小的尺子再量,海岸线的细节更多了,数字变大了。尺子越小,细节越多,数字越大——永远收敛不了。
软件工程跟这个玩意儿简直一模一样。
你接手一个大项目,第一步当然是"拆"。WBS——工作分解结构,把大需求拆成模块,模块拆成子模块,子模块拆成具体任务。拆完一看,嗯,清晰了,可以干活了。
然后你开始做。做了三天发现,这个"小模块"里面照样有需求扯皮。扯完扯皮发现,还有脏数据要清洗。清洗完数据发现,测试环境又崩了。
你以为你切开了一块蛋糕,其实你切开了一段海岸线。
邹老师在文章里写了一句特别到位的话——"WBS 切开的不是蛋糕,是海岸线。"
这个比喻精准到什么程度?你去问问任何一个做过软件项目的人,哪个不是拆完之后发现工作量比预估的多了一倍?拆完再拆,拆完再拆,永远有"再往下挖一层"的必要性。这不是管理问题,不是经验不足,这是软件本身的属性。
邹老师管这个叫**"尺度的分形"**。细节之下,永远有细节。

但分形不只这一层。
二、11 行代码干翻全球

2016 年,npm 上有一个叫 left-pad 的包。
这个名字听起来就是那种谁都能写的东西——一个把字符串往左填充的函数,总共 11 行代码。
然后这个包的作者跟 npm 官方闹翻了,一怒之下把自己的包全删了。
结果呢?全球几万个前端项目,构建全部失败。
你没看错。几万个项目依赖一个 11 行代码的包,包没了,全瘫了。
很多人听到这个故事第一反应是"这也太脆弱了吧",然后骂两句 npm 生态就过去了。但邹老师在文章里把这个现象放到了"分形"的框架下,问题一下子变得不一样了——
他管这个叫**"依赖的分形"**。
在物理世界里,一个零件坏了,坏的就是那个零件。你跑步机上少跑 11 步,后面的人补上 11 步就完了。影响是局部的,隔离的。
但软件世界不一样。软件的依赖是一棵树,一棵巨大的、层层嵌套的树。left-pad 看起来在树的最底层,但它长在所有人的心脏里。一个微小的局部故障,沿着依赖树一路传导,引发全局雪崩。
在跑步机上,少跑 11 步,后面的人补上就完了。在软件依赖网络里,这 11 行代码缺在所有人的心脏里。
三、CPU 根本不认你的"抽象"

第三层分形,是让我觉得最扎心的一层。
执行的分形。
你写代码的时候,调一个 saveToDB(),觉得这是一行代码,一个简单的操作。封装好的,开箱即用。
但邹老师说得明白——抽象只压缩了人脑的认知,从未压缩过机器的计算。
你在代码里写了一行 saveToDB(),以为是一步到位。但 CPU 会把这个"一步"展开成底层驱动中几万条机器指令——内存分配、字节对齐、内核态切换、磁盘 I/O 调度……一步变成了几万步。
邹老师文章里有一组对比让我印象深刻:
"人脑是越野车,CPU 是赤脚走过每一个水坑。"
你以为越野车蹚过去了,CPU 说:不好意思,水坑里的每一滴水,我都要踩一遍。
这就是"执行的分形"——你调的每一层抽象,在机器层面都会被展开、铺平、逐条执行。你省的是脑子里的带宽,机器一点也不省。
四、回到群里那个问题:预制件为什么不一样?

看到这里,你可能觉得这三层分形已经很全了。尺度、依赖、执行,该说都说清楚了。
但群聊里那段讨论让我想到了一个更底层的问题——为什么建筑的预制件是真的"简化"了,而软件的"预制件"只是在视觉上简化了?
邹老师在讨论里给了一个极其精准的回答。
建筑预制件遵循的是连续介质力学。一块混凝土墙板,内部纵有无数微观缺陷——气泡、裂纹、密度不均匀——但物理定律会自动通过应力分担把这些风险"平均化"并抵消掉。你不需要知道每一颗沙粒的精确位置,墙板照样立得住。
物理世界会帮你"抹平"微观的复杂性。
但软件运行在离散状态机上。CPU 是比特级执行器,一个 0 和 1 的偏差,一个 > 和 >= 的区别,会百分百、无损耗地传导到宏观结果。
没有"应力分担"。没有"平均化"。每一个微观差异,都是一发精确制导的子弹,直打你的结果。
邹老师原话说得更好——"软件的抽象化封装,只是用黑布遮住了微观悬崖,底层的离散分形依然在黑布下疯狂发散。"

五、一个困扰我很久的问题

读到这里的时候,我突然想到了一个困扰了自己很久的问题。
人类造的计算机,到底能不能无限模拟真实世界?
你可能觉得这是一个科幻问题。但我认真想过,答案其实挺明确的——肯定不能。
原因说出来你可能觉得"废话",但这个"废话"背后藏着一个很有意思的逻辑:
宇宙中每一个原子,都是一个计算单元。
物理规律就是算法,原子就是运算器。万有引力、电磁力、强核力、弱核力——这些不是"背景规则",它们就是每一颗原子正在执行的计算。宇宙有 10 的 80 次方个原子,每一个都在同时运行,每一个都是一个独立的运算单元。
你拿什么去模拟?
就算你造出一台跟宇宙一样大的计算机——那台计算机本身也是宇宙的一部分,它的原子也在跑物理算法。你用宇宙的一部分去模拟整个宇宙?这逻辑本身就打不圆。
所以真实世界是"分布式计算"的极端版本——每个原子就是一台计算机,自带物理规律这个操作系统,永不停机,永不崩溃。
每一个原子就是一个符合物理规律的运算单元。
回到预制件的问题——为什么建筑预制件换个环境也能跑通?因为构成预制件的每一颗原子,它自己就是一台"电脑",自带物理规律这个操作系统。你把一块预制墙板从工厂搬到工地,每一颗原子到了新环境,照样按物理规律运行,照样受力、照样分担应力、照样保持稳定。
它不需要一个"中心处理器"来告诉它该怎么工作。
但软件不一样。
软件的运算单元永远会落回 CPU。
不管你封装了多少层抽象,不管你调用了多少第三方模块,不管你用了多么优雅的设计模式——最终,每一条指令、每一个比特、每一个状态转换,都要由 CPU 来执行。
CPU 是你的"上帝"。所有的运算最终都收敛到这一个点。
这不是架构问题。这是物理底层的差异——连续的分布式计算(原子)vs 离散的集中计算(CPU)。
这也是为什么软件的分形困境几乎不可能被真正解决。因为它的根源不在工程方法上,在计算模型的本质差异上。
六、那我们该怎么办?

写到这你可能会说,说了这么多,结论就是"没救了"?
也不是。
认识到问题的本质,本身就是一种解法。
做软件之前就接受这个事实——你不可能通过"拆"来消灭复杂性,你只能通过"拆"来管理复杂性。WBS 不是帮你消灭海岸线的,是帮你认清海岸线的。
用第三方库的时候也清醒一点——它帮你省的是"写代码的时间",不是"执行的成本"。CPU 不会因为你用的是 React 就少执行几百万条指令。
抽象是一块遮羞布,不是一剂解药。
它能帮你把复杂的东西藏起来,让你暂时不用面对。但它不会让复杂消失。复杂还在那里,在黑布下面疯狂发散,只是你看不见了。
看见了,至少不会踩空。
邹老师文章的结尾有一句话,我读完之后沉默了好一会儿:
"分形不是故障,是特征。"
软件的分形困境不是一个 bug,不是某个人、某个团队的失误。它是软件这种计算形态与生俱来的属性。
就像海岸线不是大自然画歪了,它本来就没有直的。
你接受它,才能跟它共处。
你跟它较劲,它就用复杂度教做人。
这就是我读完邹老师文章、又在群里跟老师讨论之后的一些想法。说实话,很多地方我也没完全想通,尤其是"原子即运算单元"这个类比到底能推多远,我自己也在琢磨。
但有一件事是确定的——当你下次拆需求的时候,记得你不是在切蛋糕,你是在量海岸线。
尺子越小,岸线越长,永远如此。
欢迎在评论区聊聊:你有没有经历过"拆完发现更大一个坑"的时刻?
本文灵感来源:邹欣老师《软件的分形维度》,推荐原文。
往期精彩内容:
Agent特区第27期:一场真实研发团队向 AI Native 转型的完整复盘
Agent特区第26期,一份"失败"的职场复盘,让我想明白了三件事
我参加了一场"不写一行代码"的分享会,发现所有人都在焦虑同一件事
2023年你会写prompt就很牛,2026年你还在写prompt就完了
OpenClaw 小龙虾实战基础揭秘:一个非程序员的 AI 助手使用心得
夜雨聆风