1.理论
2.动手
理论展开讲又主要分两方面,知识的广度和知识的深度.
知识的广度是说那些通用的东西,C语言,数据结构,操作系统这些这些反映内功的东西。比如随便说说,C函数调用时的参数栈布局是什么样子?stdcall和cdecl有什么区别?内存池这东西知不知道?I/O多路复用听过没有?红黑树了解多少。哦,红黑树的例子不太合适,概念至少是必须要知道的.详细的细节没完全搞懂问题不大,我比较赞同rob pike的观点:复杂的算法比简单算法更容易出现bug,并且更难实现.应该尽量使用简单的算法和简单的数据结构,下列数据结构对于大多数的实际编程已经足够了:数组,链表,哈希表,二叉树.
据说腾讯面试喜欢装逼考红黑树,所以我花了一天时间弄补习了一下.实际应用中哈希用得比较多.简单的数据结构组合起来就可以发挥无限的威力.比如hash和链表组合的结构,如果没记错的话linux 0.11中文件系统的页缓存管理就是使用的哈希链数据结构.hash用于快速查询找到对应的页,链表用于实现NRU算法.
提升广度的方法,最有效的方式就是不断挖掘自己的兴趣,没有之一。教授任何知识都是被动接受的。而由于兴趣而关注某个东西的时候,学习则成为一种主动过程,很自然会去找对应的资料。以前编译一份源代码时,居然发现链接库文件的先后顺序不同会导致链接失败。然后我就去研究了一下链接,讲链接的资料不是很多,深入理解计算机系统关于链接的章节写得还可以,然后我就对整套的编译过程有了更深入的了解。如果不知道多个c源文件是如何编译到一起的?为什么要头文件和源文件?声明的定义有什么区别?为什么链接失败?编译时如何链接库文件?elf文件格式是什么样子的,里面存了哪些信息,好好去读一下相关知识。还有程序员的自我修养—链接、装载与库这本书也不错。
可能很多人不知道自己该学什么,其实要学的东西太多了,多到花多少时间都学不完呢。只是太多人没有去发现自己感兴趣的东西罢了。我随便提一些关于hash的关键词:bloom filter/ extendible hash/ linear hash/ consistent hash/ ,如果觉得这是新名词,去百度一下,赶紧的~喜欢瞎折腾不是什么坏事。今天觉得这东西好玩研究下,明天觉得那东西好玩研究一下...用不了多久知识和广度就上来了。如果有人觉得根本找不到自己感兴趣的技术或值得自己折腾的东西,那我觉得这样的人根本就不适合学计算机的。
知识的深度强调的是具体某一方面的东西。可以是研究方向相关的。比如说搞机器学习的,分类聚类这些基本概念有没有搞清楚?衡量标准是不要看书,不要问百度,假想现场找个没学过这些东西的同学,你能不能跟他把这些概念描述清楚。svm必须懂点吧(不懂的猛击这里)?贝叶斯的思想要了解吧?像很基础的K近邻聚类,主成分分析之类的,连这些都没弄懂就不要说自己学过机器学习了,免得让人笑话。
当然也不一定非要是自己研究方向。真正找工作时的方向不一定是自己的研究方向。对于自己很感兴趣的东西也可以深入研究的,几个月前我对云计算方面的东西还一无所知。但略略看了一下,也就明白了云计算是在研究什么东西。分布式存储系统像gfs这类,以mapreduce为代表的并行计算框架,chubby分布式锁服务其实是本质上是一致性协议问题,再理论化一点的就那个paxos协议。nosql数据库,memcached缓存。理论方面的支撑还有CAP相关的那套东西。这里有一份很好的资料可以看一下。其实仔细想一想也就那么回事。想想现在的大公司面临的访问量上来以后,单台主机顶不住压力了,就必须在基础架构上做一些事情,然后就要考虑性能,可用性,可扩展性等等问题,这就是所谓云系统架构的东西了。 这方面常用到的技术也就那些。比如数据库顶不住了会把表进行拆,这样的问题是scalable不方便,再把这种划分的思想升级一下就是一致性哈希了。随便写入的速度慢?那我们将写总是限制成append,log-struct文件系统就这么做的。负载均衡?加一个代理层进行动态调度。还有热点数据等问题,多份副本即可以分担访问压力又能提高容错能力。然而多份副本又会导致一致性问题,那分布式环境下的一致性协议又搞出来了。nosql为什么出来?第一,高并发读写传统数据库受不了。第二,海量的数据传统数据库存不下。第三,传统数据库扩展起来不方便。想想这些技术出来的背后的驱动因素,就很容易跟上云计算研究的方向,明白为什么要研究这些东西了。然后...什么不懂就去看什么咯,看着看着知识的深度就出来了。
目前感觉提升知识深度的最佳策略是看论文。作为一个研究生,如何体现出自己与小本的不同?我们在理论上会有更大的优势,而且这种优势只有在某种学术环境中才能培养,走上工作岗位后也许编程技术会更熟练,但有些非常高层建瓴的东西以及学习这些东西的能力可能培养不出来了,包括查资料的能力,英文阅读能力等等,这就是搞科研的意义。读论文一定要读英文的。还有就是挑经典原文读。研究生了就不推荐啃教材了,一般教材都落后于论文几十年的。找到一个研究点,认真看论文就行了。如果基础不太好,可能需要回头补一些基础,这里可以选择挑些教材上的相关章节看。
其实广度跟深度是相辅相承的,而不是相互矛盾的。我在百度一面时,面试官指出我一个问题就是知识面够广但在具体的方向上不够深入。这个观点其实我不能完全认同。尽管专门深入研究某一个方向肯定比每个方向了解一点要好。但面试官的结论基于一个不符合实际的假设:在花费同样精力的情况下。然而,对计算机学科感兴趣的学生花在学习上的精力远远超过被动地学习的那一类人。后者往往连80%的时间都无法把握,而前者不仅会在80%时间里做好自己的工作,还会利用20%的时间充分挖掘自己兴趣,别小看这20%的积累,时间长了之间他们的研究绝对不是“业余”水平,也绝不会没有深度(当然如果是每天研究如何cout<<"hello world"那我就没话说)。真正的牛人大多是这一类,他们无论从广度和深度上都非常优秀.
说完理论说实践。动手能力没有任何捷径,只有二点:多写,多读
再怎么强调动手的重要性也不为过。女生找工作时的劣势,大多也在于她们的动手能力相对太差。
关于多动手写代码这里有三个建议,根据自己当前的能力对号入座:
1.把数据结构书上的东西全部实现一遍
对于基础不算太好的同学,建议把数据结构书中出现的每种数据结构和算法都动手实现一遍。这样编程能力就会有一个质的提升了。我跨专业考研时零基础,曾经就是这样练习的,效果非常好.
不要觉得麻烦或是没必要或者没价值。很多人自以为学会了数据结构,说个数组,链表,二叉树,图,排序算法什么的自己都懂。错!知不知道理论与上机实践完全是两码事,只有上机了才能真正学会。没有将这些东西编码并运行过的人动手能力永远达不到高手级别....仔细看书的人还会发现,数据结构那本书上什么都讲了,就严蔚敏那本。字典树,并查集,动态内存管理,伙伴系统,也许对很多人是陌生的东西,其实书上都讲过了,只是学的时候没认真看而已。
2.找适当大小的东西练手
这个就靠自己去发掘合适的东西了。找一切的机会给自己练手。比如学操作系统中PV操作的时候,就可以试试用pthread线程库和信号量,互斥锁之类的去模拟生产者消费者等问题。像内存池什么的也可以拿来写写练手。看到某个从没见过的数据结构,也可以写着练练。只要有心做,总能找到适合的东西练手的。有意思的东西从来不缺乏,缺乏的是一颗善于发现的心。
3.做项目
写一个相对完整一点的东西,然后开源放到网上。这样不仅可以练手,找工作时还可以写到简历上面。一个人做过的东西就是一份最好的简历。找不到好的项目? github还有sourceforge或者google code上面大把的开源项目。找某个自己感兴趣的代码量不太大的东西读。如果觉得看了之后有什么想法就可以自己改,可以自己重新写,反正就是练习编码能力的。开始可能写不了很大的东西,慢慢来就可以了。比如这些项目memcached,键值存储,用户级的线程库。
再说说读代码的重要性。读过linux内核代码的人跟没读过的人完全不一样,即使只看过一点点,受过那种高质量代码洗礼一个人的动手能力会上升一个档次。并且拿到大的项目也不会发怵不知道从何读起。即使没看懂代码,看一看编码风格也是很好的,单从风格就可以体现出一份代码的质量。比如linux内核是非常优秀的代码,而emacs的源代码糟糕透了,可读性极差。stl的源代码也还行,除了模板技术比较恶心以外,对于学习数据结构还是很有好处的,记得SGI STL里面链表排序就用的一个很精妙的算法:不是分成二半归并接序的,而是搞了好几级队列,分别放2个,4个,8个,16个,32个结点...2跟2合成4,再跟4合成8,这样一级一级地合并上去。STL中还有些代码把循环故意拆成一条条的语句进行优化(编译后机器指令级别的)。stl的sort速度为什么快?其实它是混用好几种排序算法实现的,先对小块进行quicksort,对大于一定大小的块进行mergesort。开源就是一个无比巨大的财富,属于全人类的财富。
看多了一些开源代码就会发现,哪些是常用的小技巧。比如linux内核中的链表就很有巧妙,尤其是那个offsetof给出结构体成员计算结构体首地址,不懂?自己去百度linux内核链表。其实复杂的数据结构都是一点点拼凑成的,说白了就是指针,C语言最精华的部分就在这里体现了。
想开始写个什么东西,可以先到网上找找是否已经有人写过了。一般都能找到现成代码的,好好读读代码,如果有读不懂的地方,就自己实现。以前的那些黑客经常就常常说,因为我读不懂这个代码,所以我自己重写了一个。不过随着现在软件越做越复杂,以至于以一个人的能力无法理解整个代码了。怀念the happy old days! 不过即使不能重写出来,自己尝试着重写的时候也有另一个好处,就是加深对别人代码的理解。有时候就是觉得别人写的代码有些地方怪怪的,不能理解为什么要这么弄。结果自己写一遍,遇到实际的困难之后就能理解作者当时为什么那样做了。不过仅仅读是不行的,一定要自己写。即使是读完别人的东西自己再重写一遍。检查标准是,不要再看他们的代码,能完全地自己写出来,就说明自己真正掌握了。
还有一个小的经验就是读早期版本的代码。因为早期的版本代码量小,读起来会轻松一些。然后看看changelog,挑着看改动。这种学习曲线比直接看最新版代码来得平滑许多。尤其是linux内核这种,最新版的代码量完全没法看了,估计linus自己也无法理解代码的每一行。读读0.11左右的版本会比较轻松一些,有人写了书的。
其它一些杂项
珍爱生命,远离windows
这个本来应该放在第一条的。以我目前的经验来看,linux平台的程序员平均水平要远高于windows,懂linux的程序员平均水平要高于完全不懂linux的程序员。这个很容易理解,现有的教育环境,大学不会教这些,掌握linux的一般就是对计算机技术感兴趣的,好奇心重的,喜欢折腾的人。这类人因为是真正对计算机感兴趣的,所以技术水平会高于平均水平。
写代码有二种哲学,一种是把事情搞简单,尽量的简单所以不会范错。而一种把事情搞复杂,复杂到别人都看不懂了所以找不出其中的错误,然后提供一个相对简单的API封装。window走的采取的是后一种,所以它的技术也不断地更新,api也不断在变,技术人员跟着微软后面跑,累死。windows很不友好,它是给用户用的,不是给开发者用的。而 linux的哲学是KISS,posix的接口就没有什么变化,因为它采取的是前一种哲学。
找工作时,linux也比windows也有优势。想看看高手是什么样子的吧,百度一下“完全使用linux工作”。搞内核,搞服务器的也都是弄linux的。好好学一学linux。
熟习下linux的基本命令,vi或emacs必须学一个,gcc,gdb必须会用,makefile也要懂一点。可以装个ubuntu系统,apt-get什么的,反正也做得比较弱智化了。最好是直接使用linux系统,实在不行装双系统,再不行搞虚拟机。远程ssh到服务器主机也行,就我目前了解到的情况,百度和人人网就是这种开发环境。
多读书,读好书
多读书可以扩展一个人的知识面,也就是上面说的广度。至今仍怀念我本科时的图书馆,怀念当年考研时找个角落抱着书本一啃好几个小时的日子。读书要挑好书读。什么是好书这个到网上百度一下书单,看计算机的别人都推荐些什么书。这里我先说说哪些是坏书,哪些是不值得读的书。
首先不推荐读的是算法导论和TAOCP。很奇怪我怎么会这么说吧?因为这种书其实是装B党必备。我打赌,推荐读这类书的人,其中99%自己本身就没有认真读过这些书,完整地读更是谈不上。他们推荐这些书完全是冲着书的名气的,好似不推荐这种书就不能体现他们的水平。擦亮自己的双眼,别被这群傻X忽悠了,他们根本没有资格推荐什么书的。读什么呢?严蔚敏那本就够用了,认真读,仔细读。如果觉得自己算法数据结构什么的都会了,那就这一类的书都别读了,与其浪费时间读原理,不如读开源代码实践。
然后不推荐的是21天学会XXX,以及讲c++语言的各种书籍。21天能精通什么那完全是扯蛋的。不要在讲语言类的书上浪费太多时间,语言不是读书掌握的,而是在实践中学会的。尤其是c++那种语法变态的语言。看那些语法的角角落落的东西不如去看开源代码,看哪些东西是常用的。书上一些冷门的语法,除了装B真没太大作用。所以effective c++和more effective c++包括effective stl这一系列都最好不要读。更好的策略是压根别学C++,离它越远越好(可能参杂了太多个人观点,有点偏激)。如果真的想了解一下各种编程语言,读读coders at work吧。读C++是洗脑,现在洗脑的书太多了,读这种书可以解毒。设计模式的书也不要读了,你可以看看coders at work书中的作者有几个是支持c++和设计模式的? 首先说明,设计模式这种东西都是前人摸索中留下的宝贵的经验或者说编程习惯,是好东西。但这里说两点我反对设计模式理由:第一,这种经验其实没法走捷径,通过书本不可能真正掌握,必须在实践中练习。第二,一门语言变态到需要引入各种模式来达成编程上的共识,这门语言本身就是有问题的(太复杂了)。设计模型为了填坑(编程语言的坑,是的,我说的就是C++,c++支持各种编程习惯,C方式的,面向对象的,这已经不能算一门语言了)而被发明出来,为什么要学习这些畸形的东西呢?
我不会推荐一大堆书,装做自己很牛B似的。这里只推荐很少几本。
unix环境高级编程,简称APUE。所有关于linux系统编程的书都没有这本书写得好,讲得透彻。我桌上常备参考手册,除了这本书就是一本C语言了。
unix程序设计艺术,本书作者也是大教堂与市集作者,著名黑客。谈到黑客这个词我很一反应能想到的人就是他,RMS和Linus几个家伙,当然K&R也算上。这不是一本关于技术的书,而是关于unix的哲学。很适合当小说读,反正读起来不累。要学习linux就应该彻底用unix的视角来审视问题,带着windws的枷锁来学linux,整天觉得linux这里不对那里不对的人,永远也学不会linux。因为他们已经被windows中毒太深,没得救了。
黑客与画家,这本书也不是关于技术的,当小说读。之所以推荐它是因为这个作者的煽动性太强了,思想很偏激,但观点很奇,很对我味口。如果一本书有人说它好,有人骂它偏激,那说明其中确实有些独到见解,这本书就是。读这本书还可以顺便学习一下如何忽悠,看作者是如何吹捧一个东西的。
unix网络编程(可选),讲网络编程和进程通信的,是APUE的补充。唉,stevens大牛啊,留下几本巨著APUE,UNP,TCP/IP,本本都是精典,可惜死得得早了。
SICP(可选),不能够颠覆一个人思维方式的语言,是不值得学习的。很多人学C,C++,学Java,然后得出结论:所以语言都是一样的。我只能说这些人都嫩得狠呢,才看了各种编程语言范式的冰水一角就下结论,以为自己什么都懂了,看透了编程语言的本质。其实就一小屁孩,啥都不懂。这本书是关于抽象思维的,编程的本质就是对事物进行抽象,函数式的思维是否比面向对象是更高层次的抽象?到书中去找答案。这本书会带给只学过C/c++语言的人一个全新的视角,颠覆之前的思维方式。
人月神话(可选),读了可以跟大家一起装B,否则跟别人聊天时如果连“没有银弹”都没听过会被看不起的。刚开始编程的人读可能没感觉,等后面真正工作,遇到项目上的一个一个坑就能体会了。
唉呀,不能再推荐了...再写下去就要写一大堆了。 我说过只推荐很少几本,就此打住。其实以上推荐的书中,有部分我也只挑着看了几个章节。这几本都是很通用型,不是具体某方面的技术,所以无论做什么具体方向的人都推荐一看。
维护一个技术博客
技术博客可以一路记录下自己的学习过程,并且也可以作为一个知识备份。有些时候忘记某个以前看过的知识点,如果写博客记过,很容易翻出来。找工作做简历时也可以把博客地址放上去。技术博客也可以当一份简历的,好处多多啊。
写一些代码开源放到网上
前面提到过了,这里重复一下。显示这一条是很重要的。敢于把自己代码贴出来给任何人审查的才是有点干货的。
利用好20%的时间发现兴趣和做感兴趣的事情
如果把工作时间和自由支配时间划为80%和20%。利用20%的时间去发现自己的兴趣点,或者把20%的时间留给自己做感兴趣的事情。
以前我用vi,但vi的调试支持非常不好。所以我需要找个称手的兵器。在20%的时间里,我去研究了emacs。
接着我又发现emacs中的lisp语言是种很神奇的东西(这里,这里,还有这里),于是我又去研究了一门语言。
它为我打开了更大的一扇窗,让我对编程语言,编程本质以及各种编程范式有了更深刻的理解。
lisp中的eval是如神奇以至于我在不知不觉中又被带到了它的编译器层面。学习了编译原理,动态类型语言,类型系统,垃圾回收,虚拟机等等一大串知识。
知识的厚度就在这一天一天的20%中积累了起来。同学眼中我太疯狂了,整天都在学习。其实那20%的时间里,学习过程对于我就是在娱乐。
这一条主要是为找工作写的。很多人直到找工作才知道该学什么,但到这一步时已经晚了。
平日里就应该提前关注这些。了解新技术,但不盲目下结论。了解业界的情况。思考下一些公司的营利模式,哪些将来的发展前景会比较明朗,了解一下公司需要用到哪些技术。这些都对自己以后找工作会有帮助。
关注优秀的技术博客一方面可以充实自己,另一方面可以为自己的技术选型有帮助,决定自己将来工作做什么方向。
了解业界动态可以知道公司需要什么样的人,把自己卖个更好的价格。
如何看论文
进入一个未知的领域,先读比较新的综述性文章,中文即可。读博士论文的综述性部分也行。然后读有影响力的英文原文。读一些综述性的文章后,很容易了解到哪些文章常被提起,这些一般就是重要的英文原文了。一定要读原文,而且要读英文的。这些有影响的英文文章一般是真正有东西的。思考他们的相比前人改进了什么,创新在哪里,能带给自己什么启发。不必要多,但一定要挑好的英文原文读,这样自己水平才能提高。刚读研的时候可能读英文很吃力,但英文阅读能力是一定要练出来的。读第一篇的时候可以多花点时间,一个星期读完第一篇都行。慢慢地,当读英文成一种习惯之后,语言就不是障碍了,也许仅仅就是阅读速度比读中文慢一点而已。读完文章以后,如果觉得没有完全弄懂,可以去网上搜一下其它人对这篇文章的理解,特别是一些很经典的文章网上都能找到大量资料的。
懂得独立思考的人,往往都是很有思想的人。而不进行独立思想的人,就是等着被有思想的那群人忽悠的。就比如说吧,有些同学老是叫嚷着云计算是忽悠。但叫他具体讲他的观点,他又说不出个所以然来。原因很简单,他从来没有自己用脑袋去思考,或者主观论断,或者是被忽悠着接受别人观点了。