上一章说软件是凝固的沟通。这一章要回答的是:它为什么非得凝固成这样?为什么你手机屏幕上的 App 不能像跟一个店员说话那样——「今天能不能给我打个折」——当场商量?
答案不在技术细节里,而在一个更根本的分工里:传统软件把「做决定」和「执行决定」拆到了两个不同的时刻。做决定发生在开发时,执行决定发生在使用时。中间隔着一条又深又贵的鸿沟。
编译:把想法烧成陶瓷
工程师写出来的代码,人读起来还行,但机器读不懂。中间要经过一道叫编译的工序——大白话说,就是把人写的草稿一次性翻译成机器能直接执行的形态,翻完草稿就没用了,留下的只有译文。
这道工序很像烧陶瓷:泥坯在窑外怎么捏都行,进了窑,出来就定型了。想改?回炉重烧。编译带来的好处是速度和确定——译文跑起来飞快,行为完全可预测。代价是:从烧窑那一刻起,软件就失去了商量的余地。你手里的 App 是一块出厂的瓷盘,不是一块还在转的泥。
有人会说:不是还有解释执行的语言、还有热更新吗?有,但那只是把窑搬近了点,没有改变「做决定在开发时」这个结构。真正要紧的不是编译这一步,而是下一步。
发布:一堵时间的墙
就算代码改好了,到用户手里还有一道发布流程——大白话说,就是把新版软件成批地、郑重其事地推送到所有用户的设备上。提交审核、打包、灰度、推送,快则几小时,慢则几周。
发布流程是一堵时间的墙:它把软件的变化压成一个一个离散的版本。v1.0、v1.1、v2.0——每个版本都是一批决定的集中凝固。墙的存在有其道理:成批发布意味着成批测试、成批负责,出了事知道怪哪个版本。但墙的另一面是,软件对世界的响应速度,被锁死在了发布周期上。用户今天在地铁上冒出来的一个真实需求,最快也要下个版本才能被满足——如果它幸运地被排进期的话。
if-else 的暴政
现在进到软件的身体里,看它的骨头。传统软件的行为,归根结底由无数个 if-else 撑起来:如果用户是会员就这样,如果不是就那样;如果库存大于零就允许下单,否则显示缺货。
这个结构有个隐秘的暴政:软件能应对的情况,必须在使用之前就被一一预见到、一一写出来。没写进 if 里的情况,软件要么报错,要么装作没看见,要么——最糟的——给你一个莫名其妙但看起来非常自信的结果。
大白话:传统软件像一本填字游戏说明书。说明书里有的情况,它处理得又快又准;说明书里没有的,它连「我看不懂你的意思」都说不出来——因为连这句话都得有人提前写进去。
所以传统软件工程的大量劳动,本质上是一场预见未来的军备竞赛:需求评审在预见,边界情况讨论在预见,异常处理代码在预见。工程师的功力,很大程度上就是「把还没发生的情况想在前面」的功力。而所有预见不到的长尾——那些千奇百怪、每个都只出现一次的真实需求——统统被挡在 if 的外面。这就是为什么再周到的软件也总有「它怎么就想不到」的时刻:不是工程师笨,是 if-else 这个结构注定了,覆盖面是用人力一寸一寸换来的。
硬的收益,硬的账单
把这一章收拢一下。传统软件的「硬」是三层结构叠出来的:编译把行为烧成陶瓷,发布把变化切成版本,if-else 把应对面限定在预见之内。这套结构给了我们便宜、快速、可靠的软件——它支撑了从银行到火箭的一切,它的账单也同样清晰:
- 改的决定,成本极高:一个字段的改动可能牵动几十处凝固的依赖;
- 没预见的,就是不存在:长尾需求被结构性地抛弃;
- 理解的门槛极高:想改软件,先要学会整个开发的行话和流程——「沟通」被专业技术垄断了。
注意第三条。软件既然是凝固的沟通,那么谁能参与这场沟通,就取决于谁能进入这个高门槛的凝固过程。这个门槛,正是 AI 最先拆掉的东西。下一章我们就来看:AI 的「软」,软在哪个时刻。