商业转载请联系作者获得授权,非商业转载请注明出处。
作者:vczh
链接:http://zhuanlan.zhihu.com/p/19796639
来源:知乎
我有一个想法,不一定对。
第一篇文章(第一篇文章就贡献给投票了 - vczh的日常 - 知乎专栏)果然给了我灵感耶,标题的图片就是从评论里截出来的。为了以后回答那些层出不穷的月经问题,我决定写下这么一篇文章,讲一下我对牛逼的程序员的理解。为什么我要讲这个呢,当然首先我还是觉得自己是很牛逼的,不然我就不会讲这个了(误
一个牛逼的程序员和一个不牛逼的程序员的区别到底是什么呢?懂的算法多就牛逼吗?懂的API多就牛逼吗?或者懂的工具多机会牛逼吗?其实牛逼不能用这些简单的指标来定义。我们觉得一个人牛逼,通常指的是那个人懂的东西非常多。不过懂的东西多而写出来的程序很蠢的话,或者半天搞不定一个问题,我们就会开始怀疑我们的判断了。那到底什么是牛逼呢?
其实这就跟聪明区别于傻逼一样——直觉准!
直觉一半来自于举一反三,举一反三一半来自于那个一,而当你对很多问题都有那个一的时候显然是因为你这些问题都碰过,碰过问题跟只学会知识还不一样,你还要解决他们。那如何才能碰过并解决大量的问题呢?唯一的方法就是熬过那一大段时间,通常是十几二十年。你光是聪明,可以学会很多东西,但是由于实践的时间不够,仍然不足已成为一个牛逼的程序员。所以牛逼本身不是一个可以速成的东西,它是知识和经验的积累,然后是运用你的知识和经验的熟练程度。
我一直都跟别人推荐这篇文章(成年人的思想还能进步么? « 学而时嘻之)讲的就是如何变成一个牛逼的人的。上面说到要变牛逼首先一定要花费这么多的时间。那这么多的时间难道光刷那些傻逼ACM题目就可以变牛逼吗?你刷半年可以,刷十年呢?显然刷ACM题目只能让你从傻逼变成菜鸟,后面还是有很长的路要走的。文章给我们的一个重要的结论就是,你自己在利用这一大段时间练习的时候,每次都要给自己足够难但是又刚好可以做出来的题目来做。等到你把这个题目做出来,你就会觉得很多问题便容易了,这个时候你重复的解决他们只能得到很小的锻炼,于是你要自己寻找更难的题目,一个足够难但是又刚好可以做出来的题目。当然找到一个好的题目也不是那么容易的,反正年轻的时候时间都是不值钱的,等你试图做几个题目发现自己根本做不出来的时候,你就知道什么叫做刚好可以做出来了。
于是逼自己过了这么多年,就算跟我一样整天搞windows,遇到需要用linux的时候也只是问问人看看说明书(不过linux好像没有说明书)的事情了。因为本质困难的东西你都会了,剩下的这些操作问题,只是熟练不熟练的区别而已。
不过到底什么是足够难又刚好可以做出来呢?其实我觉得我小时候编程的学习过程就是很好的一个例子。刚开始自学的时候的确难度是很大,学会了while循环半年后我还总是控制不住自己通过复制代码来做循环的事情,这种感觉就跟哑巴英语一样,你知道那个东西,但是用的时候就是想不起来。当然随着训练的逐步加深,这是可以克服的。
当时我是沿着这么一个路线来走的。首先会用函数画几个图做做模糊啊锐化之类的简单滤镜,其实有算法抄那就是几行代码的实情。然后就开始学习如何写出高性能的程序。自己觉得性能差不多了就开始折腾怎么实现一个RPG。每一步大概都花费了几个月,而且步与步之间的跨越是很大的。当然具体到我当时的情况,难免最后会弄失败,这主要是由于思路的问题,因为没人告诉我要怎么做。我记得很清楚初三的时候做一个RPG,结果在VB6里面试图用Picture控件去搞,不死就怪了。过了两年我终于知道什么是靠谱的方法了,于是就做出了这个(作品:《天地传》)。这个链接还能下载到我当初的Delphi写的代码,小时候的代码就是烂,尽管看起来也有点复杂了,啊哈哈哈。
游戏做完了不能满足于做完,就要开始想模块化的问题了。怎么做一个游戏用的GUI库?怎么做一个游戏用的脚本引擎?怎么给他们制作工具?怎么写一个游戏引擎?怎么写一个RPG Maker?每一个问题想做简单也可以做简单,想做复杂也可以做的很复杂。于是当我问题一个一个的解决之后,都已经来了M$RA了,这也是我为什么后来会做GacUI 和各种奇怪的编译器研究各种奇怪的类型系统的原因了。当然现在做到这地步都不是仅仅为了游戏而做,当时当你做出一个游戏可以用得东西之后,你就要开始想怎么把它做成通用的,使得开发软件也可以用。每一个问题都最终上升了一个台阶,而你觉得容易的问题就不要浪费时间去解决了。
我觉得这应该给大家指出了一个道路,这也是为什么我觉得那些花费那么大精力去研究工具的人很浪费时间的原因了。工作要用的事情就应该占用工作时间去研究,课余的时间当然是花在提高自己的元编程水平上:大概就是算法啊、架构啊、设计模式啊、单元测试啊各种任何语言都用得上的东西了。不过为了训练这些能力,你总得通过真刀真枪的解决什么困难的问题来得到。于是最好的选择就是big clean problem了。这些问题都是定义很清晰但是非常复杂的问题,譬如说我大四尝试并最终成功的一个问题——怎么把C语言编译成x86。当然这只是一个问题,如果你想把它做得实用,要么你要知道怎么写PE文件,要么你要知道怎么跟C++的数据结构和函数指针无缝的结合起来,这就不那么clean了。解决这些边角问题纯粹靠资料,而跟你的水平是没有关系的,如果没有兴趣的话完全没有需要去解决它。当然解决它也不是没有好处的,因为解决了你就弄明白了,你就可以用这些知识来解决你未来的工作里可能会遇到的牛角尖问题了。不过这永远不应该成为你课余学习编程的动力,这就像附加的好处一样。
说到这里我们可以明白,牛逼的程序员,在于它的元编程水平很高的同时,还知道很多奇怪的知识,以便于你在遇到一个真正的工程问题的时候,能正确地在已经掌握的浩如烟海的知识里面联想到正确的那一个小片段,从而经过简短的研究从而立刻解决它。这也是为什么我们觉得牛逼的人知识很多,因为这是一个必要条件。这也是为什么我们觉得牛逼的人写程序很快,因为这是牛逼的结果。
当然对于刚入门的菜鸟来讲,他们还处于连一个工具都没用好的状况,那自然应该花点时间去熟悉工具。不过当你已经掌握了C++、C#、Haskell、Erlang之后再花相当多的精力研究什么Go和Swift,就很划不来了。因为Go和Swift所需要研究的问题其实已经包含在前面的C++、C#、Haskell和Erlang的时间里面了,因此在你使用Go的时候,就应该直接用,万一踩到了坑你跳出来也是相当容易的事情,根本无需花时间去研究Go的细节。当然对于只会写几行php和python的人,花时间研究Go也是好的,因为他们仍然处于连一个工具都没用好的状况。那自然应该花点时间去熟悉工具。
当你至少掌握了一个general purpose的编程语言和一个系统上的API之后,你就不需要花大量的时间去研究另一个类似的general purpose的编程语言和另一个系统的API了,因为这属于举一反三的内容,只要看文档就可以立刻精通了。倘若是完全不同的两门语言,譬如说C#和Haskell,你学会了一门之后还是可以去花时间研究另一门的。
这些事情都不是绝对的。你需要花时间做什么,取决于这个问题是不是够难,是不是刚刚好你可以做出来,再难一点点你就做不出来了。只要你保持这种训练方法长达十年,想不牛逼都难。
想到这里,不禁回忆起小时候的一些傻逼想法。初三的时候曾经试图用Visual Basic 6.0去做一个Basic的解释器,当然最后做出来了,只是性能巨低,因为我把语法树都保存在表格控件里了……不过在当时的知识下面,能用傻逼方法解决这么个问题,也算是进步了不少。