古法软件开发简史(2022前)

为了让可能不记得的年轻读者受益,以及那些宁愿不记得的年长读者,以下是对2020年代早期如何构建软件的历史记录。按照现代标准,这些做法很原始,但在当时被认为是最先进的。我们不应该过于严厉地评判我们的祖先。他们用手头的东西尽力而为。

1、编写函数

在旧世界,开发者手动编写函数。

疯狂吧?

一个字一个字地。他们会坐在屏幕前,把手指放在键盘上,逐行打出逻辑。如果一个函数需要40行,开发者就打出40行。没有捷径。没有委派。人脑构思逻辑,人手执行它,一次一个按键。

一个高级开发者每天可能产生100到200行生产质量代码。这被认为是可观的产出。一些开发者因其产生更多代码的能力而受到赞誉,这些人被赋予"10倍工程师"的头衔,这个头衔意味着他们可以在一天内做大多数人十天才能做的事情。用2026年的术语来说,10倍工程师是指当你煮咖啡时,几乎能跟上在后台运行的单个Claude Code会话的人。

编写函数的过程通常以盯着屏幕几分钟开始,有时更长。开发者称之为"思考"。这备受尊敬。

2、Stack Overflow 的神圣文本

当开发者遇到无法解决的错误时,这种情况经常发生,他们会执行一种称为"谷歌搜索"的仪式。这涉及将错误消息输入搜索引擎,并扫描结果,寻找一个名为Stack Overflow的网站。

Stack Overflow是一个庞大的问答存储库,完全由志愿者维护。该网站运行在声誉系统上,用户通过提供有用的答案获得积分。高声誉分数的用户受到通常保留给宗教人物的敬畏对待。有些人的分数高达数十万,是十多年来回答JavaScript日期格式化问题累积起来的。

典型的Stack Overflow交互遵循严格的礼仪格式。开发者会发布一个问题。在几分钟内,另一个用户会将其标记为2014年某个问题的重复。原发帖者会抗议他们的情况不同。并不不同。2014年的答案会解决问题。开发者会将解决方案复制到他们的代码库中,只更改变量名,然后继续他们的生活。

投票最高的答案并不总是正确的。偶尔,正确的答案位于页面底部,只有三个赞成票和一条评论,写着"这应该是被接受的答案"。找到它需要滚动,这个时代的开发者愿意这样做,因为他们别无选择。

Stack Overflow在2024年底停止接受新贡献,不是因为它选择这样,而是因为新问题的比率下降了90%以上。古代文本仍然作为只读存档可用。人类学家继续研究它们。

3、复制粘贴的艺术

在古代世界,复制粘贴是代码重用的主要机制。开发者会在Stack Overflow、博客文章、GitHub存储库,或者偶尔有人非法上传的教科书PDF上找到代码片段。他们会选择文本,按Ctrl+C(或在Apple制造的设备上按Cmd+C,当时Apple主要是一家手机公司),然后按Ctrl+V将其插入到自己的代码库中。

粘贴的代码很少在第一次尝试时就有效。这是预期的。然后开发者会花十分钟到四小时修改粘贴的代码,直到它在他们的特定上下文中正确工作。这个过程被称为"集成",被认为是核心工程技能。

围绕复制粘贴有一种不成文的礼仪。从Stack Overflow粘贴是可以接受的。从同事的拉取请求粘贴是边缘情况。从你不理解的生产代码粘贴很常见,但从未公开承认。2023年的一项调查发现,超过70%的开发者每天至少复制粘贴一次代码。剩下的30%在撒谎。

4、调试仪式

当软件不按预期运行时,这种情况一直发生,开发者会进行一种称为"调试"的做法。在所有语言、框架和经验水平中,最常见的调试技术是将文本console.log插入代码中。

console.log是一个命令,将值打印到一个称为"控制台"的特殊窗口。通过将这些命令放在代码中的各个位置,开发者可以观察程序实际在做什么,而不是他们认为它在做什么。这两者之间的差距通常很大。

典型的调试会议涉及添加console.log("here"),然后console.log("here 2"),然后console.log("WHY"),然后console.log("WHAT THE FUCK")。这些消息应该是临时的。几个月后经常在生产代码中发现它们。

