软件开发的历史与未来(第一部分):从打孔卡到C语言的演进

本文深入探讨软件开发的历史演变,从20世纪60年代的打孔卡编程到70年代家用计算机的汇编开发,再到C语言的兴起。通过具体的技术细节和历史案例,展现了开发环境、编程工具和协作方式的变革轨迹。

软件开发的历史与未来(第一部分)

即使回溯短短几年,软件工程的面貌也已有所不同。但如果回溯20年呢?70年前呢?我们还能认出当时的软件开发方式吗?

图片来源:Alexandra Francis

当今时代的开发者已经习惯了完善的开发环境。从精心调校的vim/emacs配置到庞大的AI驱动套件,软件开发变得异常便捷。内置语言服务器、代码检查工具、自动文档生成、语法高亮,甚至版本控制——这些都是现代软件开发生态系统的产物。我们仿佛生活在梦中!

然而…
过去并非总是如此。即便回溯几年,情况也有差异。若回溯20年、40年甚至70年,我们是否还能理解当时的软件开发方式?让我们共同探索软件开发的历史脉络与未来展望。

打孔卡的作用

你是否好奇为何某些文本编辑器和开发者喜欢在代码达到80列时换行?连Python的PEP8风格指南也如此建议!这其实与打孔卡有关。是的,就是我们在想象1960年代计算机时都会想到的打孔卡。当时的软件开发者使用打孔卡在大型主机上存储和执行代码。

实际开发并非在卡片上进行,程序是写在名为"编码表"的绿色相间纸张上。程序员在此编写和调试代码,每张编码表可容纳多行代码(示例可见原文链接)。随后编码表被送至"打孔卡部门",通过IBM029等机器转换为实体打孔卡。每张卡片最多容纳80个字符(含空格),超出部分需使用新卡片,这意味着单张编码表可能产生多张打孔卡。

开发大型软件需要成堆的打孔卡——1000行代码对应1000张卡片,且必须保持顺序。想象不小心打翻千张卡片的场景!当时的开发者常遭遇此种困境,因此发明了各种标记卡片顺序的创意方法。

这些打孔卡通常用于批处理:将卡片堆送至计算中心,待计算资源空闲时运行程序。这是种"一锤子买卖",若运行失败只能纸上调试后重来。如今听来骇人,但在当时却是革命性技术。

(附:网友制作的打孔卡网页模拟器链接,可亲身体验)

家庭编程革命

将视线从商业主机转向家庭场景,Meet the bedroom coder。1970年代中期,廉价家用计算机成为现实。Altair 8800、IMSAI 8080、Commodore PET、Apple II和TRS-80等设备让编程进入寻常家庭。

这些计算机让开发者同时置身于过去与未来。由于硬件限制,重要软件需用机器码或汇编语言编写(有时甚至需拨动开关)。通过直接操作比特位,开发者能充分发挥硬件性能。汇编语法取决于计算机架构(Z80、MOS 6502、Intel 8080等),甚至具体到使用的汇编器。

以Tandy TRS-80 Model 1为例:开发者通过磁带加载EDTASM工具,编写汇编代码后存回磁带,再进行汇编和运行。听起来简单?但汇编编程需直接处理内存地址——必须硬编码数据存储位置。更需考虑编辑器本身也占用内存空间,可能与生产环境地址冲突。

例如在为Commodore 64编写汇编时,需根据开发阶段使用不同的ORG(起始内存位置)定义。开发时汇编器和编辑器会占用内存空间,这或许是史上首例"在我机器上能运行"的兼容性问题。

并非所有编程都使用汇编。BASIC(初学者通用符号指令代码)成为无数人的编程启蒙语言。虽然用其开发的软件运行缓慢,但确实让编程变得平民化。作者的首行代码便是在Commododore 64上用BASIC编写:

1
2
10 PRINT CHR$(205.5+RND(1));
20 GOTO 10

(欢迎在C64模拟器中尝试这段经典代码)

C语言开启新时代

无处不在的C语言即便在2025年仍随处可见,从嵌入式开发到Rust项目中的unsafe代码块。作者在2004年高中时期首次接触Borland C(非C#或C++)。C语言由Dennis Ritchie于1972-73年在贝尔实验室创建,最初用于构建Unix工具(早期C编译器源码仍可在网上找到),直到1980年代才真正普及。

学习C语言必知"K&R C"——由Dennis Ritchie和Brian Kernighan合著的经典书籍。无论使用何种C语言版本,书中内容都是必须兼容的最低标准,正是这本书让作者真正爱上C语言。

当时的开发者如何用C语言构建软件?如何学习相关知识?
答案首先是书籍。由于语言及其框架相对简单(没有如今纷繁的JavaScript框架),软件工程师通过几本书籍就能掌握全部要领。这些书不仅是参考文档,更展示了C语言的潜力空间,让充满热情的工程师能自由探索这种新语言的无限可能。作者学习汇编时也有类似体验——语法本身不复杂,但通过实验与创意能实现惊人成果。

关于代码管理:当时尚无git(2005年才出现),版本控制依赖人工方式。从本地源码管理到墙上图表标记文件归属,在共享系统或早期网络存储环境中,源码共享基本依靠软盘传递。

迭代速度缓慢:软件主要通过物理介质发布,在线更新并不普及(部分软件支持调制解调器更新,但非主流)。因此无法像现在这样快速获取用户反馈。

(建议未接触过C语言的读者在ESP32上尝试MicroPython实现,给C语言一个机会。虽然需要适应时间,但由于现代语言多受C语言启发,你会很快上手。只需小心内存管理问题!)

暂停反思:90年代的技术沉淀

本文篇幅已长,让我们暂停脚步,回顾过去30多年的演进。从绿纸打孔卡到比特操作与C语言编译…其实进步并非天翻地覆。对比C语言与FORTRAN的"Hello World"程序可见一斑:

1
2
3
4
5
#include <stdio.h>
int main() {
  printf("Hello, World!\n");
  return 0;
}

真正的变革将在未来几十年加速爆发:从面向对象编程到万维网,从JVM到LLM…所有这些都将在本博客第二部分揭晓。

(第二部分将于数周后在AWS Builder Center发布,欢迎关注作者账号!)

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计