后来在大三暑假前机缘巧合被高中同学海子推荐去了北京实习,在一家国资背景的通信公司的子公司里做一些SP的行当。那个公司比一般的SP要强不少,要外包一些活计给稍微弱一些的SP和CP(内容提供商)。当时那家公司要做一个CMS系统给下游的这些SP和CP用,都是些输入短信息之类的破事儿,我过去实习就是做这个CMS,80%的时间里是自己一个人做,这才算开始用Java做一个稍微正式一些的程序。负责带我的组长给我介绍了Velocity,而不是扔给我那个当时看起来牛B得让我很担心自己学不会的Struts,让我有了一个还算不错的开始,可以接触一个设计得不错又比较轻量的东西,所以没有被现实世界中的Java开发一下子吓倒。

对于那个时候的我来说,那个CMS我做得还算凑合。当时也不知道什么单元测试,好在运行起来基本没有什么问题。不过整体来说,几乎没有太多设计方面的考虑,也不太懂得Java的接口要怎么用才好,于是抽象也都是基于Java抽象类做的,当然也无意中悟出了模板方法这个东西,直到N年以后才知道这也算是个模式。

虽然80%的时间里都是我自己在做,但是组长会时不时地看一遍我的代码,指出里面一些设计方面不太合适合理的地方,告诉我如果继续这么做的话,过几天你就会编码到很郁闷,不得不停下来大幅调整的。这是我第一次有意识地注意设计。从这个CMS开始,我了解到设计是很重要的,也不断看书看文章、读其他框架的源代码,不断对比自己那个很简陋的CMS的代码,一点点看到它的代码是多么的不方便扩展又暴露了那么多不必要的细节,这大概是我第一次被震撼了——事关设计。

其实实习之前还有个插曲。大概是大三的计算机网络课,老师布置了一个作业要做一个HTTP服务器用来传输静态文件。因为暑假里为了实现一个FTP客户端,我就已经自学了些Java的网络编程,所以这个HTTP服务器我也自然选用Java来做。用Java完成这么个小需求可以说太简单了,即使后来发觉没有多线程支持而自学了Java多线程并加入了这个功能,也没觉得特别困难,不过后来老师检查测试我们的作业的时候,也没考察多线程这块,所以都“奈何明月照沟渠”了。交完作业以后,我像以往一样得意洋洋地扫视自己的代码,忽然觉得似乎可以在这里这里做一层抽象,把HTTP I/O方面的逻辑提取出来,这样就可以用这个类处理静态文件,再用另外的类负责做PHP页面一样的动态输出了!就这样,我就动手开始整理现有的代码,开始向这个方向努力,做了个超简单的原型,也算麻雀虽小五脏俱全,还给这程序起了个J开头的名字——看,这就是个学了Java半年不到的大三小屁孩第一次意识到应该有个Servlet容器。后来这学年完事儿以后就去实习来着,也接触到J2EE的那些规范和Web/Servlet容器,才知道自己鸡血了半天做的东西早就有规范和N多臭遍街的实现了,可是看完人家再看看自己那设计… 唉,于是就把很久以来敝帚自珍的代码直接Shift+Del掉了。惋惜了不到5分钟。

因为当时还在上学,大三而已,所以平时还是会时不时地打开Visual Studio鼓捣些C++和C#。其实除了C++自身造成的boilerplate以外,我还算比较在意代码整洁和性能的,算法虽然不算当时所追求的第一要务,但是还是经常会注意的,再怎么说1秒能做好的事情拖个5秒也纯粹是有病;虽然用着128M SDRAM的机器,也还是可以看到内存会越来越不值钱的,所以空间换时间的小伎俩也是懂得的。当然可以说当时我在算法方面所有的追求都是属于一种很…可以说是纯朴的层次,能省则省,能优化就优化,即使是用Java时也一样,察觉到某些用起来很“舒服”的Java核心类库的调用可能带来很多额外开销的话,肯定会选择不那么折腾的做法,以及不滥用容器类之类的。除此以外,我知道用Java就会有虚拟机带来的额外开销,但是具体怎么优化呢?受当时能力所限,我一无所知。

