新手必读:编程前辈留下的五条经典传世心得
虽然年轻就是本钱,不过多年经验能让我们编写出最卓越的代码。
在硅谷,企业招聘人才时总会面临着两难局面。考虑到过去几年中出现的歧视诉讼案,人力资源方面往往不敢询问申请者的年龄。为了解决问题,他们只好想出一些只有老鸟们才懂的梗,希望借此了解对方的从业时间。
计算机行业永远充斥着新的技术与模式,当然也包括新晋程序员。不过必须承认,旧有技术仍然广泛存在。大型机之类的古董级产物可能已经无法登上头条新闻,但其还在运转不休。事实上,目前的Cobol从业者数量仍达到Ocaml、Erlang以及Haskell从业者总和的五倍。
年龄歧视非常普遍,在一定程度上也可以理解。年轻的程序员们不受旧观念束缚,但老鸟们则更加专注且勤奋——至少不会把大量精力分散到自己的PC及智能手机上。
事实上,拥有多年开发经验的程序员曾经经历过一切亲自动手的时代。那时候根本没有什么集成化开发环境、优化编译器乃至持续集成方案,想要的全部工具都得自己想办法解决。毫无疑问,这是年轻一代所想象不到的。
因此我们将在今天的文章中共同了解由编程前辈们传递,并应由新一代新鲜血液继续传承的五项心得。
汇编
不到50岁的从业者们可能根本搞不清mov ah, 09h或者cmp eax, ebx这样的语句。如今的程序员们以为计算机天然需要使用大括号来实现代码块分隔,但实际上最初分隔效果是依靠以上表达实现的。即使是了解Java或者C应当被翻译为二进制形式的朋友,也往往很少或者完全没有实际操作经验。
老程序员们曾拿出大量时间编写汇编代码,这也是原始填制机器码与人类可读版本之间的第一道桥梁。当然,这并不是说汇编仍是一项必须掌握的技术。由于极为冗长且存在大量重复内容,我们很可能在处理汇编语言时犯下错误。如今的编译器已经足以识别各类复杂且仍有优化空间的模式;一部分编译器开发者甚至坚信自己的工具能够编写出水平高于手动构建的代码成果。
也许确实如此,但学习汇编语言的益处在于,我们能够借此了解计算机的工作方式。高级语言带来大量便捷的标准操作设定,例如连接字符串,但这同时也带来了新的陷阱——程序员们开始误以为“加号”在连接两个整数以及对两个整数进行相加时,占用的时长是相同的。实际情况并非如此。操作的耗时要远高于普通连接,而理解汇编代码以及JMP(jump)操作原理的程序员能够顺利做出正确的选择。
另外,理解对象如何在内存中打包并载入至CPU能够帮助我们降低迟缓代码的出现机率。虽然接触过汇编语言的从业者们如今可能不再记得x86代码的编写方式,但他们仍然具备良好的本能,足以发现一切可能导致代码效率低下的状况。
声与光
很久以前,一位程序员告诉我,他对Unix极为厌恶?为什么?因为他在刚刚入行时,使用的是Altair或者Sol 20这样的单用户微机,其一次只能处理一个代码块。
“Unix计算机总是在同时处理多项任务,”他告诉我。“你会听到磁盘突然就转动起来,但却不知道是怎么回事。”
真正困扰他的是,他失去了对计算机当前运作目的的判断能力。在现代计算机当中,没人知道这台设备究竟在干什么——因为其中包含着数不清的软件层,并运行在四核甚至是八核CPU当中。病毒与蠕虫亦可潜伏于其中,而用户完全感觉不到由此带来的性能影响。
前辈程序员们仍然习惯于通过视觉与听觉判断问题,帮助他们理解并调试代码。他们观看数据经过时RJ-45以太网插孔的闪烁,聆听磁道改变时硬盘的响声。他们甚至能够借此意识到不同分页间的差别,甚至借此了解设备在对索引的哪部分进行读写。
这些线索的价值正在逐渐消失,SSD以及无线路由器的大量普及让它们不复存在。但只要智能手机上还有小小的指示标记提醒数据流通,这种敏锐的嗅觉就仍有用武之地。
数据大爆炸
遥想当年,程序员们需要将8个不同的布尔值转化为1个字节。他们对每个存储位都极为珍视,因为当初的容量资源真的非常有限。
现代数据结构则充斥着浪费与随意。XML中的各类标签名称极长,且每个名称都会以额外的斜杠作为结束标记。JSON相对更为进步,因为其无需关闭标签——而只需要大括号,这就让其身材更苗条一点。然而,JSON的标签与字符串内也存在着众多不必要的引号。
好消息是,现代压缩算法能够显著降低数据结构所占用的空间。但压缩并不能彻底解决问题,而前辈程序员们却知道如何从起步阶段避免这种浪费。也正因为如此,MS-DOS 3.0操作系统仍有32MB,这意味着其最大空间占用量也不会超过3200万个字节。
事实上,MS-DOS 3.0诞生于上世纪八十年代初,七十年代的代码在精简程度上更胜一筹。而六十年代的代码——简直就是艺术品。
二进制数学
对bit位的测试与调整并非出于好奇,而是一种必要。某些操作的执行速度太慢,迫使程序员们寻求更理想的方式加以解决。最典型的例子就是除以二相当于在二进制中将小数点向右移一位,而除以十则为十进制中将小数点向右移一位。
相较于正常除法,CPU在处理数位移动时速度明显更快。出色的程序员会利用这种优势加快代码运行速度,而非笨笨地坐等乘法与除法处理。
但如今这种良好的思维方式正在逐渐消失,强大的处理性能足以承载我们的挥霍。不过必须强调的是,这种敏锐的本能在现代开发工作中仍然有着重要价值。
细节累加即为结果
在多数早期处理器中,某些操作的时耗要远高于其它操作。在初代8086处理器中,数学除法要耗费80到190个时钟周期,而将两个数字相加则只需要耗费3个时钟周期。即使当时的CPU主频已经达到5 MHz,大量操作叠加起来也会造成巨大的处理时长差距。
前辈程序员们很清楚每行代码或者每项指令的执行时间差别,他们也明白计算资源是如此宝贵,需要认真规划与管理。错误的操作类型将大大延长处理时间,而错误的数据类型也会带来同样的后果。一旦使用错误的数据结构,我们辛苦打造的程序将瞬间成为垃圾。