编写“老人”程序时要牢记的七个教训十三和十四岁的男孩寻求帮助。神童看了李察一眼,道:“我还以为你会更年轻呢,你多大了,25岁?”“26,”理查德如实回答。“我的上帝。”没错,软件行业向来提倡年轻化。如果你已经有了自己的家庭,那你在编程领域已经是个老人了。而如果你超过25岁甚至超过30岁,那么你未来的科技之路可能只会走下坡路。唉,自以为是的家伙并不总能完美地解决技术问题。虽然他们的大脑充满了关于最新最好的架构、框架和堆栈的技术细节,但他们对软件在基本层面上运行或失败的原因没有充分的理解。当我们连续数周遇到奇怪甚至无法解释的错误时,这些经验只会慢慢积累和积累。就像《硅谷》的观众们心满意足地看着第一季第六集结尾的神童最后搞砸了一样,我们节目中的“老男人”也同样乐于欣赏这群把我们看成“老土”,而是后起之秀因不听前辈劝告而陷入困境的沮丧表情。本着分享的精神,或者作为对年轻人的教训,在这里我们总结了一些远非聪明的头脑和几周的实践就能掌握的宝贵经验。顺便说一下,这些宝物中有很多只有需要两位十六进制数字来写年龄的老人才有。#p#内存很重要不久前,我们计算设备上的内存量以兆字节而不是千兆字节为单位进行衡量。当我组装我的第一台计算机(Sol-20)时,它的内存只有微不足道的KB级别。该设备的主板连接了大约64个内存芯片,每个内存芯片配备了大约18个引脚。具体数字我记不清了,但是我可以肯定每个接头都是自己焊的。焊接任务结束后,我不得不重新加工未通过内存测试的引脚。如果你像我一样经历过记忆是金子的日子,你就会意识到这个小资源有多么宝贵。现在的年轻人没有那么严谨了,更倾向于以一种“差不多够用”的态度来呵护内存资源。他们到处乱放指针,从不清理他们的数据结构,这一切都是因为现在内存太便宜了。他们只需单击一个按钮,即可将16GB的内存容量添加到他们的云实例中。如果每个人都可以那么轻易地从亚马逊租到一个244GB的大内存实例,鬼在编程时会认真考虑内存分配。然而,垃圾回收机制的工作效果总会有局限性,就像父母不能无休止地为孩子打扫房间一样。你可以分配巨大的堆,但最后我们仍然需要清理内存。如果您习惯于像流感一样任意浪费资源并在内存中来回跳动,那么垃圾收集机制的大小很可能会膨胀-并最终填满看似充足的224GB空间。此外,虚拟内存的繁荣也带来了值得关注的隐患。如果我们的电脑因为内存不足而转而使用磁盘进行数据交换,那么软件的运行速度就会降低数百倍甚至数千倍。虚拟内存在理论上确实很有前途,但是在实际效果上太慢了。程序员需要清醒地认识到,在物质丰富的今天,内存资源仍然是非常宝贵的。如果缺少这个科学概念,那么原本在开发阶段以理想速度运行的软件,在投入实践后很可能会出现速度变慢的情况。也就是说,大家的工作成果,根本无法规模化。近年来,可扩展性已成为任何技术解决方案的必要前提。所以请注意在软件或服务遇到瓶颈之前照顾好内存资源。#p#电脑网络速度慢营销人员一直将云服务包装成计算业务世界的一种灵丹妙药,数据可以始终顺畅地来回流动。如果人们想将他们的数据保存在云中,他们还可以使用简单的Web服务产品来提供持久存储、备份和各种其他功能——总之,让服务提供商放心吧。说到请,营销人员宣传的内容确实是真实的,但有一点他们不说——顾客需要等待,漫长而无情。进出计算机的所有流量都需要时间。与CPU和本地磁盘驱动器之间的传输速度相比,计算机网络一直是缓慢的乌龟。编程界的前辈们可以说是“生于新中国,长于红旗下”。在那些艰难的岁月里,互联网甚至还没有雏形。FidoNet以对话方式将我们的数据路由到可能靠近目的地的其他计算机。为了跨越国界,我们的数据传输速度可能比人慢——要花几天时间通过无数吱吱作响的调制解调器。这段惨痛的经历告诉他们,正确的处理方式应该是在本地处理尽可能多的计算任务,并保证远程Web服务只需要处理小规模的最终结果。今天的程序员可能不会体会到老一辈无产阶级开发者的血汗教训,以及云存储承诺的不靠谱这一事实,直到最后几毫秒,他们才可以放心地将任务卸载到云服务上。#p#编译器存在漏洞当我们遇到故障时,实际上导致问题的往往不是我们编写的代码。我们可能忘记了初始化某些项目,或者未能及时检查空指针。不管实际原因是什么,每个程序员都明白,当软件出现故障时,责任必须落在我们身上——句号。事实上,最头疼的不是我们自己的编程错误。有时责任在于编译器或解释器。虽然目前的编译器和解释器在稳定性方面都比较靠谱,但离完美还有很长的路要走。必须承认,无数的技术人员花费了大量的心血才使今天的编译器和解释器具有了现在这样的稳定??性,但将这种稳定性视为理所当然仍然是不明智的。需要提醒的是,编译器和解释器也可能会失败,遇到问题时也要考虑到两者的调试力度。如果不清楚编译器出现问题的原因,寻找答案可能需要几天甚至几周的时间。很久以前,资深程序员就意识到,有时调试问题最好的方法不是测试自己的代码结果,而是关注工具。如果大家习惯性地认为编译器本身不会出问题,不假思索地归咎于代码的渲染和计算过程,往往需要几天甚至几个月的时间才能找到根本不存在的问题根源。年轻人,相信你们很快就会在实践中成长起来。#p#速度对用户很重要很久以前,听说IBM对可用性问题进行了研究,发现响应时间超过100毫秒后,人的意识会出现波动。这个结论对不对?我尝试了一个搜索引擎来验证这一点,但是互联网中断了......我忘记了之后再试一次。经历过IBM大型机古董级绿屏应用时代的朋友一定知道,IBM设定了100毫秒,这个导致人脑失去意识的时间分水岭,作为响应速度的阈值。考虑到这一点,他们在I/O布线上投入了大量精力。在销售其大型机产品时,蓝色巨人的员工使用详尽的规格列表指定设备中的I/O通道数量,这与汽车制造商描述其发动机规格的方式相同。诚然,这些设备会像现代产品一样崩溃,但当它们正常运行时,数据总是通过预设渠道顺利流向最终用户。我见过相当多的程序员努力调整他们的大量AJAX项目,以致于由于JavaScript库的绝对数量和流向浏览器的绝对流量而崩溃。他们经常抱怨说,将他们陷入泥潭的缓慢创新努力与他们正在更换的陈旧绿屏终端进行比较是不公平的。但企业的其他部分应该感谢。毕竟,我们现在的应用程序中有更好的图形和更多的颜色表示。毫无疑问,CSS让一切变得更酷、更漂亮,唯一让用户不满意的是它的响应速度慢。#p#真正的网络永远不会像办公网络一样快。现代网站通常就像是随着时间的推移而建立起来的猪。将数兆字节的数据从JavaScript库传送到浏览器通常需要几秒钟。接下来,浏览器需要将这些多层的MB数据推送给JIT编译器。如果我们把重新编译世界上所有jQuery所花费的时间累积起来,总长度很可能达到数万甚至数百万年。喜欢使用各种基于浏览器的工具的程序员往往会犯一个常见的错误-以无处不在的方式滥用AJAX。在办公室环境中的演示中,这一切都运行良好,服务器本身在这些条件下位于桌子后面的机柜中。有时“服务器”也在本地主机上运行。当然,文件动动手指就能到达指定位置,整个运行过程非常流畅,即使是老板在房间角落测试时也能游刃有余。但是,当用户使用DSL连接或需要通过已经过载的蜂窝塔在蜂窝网络上进行路由时会发生什么情况?他们需要花费大量的时间来等待图书馆的资料送达。如果他们不能在几毫秒内到达那里,他们通常会在TMZ上发表文章并抱怨。#p#算法的复杂度很重要在某个项目中,我遇到了理查德在《硅谷》生活时遇到的同样问题,和他一样,我把目光投向了一个还未到醉酒年龄但正在喝酒的人已经很熟悉Greasemonkey的前世今生了。他重写了我的代码并将结果发回给我。看了改动才知道,他只是把代码内容细化了,同时也把算法的复杂度从0(n)提高到了0(n^2)。他坚持把数据放在一个列表中来实现匹配,看起来确实很漂亮,但是随着n值的增加,会导致代码运行越来越慢。算法复杂性问题在大学计算机科学课程中得到了很好的解决。然而,许多来自各大班级,利用周末自学精通Ruby或CoffeeScript的年轻人,却根本无法深刻领会其精神。复杂性分析似乎是一个非常深奥的理论问题,但随着项目规模的变化,它呈现出截然不同的面貌。当n值很小的时候,一切都很容易实现。尤其是当内存容量充足时,代码的执行速度会令人满意,即使是糟糕的算法此时也能通过测试。然而,当用户乘以乘法时,那些包含0(n^2)甚至0(n^3)的算法会让用户陷入无尽等待的噩梦中。当我问这位年轻的天才是否可以将匹配过程转化为二次算法时,他挠了挠头。他不知道我在说什么。后来我把他的列表换成一组哈希表,一切又顺利了。但到现在为止,我认为他一定已经足够大了,可以理解这个主题了。#p#库可能很糟糕编写库的技术人员并不总是考虑到我们普通用户的兴趣和愿望。他们确实尽力提供帮助,但他们的重点往往是改变整个世界,而不是我们每天面临的小问题。他们最终得到的往往是一把可以解决许多不同版本问题的瑞士军刀,而不是针对手头问题的深度优化解决方案。图书馆项目的工程和编码水平毋庸置疑,但它的运行速度却让人不敢恭维。如果您不更加注意这一点,库本身很可能会在您甚至没有意识到的情况下将我们的代码工作拖入缓慢的泥潭。我曾经请一位年轻的程序员帮我微调我的代码,因为我写了十行代码来从字符串中提取字符。“我可以用一个正则表达式和一行代码来做同样的事情,”他自信地说。“从十行到一行,这是看得见、摸得着的进步。”但他没有意识到,他的这行代码在每次调用正则表达式时都需要经过解析和重新解析的过程。他单纯的认为他写的是一行代码,而我是十行代码,所以他比我高明到不知何去何从。如果使用得当,库和API可以发挥巨大的作用。但如果在内部循环中使用,它们会对速度产生毁灭性的影响——而各方往往完全一无所知。原标题:编程“灰胡子”核子可乐翻译的7堂永恒课