大概直到近几年了吧,我才真的不忌讳说自己大学时留过级的这件事情。现在回想起来,也不是完全没有后悔当初的所作所为,如果当时“听话”,好好学习,没有逃那么多课去学那些自己感兴趣的“技术”,单凭着对计算机的兴趣,在校期间把基础夯实不是问题,即使老师讲得再少再没水平,上学期间的学习也不会比日后完全没有指导的自学更困难,更别提天大的老师不可能没水平,只是当初心思太活了,觉得他们讲的东西太圡了太没有时代感了。今天看来,实际上自己对底层和基础方面的知识、技术的兴趣一直强过对纯粹的应用方面的兴趣。学了C和C++,还是想看看各种vcrtXX.dll里是什么,glibc在整个系统里是什么地位,libstdc++怎么就显得没它那样“关键”?学了PHP做了个简单的留言板,还是想不通session和cookie有什么关系,X-Powered-By这个设置开不开区别大么?为什么用header()做跳转有时就“headers already sent”,但是meta refresh就没事?Java的虚拟机是怎么做GC的,类装载器干什么用的?异常桟这么神奇,一下子就知道是哪里出错了,是怎么做的?为什么有时又会看不到异常桟里的行号?——这些问题现在看起来都不算什么了,可是在当时那种情况下,对一个上大学前没接触过多少计算机教育的我来说,一边上着学校那些感觉完全和现实生活不搭界的课程,一边在脑袋里琢磨着这些问题,也算得上是往底层钻研了吧,无非是和一般的自底向上的经典路线相反,当年是因为兴趣而一路自顶向下钻研的,所以现在看来自己学到的东西多少都不是那么地系统和全面,而多是兴趣和视野驱动的,很实用主义。而现在,虽然用的语言和平台是Java,但是对底层和计算机基础方面的兴趣丝毫不减,在这方面如果遇到了些问题的话,相比之下要明显比关心公司的产品更让我兴奋得摩拳擦掌。

我想这应该不是偶然吧。作为一个还算说的过去的程序员,好奇心必不可少,了解事物运作方式的好奇心尤其重要,即使是作为平台的Java也完全不能禁锢这样的好奇心——从这个角度来说,Java并没有错。

我刚接触Java的时候,详细讲解Java底层方面的书籍和资料少之又少。当时我虽然明明白白知道世界上有Sun以外的很多组织实现了Java虚拟机,也知道这是因为Java虚拟机是有规范的,于是乎可以有很多种实现,但是常见常用的还是Sun家的,其他的如IBM和BEA的Java虚拟机基本是没办法接触到的,所以还是没什么选择,只能看Sun家的。核心类库的实现倒是可以参考src.zip,但是sun.*和com.sun.*下的内容基本上是不要想了;虚拟机方面可以看Java虚拟机规范和一本《深入Java虚拟机》,虽然过瘾,但是没有任何途径去窥探这跑着Tomcat的Sun家虚拟机到底是怎么样实现虚拟机规范的,又是不是真的如《深入》一书中那样运作的;散落在java.sun.com网站上的一些参考资料可以覆盖到不少Java相关的知识,可是看过也仍觉是隔靴搔痒,都是片段。诸如此类,诸多暗箱和黑盒,至少从我自己的经历来说,直到有OpenJDK之前,想了解些Java平台的底层知识的话基本都是无奈收场。

虽然当时我是个没毕业的学生,弱的不行,不过Java平台相关的资料比较欠缺的事实应该大家都有体会,这种情况下,用Java这样一种封装掉运行时细节的语言去描述一下应用方面常见的设计问题,甚至都可以算是Java在“学术”方面一个很不错的用途了——反正它的运行细节大部分时间里都是和黑盒一样,而在那个动态语言还没有集结发力的年代里,Java语言还算是主流语言里相对简单的一种。至今为止,Java都可以算是各种设计模式的最忠实的拥趸,所有的设计模式都有Java实现,而“得益”于J2EE/Java EE,Java阵营经常有达人总结出很多企业应用方面的模式,比如Enterprise Integration Patterns中的一大票都带着股Java味。在设计模式风头很盛的年代,Java似乎是最带感的语言和平台了。

就像当年我的同班同学里很多人不喜欢C++带来的大批boilerplate代码一样,应用设计模式时的一些繁复编码也逐渐让很多追求简单的程序员感到越来越不可容忍,而随着设计模式被鼓吹到大江南北,每个人身边也更是有很多言必谈设计模式、编码必套用设计模式的人时不时地让大家恶心一下,于是乎设计模式变得不再是那么可爱的东西了,甚至让人讨厌。紧接着恰巧Ruby on Rails也几乎在同期着实火了一把,让一群对Ruby、Python少说十几年的存在都毫无知觉的人一下子找到了新的G点,绝口不提以前常常拿来揶揄Java的运行时效率问题,个个变得喜欢上了这些更加动态的语言,因而更加厌恶语法啰嗦、沉重感十足又早已投靠设计模式的Java、C++,又以Java尤甚,毕竟C++在系统编程方面还算有一席之地,敢骂C++的也只有C程序员,以最坏的恶意揣测的话,这两“害”相权取其轻,Java真是不骂白不骂。可想以前设计模式风头正盛的时候,可是什么语言阵营都有人跳出来用自家语言实现些许模式的,只不过这些当初的设计模式达人现在大概也被当为家贼难防了吧。