编程为什么让人如此着迷,又如此痛苦?
愿你穿过焦油坑,仍享受创造。
今天,AI Coding 正以前所未有的速度降低编程门槛。
越来越多人开始亲手构建产品,也重新讨论编程究竟是一门怎样的手艺:它为什么令人着迷,又为什么如此困难。
Frederick P. Brooks Jr. 五十年前在《人月神话》中写下的《焦油坑》,今天读来格外贴近当下。
Brooks 最为人熟知的经历是领导 IBM System/360 及其操作系统的开发。他将大型软件系统的开发比作史前巨兽陷入焦油:真正的危险从来不是某一个困难,而是无数问题同时出现、彼此纠缠。团队越是挣扎,有时反而陷得越深。
编程既是痛苦的,也是快乐的。它让人困于琐碎,也能让创造者把想法变成现实。
愿你穿过焦油坑,仍享受创造。

焦油坑
史前世界里,最鲜明的场景之一就是巨兽在焦油坑中垂死挣扎。
恐龙、猛犸象、剑齿虎……它们越是奋力挣脱,焦油就缠得越紧。没有哪头野兽强大到不会沉没。

过去十年,大型软件系统开发正是这样一个焦油坑。
许多强大的团队都曾在其中激烈挣扎。很多团队最终确实做出了能够运行的系统,但鲜有人能在达成目标的同时,按时交付并控制预算。
困难并不是由某一件事造成。任何单个困难看起来都可以解决,就像一只爪子还能从焦油中挣脱。真正可怕的是,许多因素同时出现、彼此作用,最终让整个项目越陷越深。
要解决这个问题,首先必须理解「编程」这门手艺本身,以及它内在的快乐与痛苦。

程序、产品、系统
大家经常会在新闻读到这样的故事:两个程序员在改造过的车库里做出了一个程序,成果却超越了巨头。
每个程序员都愿意相信这样的故事,因为大家知道,如果只是写一个程序,自己的速度一定远超组织「每年 1000 行」的水平。
但为什么大厂的开发团队至今还没有被专注的车库二人组取代?

1976 年,21 岁的乔布斯与好友沃兹尼亚克在自家车库内成立苹果电脑公司
所谓「程序」,指的是一个本身已经完整、能够由作者在其开发环境中直接运行的东西。这就是在车库里完成的项目,也是程序员在估算自己生产效率时默认参照的对象。
但一个程序想成为真正有用的东西,还要跨过两道边界。
第一道边界,是从程序变成产品。
它不再只满足于作者自己能运行,而是任何人都可以运行、测试、修复和扩展。它可以用于不同的操作环境,也可以处理多种数据。
要成为一个通用的产品,程序必须以更泛化的方式编写。尤其是输入的范围和形式,必须在基本算法合理允许的前提下尽可能泛化。
接着,程序必须经过彻底测试,使人可以信赖它。这意味着开发者要准备、运行并记录一整套规模可观的测试用例,用来探索它的输入范围和边界。最后,还需要完整的文档,让所有人都可以使用、修复和扩展。
根据经验估算,一个产品的成本至少是一个具有相同功能、已经调试好的普通程序的三倍。
第二道边界,是从程序变成系统中的组件。
系统不是孤立程序,而是一组相互作用、功能协调、格式受约束的程序组合。
要成为系统中的组件,程序的每个输入和输出都必须在格式和含义上符合定义好的接口规范。它还要按照既定的资源预算进行设计,包括内存空间、输入输出设备和计算时间。最后,它要和其它组件一起,在各种预期组合中接受测试。
这类测试必须非常广泛,因为测试情况的数量会以组合方式增长。它也会很耗时。即使每个组件单独调试过,组件之间仍可能因为意想不到的相互作用,产生微妙的 bug。
一个系统组件的成本也至少是一个具有相同功能的独立程序的三倍。
一个程序同时成为产品和组件,它的成本则是简单程序的九倍。 但这才是真正有用的成果,也是大多数开发者的目标。