更复杂的开发者使用称为"调试器"的工具,可以在特定点暂停程序并允许检查其状态。这些工具功能强大且文档完善。几乎没有人使用它们。当被问到为什么时,开发者会咕哝一些关于"流"的东西,然后添加另一个console.log

还有一种称为"橡皮鸭调试"的技术,开发者会向一个无生命物体大声解释他们的问题,通常是一个为此目的保存在桌上的小橡皮鸭。表达问题的行为经常揭示解决方案。

这,回顾起来,是最早的提示工程形式。鸭子是第一个语言模型。它只是零参数。

5、阅读文档

软件库和框架附带文档:解释如何使用它们的书面说明。阅读文档被认为是一种美德,虽然更多是被赞扬而不是被实践。

API文档通常由函数名列表、它们的参数和一句描述组成,这句话用稍微不同的词语重申函数名。名为getUserById的函数会被记录为"通过ID获取用户"。参数:id (string) - 用户的ID。返回:User - 用户。这被认为是足够的。

当文档不清楚时,这经常发生,开发者会直接阅读源代码。这被称为"阅读源代码",以描述朝圣般的严肃语气说出来。

"我不得不阅读源代码,"开发者会说,其他人会庄重地点头。这意味着文档失败了,开发者被迫与代码本身交流。

一些项目有优秀的文档。这些项目以轻柔、敬畏的语调被谈论。"Stripe文档,"开发者会互相耳语。"你见过Stripe文档吗?"Stripe API文档被认为是技术写作的伟大成就之一。它有例子。可工作的例子。开发者会像艺术评论家描述西斯廷教堂天花板那样描述这一事实。

6、集成开发环境

开发者在称为IDE的应用程序中工作,IDE代表集成开发环境。最受欢迎的包括Visual Studio Code(免费,由Microsoft制造,普遍使用)、WebStorm(付费,由JetBrains制造,被喜欢告诉其他开发者他们使用WebStorm的开发者使用)和Vim(免费,1991年制造,被喜欢告诉其他开发者他们使用Vim然后花15分钟解释如何退出它的开发者使用)。

配置IDE是一项重大任务。开发者可能花一整天安装扩展、调整颜色主题、调整字体大小、配置linter、设置键盘快捷键,以及辩论制表符与空格。这不被视为浪费时间。这被认为是专业发展。

IDE提供了语法高亮(为代码的不同部分着色以使其更容易阅读)、自动完成(在你键入时建议接下来的几个字符)和错误检测(用红色波浪线标记错误,与字处理器中用于标记拼写错误的那条相同,因为整个软件开发领域借用了1997年左右Microsoft Word的UX)等特性。

那个时代的自动完成可以建议变量名和函数签名。它不能为你编写函数。它不能解释函数应该做什么。当你改变对需求的看法时,它不能重写函数。用现代术语来说,它是一个非常自信的单个单词自动完成。开发者认为这是一个重大的生产力提升。

7、依赖仪式

软件项目依赖于数百个,有时数千个由其他开发者编写的外部库。管理这些依赖本身就是一门学科。

这个过程从一个名为package.json的文件开始(在JavaScript项目中),它列出了项目依赖的每个库,以及版本约束。安装这些依赖是通过运行一个名为npm install的命令完成的,该命令会从中央注册表下载库,以及那些库所依赖的所有库,以及那些库所依赖的所有库,递归地,直到你的项目包含847个包,总计200兆字节,其中你可能直接使用了12个。

node_modules文件夹,这些包所在的地方,以其大小而闻名。有一个反复出现的笑话,宇宙中最重的物体按顺序是:太阳、中子星、黑洞和node_modules。这个笑话在每次JavaScript会议上重复了大约连续七年。它在大约两年内仍然有趣。

偶尔,库维护者会发布一个糟糕的更新,世界各地的项目会同时崩溃。这种情况经常发生,以至于开发者学会了"固定"他们的依赖版本,这意味着拒绝更新它们。一些项目运行三四年前的依赖版本。没有人想更新它们,因为更新意味着可能破坏所有东西,没有人能预测会破坏什么,因为没有人完全理解依赖树。这被称为"依赖地狱",以中世纪农民谈论瘟疫的语调被谈论。

8、合并冲突

