代码的未来

松本行弘还有一本书叫做《松本的程序世界》,那本书主要是从Ruby语言入手介绍了许多程序语言设计方面的知识和权衡。

这本书的话题比较宽泛一些,主要是作者对未来编程的预测和判断,包括编程语言,云计算时代的编程,大数据的存储和计算以及多核时代的编程。

在多去很长时间内,程序员因为摩尔定律享受着“免费的午餐”,程序员可以专注于更加高阶抽象的设计。在摩尔定律将要到达极限的同时,多核,云计算,大数据,编程语言,框架依然在不断地发展,计算能力不断提升,存储介质以及容量在不断增加,编程语言和框架再做出更好的抽象,程序员依然可以享受到这些好处,这是未来的趋势。编程语言和框架要结合未来的趋势不断发展和改进。


LSI中的电路是采用一种印刷技术印上去的,在这样细微的尺度中,光的波长甚至都成了大问题,因为如果图像的尺寸比光的波长还小,就无法清晰地转印。可见光的波长范围约为400~800nm,因此最近45nm制程的LSI是无法用可见光来制造的。在这种原子尺度的电路中,保持绝缘也是相当困难的。简单来说,就是电流通过了原本不该通过的地方,这被称为漏电流。漏电流不但会浪费电力,某些情况下还会降低LSI的性能。漏电流还会引发其他的问题,比如发热。随着LSI越来越精密,其密度也越来越高,热密度也随之提高。像现在的CPU这样高密度的LSI,其热密度已经跟电熨斗或者烧烤盘差不多高了,因此必须用风扇等装置持续进行降温。照这个趋势发展下去,热密度早晚要媲美火箭的喷气口,如果没有充分的散热措施,连LSI本身都会被熔化。由于漏电流和热密度等问题,最近几年,CPU的性能提高似乎遇到了瓶颈。大家可能也都注意到了,前几年在店里卖的电脑还都配备了3GHz、4GHz的CPU,而最近主流的电脑配置却是清一色的2GHz上下。造成这个现象的原因之一就是上面提到的那些问题,使得CPU一味追求频率的时代走到了尽头。此外,现在的CPU性能对于运行Web浏览器、收发邮件等日常应用已经足够了,这也是一个原因。

“过程与数据的结合”是形容面向对象中的“对象”时经常使用的表达。对象是在数据中以方法的形式内含了过程,而闭包则是在过程中以环境的形式内含了数据。即,对象和闭包是同一事物的正反两面。所谓同一事物的正反两面,就是说使用其中的一种方式,就可以实现另一种方式能够实现的功能。

在计算机的历史上,提高处理速度的最有效手段,就是换一台新的电脑。计算机的性能不断提升,而且价格还越来越便宜,仅靠更新硬件就能够获得成倍的性能提升,这并不稀奇。

不过很遗憾,摩尔定律并不适用于人类,人类的能力不可能每两年就翻一倍,从工作的角度来看,上面的办法是行不通的。然而,如果你原地踏步的话,早晚会被更年轻、工资更便宜的程序员取代,效率先不说,至少项目的成本降低了,不过对于你来说这可不是什么值得高兴的事。说点正经的,在软件开发中,如果不更换硬件,还可以用以下方法来改善软件的运行速度:

如果将这些方法拿到人类的工作中来,那么“采用更好的算法”就相当于思考更高效的工作方式;“减少无谓的开销”则相当于减少低级重复劳动,用计算机来实现自动化。


话说回来,在这20年的工作生涯中,我几乎没有开发过供客户直接使用的软件,这作为程序员似乎挺奇葩的。不过,我依然是一名程序员。从软件开发中,程序员能够学到很多丰富人生的东西。我从软件开发中学会了如何提高效率,作为应用,总结出了下面几个方法:

看起来这好像都是些浑水摸鱼的歪门邪道,其实这些方法对于提高工作效率是非常有用的。

减负:我们所遇到的大部分工作都可以分为三种,即非得完成不可的、能完成更好但并不是必需的,以及干脆不做为好的。有趣的是,这三种工作之间的区别并非像外人所想象的那样简单。有一些工作虽然看起来绝对是必需的,但仔细想想的话就会发现也未必。人类工作的定义比起计算机来说要更加模棱两可,像这样伴随不确定性,由惯性思维所产生的不必要不紧急的工作,如果能够砍掉的话,就能够大幅度提高工作效率。

拖延:减少不必要不紧急的工作,就能够更快地完成必要的工作,提高效率,关于这一点恐怕大家没有什么异议。不过,到底哪项工作是必要的,而哪项工作又不是必要的,要区分它们可比想象中困难得多。要找出并剔除不必要的工作,还真没那么容易。其实,要做出明确的区分,还是有诀窍的,那就是利用人类心理上的弱点。人们普遍都有只看眼前而忽略大局的毛病,因此,当项目期限逼近时,就会产生“只要能赶上工期宁愿砸锅卖铁”这样的念头。即便如此,估计也解决不了问题,还不如将计就计,干脆拖到不能再拖为止,这样一来,工期肯定赶不上了,只好看看哪些工作是真正必需的,剩下的那些就砍掉吧。换作平时,要想砍掉一些工作,总会有一些抵触的理由,如“这个说不定以后要用到”、“之前也一直这么做的”之类的,但在工期大限的压力面前,这些理由就完全撑不住了。这就是拖延的魔力。


此外,通过在程序中附加类型信息,使得在编译时可以用来进行优化的信息增加,就更有可能生成出高品质和高性能的代码。进一步说,IDE等工具的自动完成等辅助功能,也可以帮助更好地利用类型信息。 静态类型有如此多的好处,但另一方面,小规模的程序中如果强制对类型信息进行描述的话,类型信息所占的比例就会相当大,从而使得程序逻辑的本质被埋没,也会消磨开发的欲望。

为了解决这个矛盾,某些语言采用了类型推导(type inference)机制,而Dart则是采用了“非强制性(可省略)静态类型”(optional typing)的方法。在Dart中,没有指定类型的变量和表达式会被当做Dynamic型,其类型检查在运行时完成。 采用非强制性系统的语言并非只有Dart,这些语言最大的问题在于,如果类型信息是非强制性(可省略)的,在运行过程中类型信息就会逐渐减少,导致可进行类型检查的范围不断缩小。结果,在编译时可以发现错误这一静态类型所具备的优势就没了一半。此外,随着类型信息的减少,能够用于优化的信息也同时减少,从这一点上来说也有点得不偿失。

如果将上述逻辑用Lua编写出来,就是图4这样。基本上,对于任何事件,其处理都可以归结为下面的逻辑: 如果存在规定的操作则执行它。 否则,从元表中取出各事件所对应的“__”开头的元素,如果该元素为函数,则调用该函数。 如果该元素不为函数,则用该元素代替table来执行事件所对应的处理逻辑。