手艺的快乐
编程为什么有趣?
第一,是创造事物本身带来的纯粹快乐。
就像孩子会为自己捏出的泥饼感到快乐,成年人也喜欢创造,尤其是建造由自己设计的东西。
我想,这种快乐大概和上帝创造万物时的喜悦相通:每一片叶子、每一片雪花都各不相同,都是新鲜而独特的。
第二,是创造出对别人有用之物的快乐。
在内心深处,我们希望别人使用我们的作品,并发现它有所帮助。在这一点上,编程系统和孩子第一次做出的「给爸爸办公室用」的黏土笔筒,并没有本质区别。
第三,是塑造复杂对象的迷人感。
程序像一个由许多彼此咬合的部件构成的谜题,你看着它们在循环中运转,让一开始写入其中的规则和逻辑步步展开。
一台写好程序的计算机,就像一台复杂的弹珠机或点唱机:你按下按钮,里面的机关开始联动,最后给出结果。
只不过,程序将这种迷人推向了极致。

世界上最早的通用电子计算机之一 ENIAC
第四,是不断学习的快乐。
编程任务很少重复,问题总会以新的方式出现。解决者也总会学到一些东西:有时是实践性的,有时是理论性的,有时两者兼备。
最后,还有一种快乐,来自程序这种可塑性极强的创作媒介。
和诗人一样,程序员处理的材料就是思想本身。他们就像在空中构建城堡,只凭借想象力便能创造新的世界。
很少有哪种创作媒介像程序这样灵活,如此容易打磨、修改和重构,又如此适合把宏大的构想变成现实。
然而,程序又不同于诗人的文字。它在某种意义上是真实的,因为它会运动、会工作,也会作用于现实世界。它可以打印结果、绘制图像、发出声音、移动机械臂。
神话和传说中的魔法,在我们的时代成为现实。人们在键盘上敲下正确的咒语,屏幕便活了过来,呈现出从未存在、也本不可能存在的东西。
编程之所以有趣,是因为它满足了深藏在我们内心的创造欲,也触动了人类共有的感受力。

手艺的痛苦
当然,编程不全是快乐。
理解它内在的痛苦,会让这些痛苦到来时更容易承受。
第一种痛苦,是必须做到完美。
计算机在这一点上也像传说中的魔法。咒语里只要有一个字符、一个停顿不正确,魔法就不会生效。
人类并不习惯完美,少有什么活动会提出这样的要求。我认为,适应这种对完美的要求,是学习编程最困难的部分。
第二种痛苦,是责任常常大于权力。
你的目标往往由别人设定,信息和资源也由别人提供。程序员很少能真正掌控自己的工作条件,连工作目标也未必。用管理学的话说,就是「一个人的权力不足以匹配他的责任」。
不过,所有领域似乎都是如此。
那些真正把事情做成的工作,几乎都没有与责任相称的正式权力。在实践中,真正的权力不来自头衔,来自持续把事情做成后所形成的影响力。

1979 年推出的 VisiCalc 是全球首款获得商业成功的独立软件,也是世界上第一款电子表格软件
对很多程序员来说,还有一种特别的痛苦:他必须依赖别人的程序。
这些程序往往设计糟糕,实现粗劣,交付不完整,比如没有源代码或测试用例,文档也很差。因此,他不得不花很多时间修复那些在理想世界里本应完整、可获得、可使用的东西。
接下来,还有更琐碎的痛苦。
构想宏大的设计很有意思,但寻找细小的 bug 也是工作的一部分。任何创造性活动都免不了沉闷、乏味、费力的劳动,编程也不例外。
再往后,你会发现调试不会像自己期待的那样迅速接近终点。它只是缓慢推进,越到后面越难。于是测试一拖再拖,最后几个难缠的 bug,反而比一开始那些 bug 更花时间。
最后一个痛苦,有时也是压垮人的最后一根稻草,是你为之辛苦许久的产品,在完成时,或还没完成之前,就已然过时。
同行都在热烈追逐新更新、更好的想法。你的心血之作不仅已被构想出来,甚至已经排上了日程。
但等你完成自己的产品时,那个所谓更新、更好的产品还没有真正做出来,只是停留于谈论。它同样需要数月开发。
只要不真正投入使用,现实中的产品总不如纸上的新方案迷人;可一旦要解决实际问题,真实产品自有它不可替代的价值和满足感。
技术总是向前。
从概念上来说,一旦设计方案定稿,它就已经过时了。但真实产品的落地需要时间,也需要取舍。判断一个方案现是否过时,应当把它和已经存在的成果比较,而不是和那些尚未落地的想法相比。
真正的挑战与使命,是在既定时间下,用可用资源,为真实问题找到真实解决方案。
这就是编程。它既是让无数努力陷入其中的焦油坑,也是一种通过创造价值而切身体悟的欢愉。

文|Yanyang 编辑|Cindy