当多个开发者在同一个代码库上工作时,他们使用称为Git的工具来管理他们的更改。Git跟踪每个文件的每次修改,允许开发者并行工作,然后结合他们的工作。

结合部分是出问题的地方。

当两个开发者修改文件的同一部分时,Git无法确定保留哪个版本。它将用一个看起来像<<<<<<< HEAD的特殊语法标记冲突,后跟两个版本的代码,由=======分隔,以>>>>>>> branch-name结束。然后开发者被期望手动确定正确的解决方案。

合并冲突范围从微不足道(两人在同一行添加导入)到灾难性(两人以不兼容的方式重构同一模块)。解决过程可能需要几分钟或几天。在极端情况下,开发者会删除两个版本并从头开始重写该部分,这是一种被称为"核选项"的策略,官方不鼓励,但非正式地常见。

"在我的机器上工作"这句话是代码在一个环境中完美工作但在另一个环境中失败时最常被引用的辩护。这句话如此普遍,以至于成为一个梗,印在贴纸和T恤上。潜在问题,软件根据操作系统、已安装的库、环境变量和月相而表现不同,从未完全解决。它被简单地接受为生活事实,像天气、税收一样。

9、代码审查法庭

在代码可以合并到主代码库之前,它必须经受"代码审查",其他开发者检查提议的更改并提供反馈。这同时是开发过程中最有价值和最可怕的部分之一。

代码审查在一个光谱上运作。在一端,审查者会瞥一眼更改,写"LGTM"(对我来说看起来不错),然后批准。在另一端,审查者会留下47条评论,30条关于格式,10条关于命名约定,5条关于架构关注,2条实际上是重要的。

代码审查的社会动态很复杂。初级开发者审查高级开发者的代码必须小心地表达批评,经常将明显的错误框定为"好奇的问题"。高级开发者审查初级开发者的代码必须抵制重写一切的冲动。两个高级开发者互相审查对方的代码有时会导致关于抽象水平的数天哲学辩论,完全通过GitHub评论进行,而实际功能在等待。

有一个不成文的规则,代码审查的长度与更改的重要性成反比。2000行的重构可能会得到橡皮图章。对关键配置文件的一行更改会产生40条评论的线程,需要三个单独的批准。

10、这把我们带向何方

上面描述的每项实践,截至2024年,都是标准的专业软件开发。不是十年前。不是一代人前。两年前或1 BC,即Claude之前1年。

转变的速度是难以内化的事情。我们从一个一个地手工输入单个函数,到通过描述我们想要什么来生成整个应用程序。我们从复制粘贴Stack Overflow答案,到阅读文档、编写代码、测试它并修复自己错误的代理。我们从console.log("WHY"),到告诉代理"这不工作,找出为什么",然后看着它在几秒钟内追踪问题。

我们仍然非常非常早。

我们今天使用的实践、提示模式、代理配置、模型特定的工作流程,在两年内看起来同样会过时。有人会写一篇这样的文章,关于我们如何手工精心制作系统提示,或手动配置MCP服务器,或像穴居人一样在终端中输入指令。

回顾的教训不是旧方法不好。它们很好。它们是我们拥有的,我们用它们建立了非凡的东西。

3A游戏、操作系统、Adobe Photoshop——你想吧。教训是"我们如何构建软件"不是一个固定的事情。从来都不是。它只是那样感觉,因为变化过去需要几十年而不是几个月。

如果你开始你的职业生涯编写jQuery,你已经经历了五六个范式转变。每一个在当时都感觉永久。它们都不是。

在接下来两年做得好的开发者将是那些以同样的方式对待他们当前工作流程的人:今天有用,明天可丢弃。工具从来不是事情。事情是知道构建什么以及为什么。那部分没有改变。那部分可能永远不会。

现在如果允许我,我需要通过语音界面向AI代理大声喊叫关于一个命名错误的函数,反思一下,这听起来与2019年对我的IDE大喊大叫并没有太大的不同。

工具在变。喊叫保持不变。

这篇文章本来是完全讽刺的,但——不知何故变成了一篇悲伤地准确的历史记录。:)


原文链接: A Brief History of Ancient Software Development (pre 2022)

汇智网翻译整理,转载请标明出处