十八年开发经验分享:学习篇
作为本系列的第一篇,想谈谈程序员的学习问题。之所以第一个要谈的问题就是学习,是因为我觉得这个问题最重要,也是最让相当一部分程序员比较犯愁发憷的问题。本文如果能给这部分程序员带来一点帮助或者启发,那么目的就达到了。学习问题在那篇小结中写了一小段,这次可以相对较为详细的谈谈这个问题了。
既然要谈学习,那么首先需要明确一个问题,我们打算学什么?这里先对这个纷繁世界中的知识做一个分类:
A.教材上的知识
这部分内容来自计算机专业的课程教材。也有可能会涉及一部分来自其他相关专业或者相关课程的内容。
B.编程语言
每一个程序员只有在会使用一门语言的情况下才有可能从事开发工作,所以学习并掌握一门语言是最低要求了。
C.SDK
光有一门语言是不够的,从事任何实际的软件开发都需要一个类库或者开发包才可以完成。比如C语言中的库函数,C#中的.NetFramework类库,Windows的API等等就属于这个范畴。
D.开发工具
以如今的情况来说,没有开发工具理论上也是可以开发软件的,但效率就是一个问题,所以掌握并使用一个开发工具完成开发任务应该也是一个最低要求。
E.领域知识
软件总有用户,于是开发这些用户使用的软件,那么程序员就需要了解用户所在行业的知识,至少需要知道一些基本的必须的知识。还有一部分的内容也划分为领域知识,比如从事Photoshop这类软件的开发那么图形相关的知识就必须了解一些,从事工控软件的开发,那么对控制方面的知识也要有所了解。
以上的分类是在本文中我对知识的理解,一个程序员知道这些知识后从事一个软件的开发应该是没有问题了。下面分别来讨论一下这些知识的学习问题。
一.教材知识的学习
做为一个已经从业的程序员来说,我不认为计算机专业的所有专业课程(包括专业基础课,我在读大学的时候还有这个说法)都是有用的。实际上对于大部分程序员来说,只需要很少的一部分知识就足够了。这些知识主要由三门课程组成:数据结构,编译原理,操作系统。对于大部分的程序员来说,其他课程的内容不是没用,而是在实际工作中用不上。
数据结构这门课程的重要性,可以理解为是程序员的圣经,怎么如何形容其重要性都是不过过分的。这门课程中需要掌握的内容,我个人观点如下:
1. 掌握所有线性数据结构的知识,比如表,栈,队列等(广义表可以不作要求)
2. 二叉树的基本操作和基本使用
3. 图中需要知道遍历和了解最短路径算法,以及相关的一些概念
当然对于某些程序员来说,这是不够的,因为从事的具体的软件开发工作会有不同的要求。但是对于大部分从事MIS软件开发的程序员来说,这些知识够了。掌握这些知识可以有两个层面的要求。第一个是完成足够的习题,从而可以熟练的答题,第二个是能够在实际工作中使用数据结构描述实际的事物。做到这两点要求应该说不算太高,注意多加练习就可以了。目前来说这门课程的经典教材也不少,相信只要按部就班的学习完就是合格的了。
编译原理这门课程主要是学习方法和思想而不是课程中的知识本身。因为毕业出来能从事编译器开发的人实在是太少太少了。这门课程需要掌握了解的东西不多,我个人的观点主要是以下几个:
1. 确定有限自动机和非确定有限自动机的使用
2. 词法分析程序的实现
3. 语法分析的方法
自动机在实际应用中的体现就相当于是状态转换图,这个工具非常的重要,希望能够务必掌握。我们在开发EntityModelStudio时,设计界面交互部分的内容就是先设计出状态转换图然后再写代码的,否则直接开发的话就会面临开发失去控制的风险,同时重构和维护也会相当麻烦。所以这个工具极其强大,非常实用。另外提一下,非确定有限自动机,这个工具的能力和确定的有限自动机是等价的。但是由于它的不确定性,更符合人的自然思维习惯,从而在某些设计场合相对会方便很多。这一点是很实用的,也是很吸引人的。
掌握词法分析程序的实现,可以大幅度拓展开发能力和思考能力。这部分东西理论上描述可能比较麻烦,但是实际使用时还是很容易上手的,所以非常值得学习一下。语法分析程序不需要掌握了,毕竟开发编译器的机会是微乎其微的。但是相关的方法和思想希望能够了解,这可以帮助程序员用电脑的思维来思考问题。
操作系统需要掌握的东西只有两个:
1. 五大管理的基本方法,尤其是涉及内存管理的策略
2. 线程或者进程的同步技术
操作系统是复杂的,但是教材中介绍的这些管理方法相对来说是简单易懂很多了。这一难一简之间体现了基本知识的重要性,基本知识在实际开发中的应用的广泛性。好好的体会,就可以明白用简单方法解决复杂问题的技巧。线程进程的同步,这个就不用多说了,大家都知道它的作用,如果实在不想掌握的话那我也非常愿意相信你的理由一定是充分的,否则你绝对不会那么做。
最后我想强调的是,无论你如何看待这些知识:可能觉的没用,可能觉的太难,可能是不感兴趣,但是如果你想做程序员的话,那么请你务必最大可能牢固,最大可能熟练的掌握它。
二.编程语言
对于一个程序员来说,一般需要掌握2,3门语言是基本的,并且学习一门新的编程语言也是基本功级别的能力,所以这部分主要谈谈快速学习一门新的编程语言的方法。我学过的语言有这些(这里编译器和语言的概念等同了并且不按先后次序):Foxbase,C,C++,汇编,Visual C++,Delphi,FoxPro,VB,C#。就我个人的体会来说,这些语言可以分为三种类别:非面向对象的,面向对象以及支持可视化设计的。
这三种类别的语言有一些共同的内容,而这些内容也是我们在学习一门新的编程语言时首先需要知道的,可以说是关键的知识点。这些内容大致如下:
1.常量,变量,数组,不同的数据类型
这部分需要掌握常量,变量,数组的定义,初始化,不同数据类型的使用。数组中元素的读写,作为参数如何定义,作为返回值如何定义。有些语言还支持数组大小的重新定义。
2.函数(或者叫子程序)
函数如何定义(比如参数和返回值),如何调用(这里存在异步调用和同步调用的问题),全局的还是非全局的。
3.流程控制
分支结构:if语句,if else语句,switch语句;循环结构:for语句,while语句,do…while语句,有些语言可能是Loop。
4.最基本的输入输出和文件操作
最基本的输入输出语句可以帮助你在学习语言的过程中完成简单程序的练习任务,比如:输出到控制台,dos操作系统中输出到屏幕等等。文件操作也要知道,至少以后写个程序生成日志文件就会了。
以上内容在学习一门新的编程语言时,希望能首先掌握,这能让你很快的入门,并尽快使用新语言写出代码。另外还可以关注一下其他方面的内容,比如:
1.了解语言的新特性
这个阶段只需要了解,不需要掌握,记住有这些新特性,在需要用的时候想起它们就可以了。
2.了解一下帮助文档中,该语言的所有关键字
这部分内容有可能让你发现一些很有用的东西。
好了,知道这些内容差不多一门新的语言就算入门了。当然还有其他很多东西,但是这些内容可以在具体开发中遇到时再去找例子就可以了。下面谈谈这些语言的差异。对于面向对象的语言来说,需要知道面向对象三大特征:封装,继承,多态在具体的一门编程语言中是如何表达的或者等价表达的。对于支持可视化设计的语言来说,还需要知道如何设计窗体,以及常用控件的使用。按照这个方法,从一门已经会的编程语言到学习另一门新的编程语言应该是比较快的。对于还在大学中学习的人来说,我的建议是C++或者Pascal中的一个,VB或者C#中的一个或者其它可视化开发语言中的一个学习一下。如果可能学习一下汇编是最好的。
三.SDK
掌握一个SDK才能使程序员在掌握一门语言的基础上进行实际的开发,如果仅仅是一门语言那是不够的。所谓SDK举例子来说就是Foxbase的命令和函数,C的库函数,C++的类库(比如微软的MFC),Windows的API,.NetFramework,这些都是我所说的SDK。程序员可以根据自己的实际开发需要,有选择的学习相关的内容。我的建议是,可以先google,然后查文档,一般的问题都可以很快解决的,慢慢的也就逐步掌握了。比如说我不知道C#如何使用线程,那么我就用google查找,关键词是“C# 线程”,然后从结果中找到需要的内容。很多时候结果中的代码是可以直接使用的。然后再去看一下MSDN的帮助文档,了解一下相关的类和方法的说明,这样这部分的知识就可以认为是掌握了。下次使用时就知道怎么用了。我的C#就是这么入门的,大概google问了二三十个问题左右。
另外一个建议是买一本书学习也是可以考虑的,这也是一个不错的方法,只是买到好的书需要缘分。就我个人来说,绝大部分的情况下是看电子书,直接从网上下载的。
四.开发工具
除非你只用独立的文本编辑器写代码,并且用命令行编译,否则你一定需要一个开发工具,尤其是一个带IDE的开发工具。对于你使用的开发工具而言,需要了解的基本内容如下:
1. 项目或者工程的创建,属性修改,打开关闭等基本操作
2. 具体开发时的环境设置
3. 项目中的文件组织及管理
4. 常用功能的使用,比如:编译,执行,断点设置,代码跟踪,调试信息输出,实用的快捷键,调试时变量查看,查找/替换等等
5. 从帮助文档中了解IDE的新功能。因为这些功能有可能对你是非常有帮助的。
6. 帮助文档的获取
如果有自己的使用习惯的话,还可以了解一下如何定制IDE环境以满足自己的开发习惯。首先了解这些内容可以帮助你相对快一点适应一个新的IDE。
五.领域知识
一个从事技术工作的程序员需要了解与技术不相干的领域知识,确实有点无奈。但是在具体的开发中,不了解这些知识就无法更好的理解用户的需求,也无法更好的完成开发任务以及与同事领导的沟通。所以这个步骤是重要的必要的,有时候有可能还会带来更严重的后果。在有些项目中如果不能很好的了解这些领域知识,项目中的成员有可能会被替换掉,我个人就有过这样的经历。所以这里特别列出来强调一下。
差不多这些知识应该够用了,下面再提几个额外的内容,这几点虽然和开发不是太直接相关,但是确实也很重要。它们是英语,数学,读源代码和读书,有余力的程序员可以尽量提高这几方面的水平,这是很有用的学习途径和方法。对于英语而言主要是读和写,这样就可以阅读英文资料并用邮件,论坛或者聊天工具和老外沟通。由此获得的帮助是非常显著而高效的。这里要说明一下,微软论坛上的回复的质量非常之高。
对于数学我的理解主要是三个部分,都是很具体的:
1.中学里学过的知识
这部分知识很重要,这是我们用简单方法解决复杂问题的基础,同时使用的几率也非常高。如果全部忘记的话,建议多少复习一下,或者用到的时候回顾一下。
2.离散数学
我需要承认在开发中直接使用离散数学知识的场合我一次都没有遇到,但是如果没有离散数学的知识,那么我就无法思考,很多问题就无法解决。
3.组合数学
这门课程属于研究生级别了,相对难度会大一些。我的观点是你不需要全部掌握,知道一部分就可以了,比如:鸽巢原理,母函数,以及常用的计数方法和技巧。尤其是技术方法这部分在问题的分析简化,工作量的评估,算法设计以及软件测试方面都有非常实用和具体的应用价值,是很值得掌握的。是否可以使用这部分知识,在实际工作中表现出来的效果至少相差一个等级。
一个好的源代码具有不可估量的价值,潜心学习一下可以让你从一个门外汉变成一个开发老手,所以注重培养从读源代码学习编程知识的能力。我的体会是,阅读源代是一个非常有效(有用并且高效率)的方法来提高自己的开发水平或者解决实际问题的能力。我第一次认真学习的源代码来自当初的程序员大本营。一个例子是实现Visual Studio 6.0中Workspace的界面,另一个是如何实现给主菜单加入图标。两个例子大概花了我一个半月的时间并且写了几篇心得,记录下学习的内容。应该说收获很大。再比如,下一个版本的EntityModelStudio中会加入代码编辑器,这个支持语法高亮和行号的编辑器就是在读懂开源代码后我们自己独立重新开发的。在阅读源代码的时候希望能注意两点:
1. 最好能配置好环境可以单步跟踪代码,这样理解代码的速度和效果会好很多。
2. 快速的定位那些自己想看的代码。这里建议可以使用IDE提供的查找功能,看文件名,类名等方式来定位。如果实在不行,考虑注释代码,来快速定位。
第四个内容是读书,阅读是学习的一个最基本和最重要的途径。在这里我不想列出任何需要阅读的书目,这是因为当下流行的所谓经典或者著名的开发书籍我读得很少,所以也说不出体会。我看过的书都比较老了,比如:
1. BorlandC++4.5使用及开发指南
这是我的C++的教材,C++部分先后看了不下6次
2. 一本1970年发行的软件工程的书,这是我第一次接触软件工程
3. 代码大全第一版,我觉得第二版没有第一版好
4. 用于面向对象的设计和分析方法,这是美国哥伦比亚大学的一个教授写的。是清华大学原版教材中的一本,非常好,是OOD的绝好教材。
目前有印象的就这些,以后想到了再补充吧。其他读过的书还有很多,都是具体的编码的书就不再一一列举了。有些书需要仔细阅读的,比如讲设计,讲方法的书,有些书需要很快的浏览完,比如讲具体编程的书。我的体会是,一本几百页的书,你应该花1,2小时就能过一遍,最好是20分钟到40分钟就能过完。在实际开发中,用到的时候再看书,查找需要的内容。如果你需要花很长一段时间全部学完一本书的话,那么你看的第一本书可以这样,否则我觉得你的学习方法就有问题了。至少一本书中不可能所有的东西都是你马上要用到的,你没有必要立刻学习,所以应该学会快速阅读的技巧。当然这是个人观点,取舍对错自行判断吧。
你不能寄希望于一次就能买到一本理想的书,也不能希望在一本书中学到自己需要的所有内容。遇到一本好书是需要点运气和缘分的。我的总体感觉是,外国知名出版社的图书的质量明显好一些,还有台湾一些出版社的图书也还不错。建议大家可以买一些绝对知名和权威的书籍,这样相对风险会小一些。对于那些书名为XXX大全,XXX宝典,精通XXX,XXX权威这样的书,我是很不看好的,当然这是自己的看法,仅供参考。
最后说一下不要学习的东西,这是在本文发布前刚发现的问题。几天前在群里聊天,一个人说想解析暗黑的通信协议,然后做外挂。我对这方面很不在行,但是这明显是一个非常耗费时间,难度也非常大的事情。我在这里给出的建议是,一个职业的程序员需要知道自己的价值,自己的知识和精力应该花在能够创造实际价值的地方。不要仅仅出于爱好或者热情去做一些成本很大的事情,与其炫耀自己的能力,不如踏实的做好本职工作。如果实在想做可以作为业余爱好,适可而止。