写这篇短文,是想表达一下自己对学习和使用过多种编程语言的认识和感想,我要说的不是网络上那些不理性的口水仗和无脑喷,那很无聊。我想说的是语言本身之外的和方法论有关的东西,希望能给你带来些帮助或启发。
在继续之前,我还要坦诚另一层原因,那就是之前听到有人说他们招聘人时,只要看到使用过多种编程语言的人,直接PASS, 理由是泛而不精。这让我感到不安,因为我就是使用过多种编程语言的人。也许怀有这种理由的招聘方不占少数,也许由于涉猎其他而被枉杀的求职者也不占少数, 思考了良久,我觉得有必要站出来做些解释,稍微缓和一下招聘方这种非黑既白的僵硬的认识。
(以下观点全是我基于个人经历,仅代表个人观点)
不同的语言有不同的设计哲学,其方法论差别也很大。我讲个很久前的一件事,有一个纯文本的含有大纲信息和表格元素信息的文档,要求提取出这个文件中的所有大纲和元素并转储成xml文档,如果按照传统的C程序员的思维,要逐行读入,每行都做首字母比较,判断是大纲还是表格元素还是注释,处理方法各不相同:大纲有主有次,表格元素有不同属性,注释要过滤掉……处理起来相当复杂. 我当时用Perl处理,方法是首先拼接所有行,把整个文件变成一条长串,接着用匹配大纲的正则式把单个长串分割为多个大纲短串,再过滤掉不含有效信息的短串,(这些动作用join,split,grep函数连起来,一行就搞定)然后遍历剩下的所有短串,依间隔符分割短串,再过滤掉空白行,然后提取每个表格元素,(这些动作用split,grep,map+split函数连起来,同样一行搞定)然后把每个元素的属性及值存储在Hash表中,最后用xml库函数把列表和哈希结构输出成嵌套格式的xml文件,(总共20几行)这是Perl教我的思维方式,如果我使用C语言的思维来做,无论是代码量,还是调试时间,都要高出很多。不同的语言其强项和短板不同,在你学习和使用这门语言的过程中,它的常见运用方式和思考方式会逐渐入驻到你的大脑中,自然而然地你在考虑问题时就会从不同的角度来看待和衡量。我再讲个近期的事,要做一个表达式解析器,它要能支持数值的四则运算,字符串基本操作,如拼接,取子串,大小写转换等,还要能支持变量,自动类型转换等。我的脑袋中闪现出两种实现方式,一种是传统式的过程思维(单词序列,符号表,运算优先级栈,语法树等)也就是学校里编译原理课程的知识,另一种是对象思维,抽象出个体,给个体添加行为。我选择了对象方式,因为它简洁、优雅。在设计和实现过程中,我采用了Ruby语言的消息式对象方式,一切皆对象,然后向对象发送消息。核心思想是:对任何表达式元素,都可询问它是否能相应某个消息,“HI,你能响应这个消息吗?”,“YES”,“GOOD,那你响应一下这个消息。”或者“NO”, “AH...主人,它不认识这个方法,是不是你写错了?”。(加减乘除是数值元素可响应的消息)可向任意元素发送任意消息,元素可根据期望的返回类型返回具体的(也就是派生类)表达式元素。表达式元素的派生类,如字符串元素,数值元素,变量元素等重写消息响应的实现,这样一来,无论具体值还是嵌套计算式都属于表达式元素,都按同样的方式求值。这种思路和传统思路差异很大,但更简洁优雅,更易扩展和维护。我虽然用的是C#语言,但采用的是Ruby的思维,思维是可以移植的,如果我没有这种思维,实现代价会高很多,不知不觉就给自己和团队带来了损失。除了思维,还有惯用法,我在C#中,多次采用C语言惯用法,比如用位操作来设计和处理开关标志,巧用整数的大小端表示以及负数补码表示的特点 来检测数据流错位等,然而这些用法对于周围C#和Java的同事们就像哥伦布发现新大陆一样。 通过这些事,我想你应该能接受这个事实了:不同的语言会传达给你不同的方法论,当你从多种语言学到多种思维方式之后,再遇到问题时,就可以博取众长,以创新的方式,更加高效地解决问题。
在《精通Perl》的引言中有这么一句:“如果不能列出5个讨厌Perl的理由和事实,就说明你对Perl的理解还不够。这并不是Perl的问题,所有的语言都有缺陷。……你之所以是大师,是因为你知道问题的两个方面、能做出合理的选择、能给别人合理的解释。” 我认为这句话可以延伸到任何语言,即 如果不能列出你使用的语言的三到五个缺点,就表示你对这门语言的理解还不够。 但当你仔细思考这句话时,会发现话里隐含了一个前提,那就是你已经掌握了第二种或更多的语言,只有拿它们对比,你才能真切地体会到两者的强项和短板,做出合理的选择,同时感叹以前“不识庐山真面目,只缘身在此山中”。 还有一句:“你应该花时间读一些关于编程的‘元’编程的书,而不是满足于语法......你须要学点别的语言。作为大师,你须要一直学习。” 这一句是我后来学习更多语言的精神动力。 虽然很久了,但我一直记着这两句话。
曾经有这么一句话,差不多是这样说的:“编程语言全都一个样儿,只要掌握一种,其他就都通了”。最初(07年)我以为这句话是对的,直到大约三年前(12年),我开始怀疑这句话的正确性,大约又过了一年(13年),我发现这句话大错特错,错得离谱。直到现在,我都敢很不客气地说:“说这类话的人,幼稚、狂妄,且很不负责。”,说其幼稚狂妄,是因为一类是没有亲身实践过,“没有实践,没有发言权”,人云亦云,另一类是“穿新鞋,走老路”,甚至生搬硬套,发现可行,就以为是一样的,浅尝辄止;说其很不负责,是因为误人子弟,一个错误的思想不断传播、漫延,其危害不可估量。 我希望这类话没有影响到你,也请你再听到有人这么说时,反驳他,纠正他。
愿意去尝试其他语言,说明人有好奇心,好奇心是优秀程序员的特质。另一方面,有多种思维方式的人更具创造性,更容易给团队想出更多更好的点子,提出建设性意见,避免潜伏的危险等。一个团队若清一色的一种语言,一种思维,那其实是低效的,也是危险的,只是他们身在庐山中,认识不到而已。
程序员们大多狂妄自大,多学几种语言会让他们谦虚起来,学得越多越谦虚。因为接触得越多,就会发现自己不懂的东西越多。接触面就好像井口,半径越小,青蛙看到得星星就越少,越会觉得自己全部都懂,而半径越大,看到的星星就越多,越会觉得自己不懂。当半径大到能看到银河时,感叹自己只是沧海一粟,无比渺小。 认识到自己的不足,在讨论问题时,就会少一些面红耳赤,少一些针锋麦芒,代之以互相欣赏,博取众长。
其实我在说这些话时,也已经狂妄自大了,问题都是有两面性的,有对有不对,有好处也有坏处。比如C#和Java相似性很高,掌握一种另一种就很容易了。对于同一种系别(同一种思维)的语言,确实是能举一反三的,但同一系别就学不到另一种思维方式了。另一方面,通过学习不同语言来学习不同思维方式 有好处,也有坏处,坏处就是所谓的“泛而不精”,因为你没有时间去精通,精通是需要长期锻炼的。然而如果没实践过其他语言的话,单一语言即使长期锻炼,也无法完全地精通。(说不出优缺点,说不出适用和不适用的原因,怎能算精通)
总体来说,我认为学习和使用多种编程语言是绝对有好处的,虽然也有不好的地方,但好处比坏处多得多。对于“泛而不精”和“一通百通”这两种思想,我想你已经明白我是怎么看待的了。
好了,就说到这里,希望此短文带给了你帮助和启发。谢谢阅读。