那些年,我追过的语言
从MS-DOS6.0开始,程序君就是微软的狂热拥趸。
这种狂热自win95走上高潮(有谁还记得win95光盘里带的Good Times的MV,请举手,原文链接里可以听),历经《未来之路》,windows2000,最后在dotnet发布后到达顶峰。
那段时间,只要微软反对的,就是我反对的。
不喜欢Netscape Navigator,只因为IE;诅咒过SUN,对Java深恶痛绝,因为NC是PC的死敌,SUN妄图革微软的命;使用Visual Basic,啃MFC,不为别的,就因为powered by Microsoft。
但VB功能太弱(其实还是我水平太差),MFC太乱,以至于大二时,我在给人打工做软件的时候无奈地选择了Delphi。
虽然不怎么喜欢严谨的pascal,但Delphi有让我不得不用的理由。用它写代码清新明快,效率上甩了笨重的MFC几条街,速度上让VB相形见拙。在那个Wake On LAN才兴起不久的年代,我用dephi做的印象最深刻的一个小feature,是通过一台电脑打开(或者关闭)局域网内几十台电脑。看着自己的软件能『神奇』地唤醒机房里的一群电脑,别提多自豪了。
在我上大学的期间,做客户端软件(或者C/S结构的软件)虽然能赚钱,但已经渐渐不酷了,ASP的出现,让我的兴趣移师到web(那时时髦的叫法是:B/S)。ChinaRen的崛起让我萌生了做自己的班级主页的想法,但做出来的东西只能躺在硬盘上,在参加比赛的时候演示两下 —— 那时几乎没有免费的提供MSSQL的服务器,而我做的『网站』,无一不基于MSSQL或者其简化版。微软的世界之外,我并不知道有MySQL这样的替代品 —— 我像一只把头埋在沙子里的鸵鸟,把自己限制在自己构筑的程序世界。
后来DotNet带着微软的万千宠爱出炉,我第一时间接受了它。我一边玩着C#代码,一边继续无视如日中天的Java 2及NB哄哄的J2EE。C#很迷人,一下子让我有种想要扔掉delphi的赶脚,但无奈dotnet framework太大(而且相对较慢,当时),还在使用赛扬的客户无法接受。
程序员在世最痛苦的莫过于最爱的语言(C#)赚不了钱,不喜欢的语言(Pascal)却为你解决生计问题。
C#无法在我的兼职生涯中施展拳脚,只能作为又一个参赛语言或者研究院语言,被我拿着招摇撞骗(那时讲dotnet就好比现在的云计算,大数据,很容易把不懂的人侃晕),写着连我自己也不相信的虚拟企业信息集成系统,混各种核心期刊论文。
毕业后,本来想找份C#相关的工作,却阴差阳错地做了通讯领域,让C取代C#,成了我的主流语言。大学时我的C也就是个习题水平,做过最难的习题不过实现inode模拟一个简单的unix文件系统,然后提供几个shell命令能创建目录,创建和修改文件。到了工作岗位,socket,timer,hash table,ring才真正走出教科书;而伴随着通讯领域的工作,Linux则正式走入我的生活。
认识到了linux的强大和从骨子里透出来的美感,我从此与微软的技术渐行渐远,也离开了混迹多年的codeproject。
写C的日子是枯燥的,尤其是用C写protocol。完整写过的IGMPv3,大部分代码几乎都是不用太动脑子的从协议语言到C的翻译。
那两年正是互联网方兴未艾的时候。google正飞速发展,百度从新浪的搜索提供商(2B)开始寻求面向大众(2C),3721是浏览器的标配,而mediaWiki也随着wikipedia的走红而走红。写出mediaWiki的php,成了我闲暇研究的对象。那时LAMP开始成为时髦词汇,WAMP/Apache Friends为还在使用windows的人们上提供全套互联网开发环境。
后来我在做一个自动化测试系统时感受到了php的力不从心 —— 我缺一门好的胶水语言,在web和system间游刃。正巧坊间一直流传『真正的程序员用C,聪明的程序员用python』的偈子,于是我又学习了python。这下拼图完成了:我用php在前端接受用户提交的任务,用python读出任务,从clearcase中checkout对应的全套路由器代码,编译出image,然后使用pyserial(一个串口库,可以连路由器的串口)和pyexpect(expect的python封装)连上测试环境中的路由器加载编好的image,然后调用测试团队提供的自动测试脚本测试。
那时没有rabbitMQ或者Redis这样的杀器,php和python之间的任务同步做得很土:php把任务插入到数据库,python程序死循环每30s从数据库中读任务。
后来我换到了J家,很快在同事的推荐下小试了一阵QT,QT的slot和signal做得真心漂亮 —— 可惜那时客户端软件彻底从我的技能清单里被移除,我也就没有继续在QT上发力。
那段时间,C让我糊口,php让我保持和web的连接,而python,一直是我做各种小工具的最爱。
期间玩过drupal,symfony。看symfony的作者的screencast,才知道有种开发神器叫TextMate,有个程序员的电脑叫macbook。
symfony对我而言是个很好的布道师,它让我认识了Ruby on Rails和django(源自symfony和二者的对比)。
它的一个联系项目jobeet还为我日后为创业项目起名提供了思路 —— 对,toureet就是这么出来的,而且07年前后这个名字就横亘在我的脑海。这不算个很接地气的名字,但就像初恋一样让人挥之不去。
知道了Ruby on Rails后,我才意识到如今已经是RoR横扫一切的时代,几乎是个创业公司就在用RoR。JavaEye的Robin称自己几天就搭了JavaEye出来,我虽然不怎么混JavaEye,但这还是大大刺激了我一下,让我对Robin和RoR好顿膜拜。
但那时RoR内部分裂了有一段时间,社区正在开始思考如何让分裂的两个分支摒弃前嫌,在RoR3.0大一统。这让我好生郁闷:究竟是等还是不等那遥遥无期的RoR3?毕竟,之前symfony2已经狠狠地摆了我一道 —— 我在1.x上写的代码在2里无法运行,而且2的改动之大让我一时间无法适应。如果现在入手学习RoR2.x,会不会重蹈覆辙?
两权相害取其轻,我最终选择了django。
然后机缘巧合加各种必然,我走向了创业之路。
等我『毕』业时,我已经算是django和javascript的熟手。
javascript是个很有意思的存在。我大概在2000年左右抄(对,抄的)的第一段js是一个问候的代码,大致是检查当前时间,然后提供不同的问候语。很傻很天真。
那时的javascript恶名远扬。除了好玩,没人严肃看待它。
直到几年后prototype.js和http://script.aculo.us出现(谁还记得你们呢?sigh),javascript才开始自我正名。
然后是神一样的jquery。
接下来羽翼丰满的javascript开始玩MVC,代表作是backbone.js。
还玩函数式编程,如ramda.js。
如果要列举javascript对这个世界最大的贡献,那一定是closure(闭包)的思想。虽然closure源自lisp,但lisp太小众;而python/ruby虽也支持closure,但其OO的特性掩盖了closure的光辉;而不具备常规OO能力的javascript,只能另辟蹊跷,对closure进行疯狂的使用,使其发扬光大,让这个概念烙刻在每一个程序员的心中。如今,要是一门新的语言不支持closure,那TA的作者脑子一定进水了。
总之到我创业时,javascript的生态圈已经无比繁荣。途客圈的第一个产品的计划编辑器使用了backbone.js,第二个产品前端全面采用ember.js,而且用coffeescript撰写。
但那时前端打包工具远没有现在这么丰富,现在大家幸福的烦恼是webpack和gulp究竟选who,那是我只能使用makefile自己攒 —— 我写了个makefile把所有的coffeescript整合编译打包。makefile或者类似的工具是一个高效程序员必须掌握的工具,他们能帮你减轻很多事务性工作。
然后javascript在V8的基础上开启了nodejs时代,nodejs让javascript登堂入室,成为后端的一股劲旅。随着es5 / es6 (es2015) 地不断革新,javascript愈来愈活力四射:arrow,promise,tail call(滚蛋吧, for君),let,generator,class等等;当然,es6我最不喜欢的就是class这个语法糖。javascript永不该为了迎合Java/C#用户的口味去添加这种丑陋的,让人思想混乱的语法(你以为你是在用class,其实还是prototype inheritance)。
nodejs让前端工程师开始屌丝逆袭,成了香饽饽。会Python/Ruby的不见得真会写前端代码,但会javascript的已经在后端开疆拓土。
笨重的XML此时已经向JSON让路,前后两端的数据通讯被javascript把持。
mongodb的出现进一步助长了javascript的气焰 —— 连数据库都是JSON(BSON)存储,javascript作为存储过程(这么说好理解些),javascript还有什么不可以?
说说mongodb。这个在传统数据库系统开发者眼中就是一个笑话的文件系统上加了个B+树,用mmap/fsync做持久化的伪数据库抓住了时代的需求,尽管1.x烂成渣,2.x仅仅可用,它还是尽自己努力野蛮生长。如今,在收购了WiredTiger后,mongodb整出来的3.0勉强像个数据库了。这事说明一件事,只要把用户伺候好了,就算一开始是恶丑版的芙蓉姐姐,慢慢地也能清丽脱俗,飞上枝头变凤凰。
废话少说。几乎在一两年间,LAMP改朝换代成了MEAN(MongoDB,Express,Angular,Nodejs/Nginx),nodejs大有当初RoR横扫一切之势。
构建在nodejs上,提倡reactive的meteor.js向整个互联网刮了一阵清风 —— 原来网站的代码还能这么轻巧地让一切动起来!草草学习了花了几个晚上,我写了teamspark (tyrchen/teamspark),成为了途客圈团队内部的标准沟通工具。
可惜不知怎么的,meteor.js的发展渐渐受到瓶颈,打下的良好用户和市场基础在近三年的缓慢更迭中一点点被消磨。今年1.0姗姗来迟,世界已经是天翻地覆。虽然meteor还很诱人,还有简单暴力的原型能力,但如今,meteor的看家本领:reactive已经是烂大街的名词。在reactive programming这上,用户的选择太多太多,meteor已然失去了先发优势(当然,社区优势和资源优势还是有的)。
后来我从互联网回到了通讯领域,趁着一段难得的清闲,好好研究了下concurrency。concurrency自然少不了Joe Amstrong的erlang。erlang相对于我理解的那些语言,有点不食人间烟火的意味。
在erlang身上我贪婪地攫取了很多知识。erlang适应起来很难,尤其你想表达 x=x+1时会感觉那么地痛苦与无助。我颇花了一些时间才搞明白 atoi() 在erlang中究竟怎么实现。
尽管我尚未用erlang写过什么像样的系统,但它对我思想的冲击是巨大的。erlang的小兄弟elixir继承了大哥的英明神武,还从老爷爷lisp那请来了macro这把倚天剑,一时大杀四方,风头盖过了大哥erlang。如今,elixir下的web framework,phoenixframework悄悄地攒了三千多个赞,在github上,一门小众语言有如此威力,让人瞠目。相信这月底,或者下个月出炉的1.0会让ruby rails的社区真正颤抖起来。
之后,我从erlang延伸到了go。go是门优点与缺点同样突出的语言。本来我正是把它当作一个带并发支持的"modern C"来看的,但深入下去后发现,go和C是两个世界的人。go只能在某些场景下替换C,但无法取代C。soft realtime是个魔咒,把几乎一切有GC支持的语言挡在了C的另一侧。现在看来,也许只有rust能从理论上取代c/c++,可集万千宠爱于一身,革命性地提出lifetime management的rust,语法是那么的伤眼(eye bleeding),简直和C++一个娘胎里出来的。我为rust感到着迷,但我实在不喜欢她那如朱紫国皇后的五彩霞衣般的语法。当然,如果你能忍C++,建议开始上手rust,不用GC,却不用管理内存,强大的concurrency支持,好用到爆的pattern matching,你,值得拥有!
go已经发展到1.5版本,但依旧任重道远。首先,它的编译速度比宣称的慢不少,执行速度更是比C差了不少,很多场景下(尤其GC相关),要比JVM下的语言(如scala)差。作为一门强类型语言,go每发展一步,就得纠结一次要不要引入template,最后可能不可避免地,和C#一样,走向一条越来越复杂的不归路(人家C#好歹还有LINQ这样墟鼎里藏着monad的闪瞎眼的神器呢)。
但go精巧的语法(希望一直精巧下去),简洁的思想,语言内置的并发支持,没有任何依赖的二进制可执行文件,让它还是写一些工具最好的对象。
Haskell就不说了。我还能正常地说话,正常地写代码,没有入定到眼见之处一切皆monad。说明我还是个入门很浅的小沙弥。
最后说说clojure。我本无意研习clojure。我对lisp垂涎已久,但我不想一门「JVM上的带有功利主义色彩的lisp方言」毁了我对lisp那朦胧而青涩的爱。所以我的lisp之旅从racket开始,还烂尾了一本racket入门书。后来有个读者化身月老,把我和Rich Hickey间拉了根红线。当我看完他推荐的Rich的一个视频后,我就像脑残了一样,看遍了youtube上所有的高清无码的Rich的演讲。然后就一发不可收拾,夜夜守候在电脑前,和clojure眉来眼去。功利主义其实大部分时候是好的,我们学习一门语言,无非就是让自己能从中受益。racket能让我做很多事情,但clojure是独一无二的。很多时候,用上帝的视角像看待数据一样看待代码,写出的东西能优雅地让自己忍不住想哭。
人的精力毕竟是有限的。很多语言看了看思想,写了写简单的例子(上百行代码)就搁在一边了。我目前用的最多的,是python,javascript和golang。
也许你会问:一门语言究竟多久能掌握?
学精一门语言,也许需要花上三五年的功夫,也许还要更长。
但学精了一门语言后,学第二门一周也就该能入门了(erlang, haskell, lisp除外,因为最难的地方还是领会新的思想)。
现在我不再会对某个公司的技术有特殊的偏见。我拥抱一切能提高生产力的技术。
也许你会问:学那么多语言有什么用?
如果用来养活自己,一门学精了就足够。其它的没什么用,也就消遣消遣。我看中语言背后的思想,会比较用不同语言开发的乐趣。另外,当你喜爱的语言添加了新的特性(或者你用到了某个高级特性),你可以一下子就想到了背后的逻辑:啊,原来这是xxx的思想。于是,你对这两门语言的掌握又加深了一层。
我目前最大的遗憾,是没有静下心来好好看看Java。虽说写Java就像做一个让人昏昏欲睡的仪式,但Java发展二十多年的社区一直在绽放最璀璨的光芒。
虽说对技术没有偏见,但我依然痛恨恶心的IE6/7/8/9;同时,我打心底喜欢一样东西:mac。
如果说对程序员有什么忠告,那就是:Every programmer should use MAC。