最近网上一直比较热闹,“淋巴哥”老师拿出高丽棒子那种可以证明屈原、李时珍就是韩国人及端午节源自韩国的那种娱乐考究精神考究出了所有说他的书不好的人都是书托和骗子来,一时间圈内大哗;接着在博客园又掀起一股 Java 与 C# 的瑜亮之争,不可谓不热闹。不过作为普通的开发人员,这些事情都是相对较为遥远的事情,普通开发人员比较感兴趣的是如何提高自己的技术,增加自己的能力,以便在今后的工作中找到一个更好的职位,这两天周公也收到了一封一个工作了 2 年的 .NET 开发人员的邮件,在邮件中他谈到了自己的困惑不足,周公觉得他的现状有一定的普遍性,因此想在这里谈谈自己的经验和体会,原文如下(为了保护当事人隐私,去掉了一些个人信息):
周公:
我叫×××,是××××人。做.net的web开发已经2年多了。
前天去"飞信(新媒传信)"笔试+技术面试,很侥幸被我通过了,但今天上午去参加总监的复试,我被出局了。
今天灰不溜溜(周公注:似乎没有这个词,可能用“灰头土脸”比较恰当)的从大门走出来,真的感受到了从来没有的挫败感。
说下我学习.net的经过。我是07年10月份接触C#的,自己买了本C#基础教程自己看的。然后又买了本asp.net基础教程。就这样走上了.net之路。
为了能在08年毕业前找到一份理想的工作,我在08年2月份又去图书馆买了本apress小组出的关于.net2.0电子商务的书,这本书让我了解了3层架构。当然也凭借这本书我在4月份找到了工作。之后就在工作中学习成长,也感觉自己各方面能力还是蛮不错的。
到了今年3月份后,我发现自己一直受困在目前的水平中,想要自我提高,很难很难。我知道要学的东西有一大堆,但我不知道该从何学起。自己每天看看着(周公注:应为“看看这”),看看那,如果没有项目、没有环境。那就很不系统。我觉得如果想得到更好的提高,只有换个更好的环境,如果能跟着一些强者一起做项目,那么就肯定能得到突破,学到很多东西。
然后我就开始"骑驴找马",想找给(周公注:应为“想找个”)好的团队,学到些真东西。
我不得不承认飞信的团队确实很好,初试我的2个技术人员都30岁左右,技术也都很强。但就项目中的功能或一般的基本原理,由于我有充足的准备,还算是过关了。
不过今天上午,总监对我的面试,让我感觉自己了解的实在是太少了。很多东西只知其一,不知其二。更多的东西只是知道(周公注:似乎应为“只是知道怎么用”),但并不知道原理,或者使用过。
就拿对方问个:C#各个版本间的差别是什么?.net各个版本间的差别?prototype和jQuery间的差别?
我就头疼了,说实话,一直用C#2.0,并没有很好的去了解各版本间的差别。包括jq和prototype的差别也没好好的了解过。
对方对asp.netmvc的要求也比较高,mvc我的了解也比较少。
特别是这位总监提到,他们对程序的性能有很高的要求。这也是我特别想去了解的,如何去提高程序的性能。
包括对方让我很好的描述http传输的原理、为什么序列化能提高程序性能...等
我发现自己真的只停留在概念的表面!
完全杯具了!
不过我还是表现出了自己相应交流能力和学习能力。这位总监也很欣赏我挫败面前不低头的性格。他觉得我现在虽然实力不够,但愿意给我一次机会,让我好好的学习一下,觉得可以了在直接来找他,并把email留给了我。
我也很感激他愿意给我这么给机会,但我觉得自己更要好好的去丰富自己。正如您常提到的一个好的程序员一定要有深度+广度。
我是86年出生的,也是个不小的人了,我知道现在厚着脸皮向您讨教学习方法是很不应该的。
但我现在一时间确实不知道该如何提高,我想您能不能从几个方面给我推荐几本书或者视频之类的。
比如要学好asp.netmvc框架,我从什么书入门,然后看什么能提高。
包括如何深入了解http协议,.net序列化,如何提高程序的性能。
包括如何更深的去学习C#
我觉得我有一定的基础,我肯定能把这些学好,我一定行的。
我会在一年后再去找他,我不愿意认输。
很感谢周公能看完我这么多废话,希望能得到您的建议。以您这个过来人的经验,来建议我现在如何去一步一步的完善自己。
×××
我的答复如下:
×××:
你好!
非常感谢你对我的信任,愿意把你在成长过程中的烦恼将给我听。我也很愿意分享一下我的观点和看法,只是在年龄上我比你多虚度了几年光阴,在开发上我比你多做了几个不成功的项目及在面试上我比你多一些面试次数以及还有你所没有的面试别人的经历而已,所以我的经验和观点未必完全正确,仅供你参考。
首先说一点我对你这封邮件的看法,在这封邮件里有几个错别字,还有一些地方词不达意,还有一些地方排版不是太好(周公注:上面的邮件已经经过周公排版),尽管这不影响我阅读你的邮件,但是这会让我对你有一些小小的看法,比如你不够细心——尽管我可以猜想为你在上班之时给我书写邮件,慌乱之中会出现这种现象,但是这不能成为你没有做好的理由。特别如果是在你的简历中出现这样的问题,可能第一眼就会被pass 掉。也许你会不以为然,会说这样或者那样的理由,但是这些理由在某种程度可能会看做借口或者做其它的联想,比如你说因为时间紧慌张所以出现了错别字,那么我会想如果把你招进来之后遇上项目紧的时候你是不是同样也会慌张因而出错呢?
ASP.NET初级程序员的现状
接着我谈谈目前ASP.NET 开发的现状,目前很多培训机构及一些出版社给初学者灌输的都是如何方便地使用 ASP.NET 服务器控件——显示数据记录使用数据绑定控件,对数据库操作使用数据源控件,这样就给一些初学者造成了一种假相——学好了 ASP.NET 服务器控件就等于学好了 ASP.NET ,甚至就等于学好了 .NET ;如果能熟练掌握这些控件的用法,能在数据绑定控件里面嵌套服务器控件那就等于精通了。所以经常在 .NET 里看到一些“ .NET 高手”在网上哀叹:“精通 .NET 开发居然找工作那么难,好不容易找到了个工作比民工薪水还低!”其实完全不是这样的,真正的 .NET 高手还是奇缺的,如果你知道你身边有这样的人请告诉我,我的很多猎头朋友让我向他们推荐呢。当然这种现象不是最近才出现的,至少在 2007 年我负责招聘的时候就注意到这个问题了,我当时就写了一篇博客《一才难求——也谈程序员素质问题》里记录了这个问题:
情况之一:不会利用msdn。众所周知.net类库包含有几千个类,不可能去记住每一个类有哪些方法和属性,特别是在初次使用一些以前没有使用过的类时,查看MSDN帮助应该是第一选择。在面试中发现很多人根本没有这一概念,有些根本不知道怎么用(在面试做题的时候,我一般都事先声明允许查MSDN)。
情况之二:不懂一些基本而且必须知道的知识。最离谱的一次,居然遇见一个不会将FLASH嵌入到aspx页面中的程序员(有HTML的可供参考)。有几次还遇见过需要Response输出一些HTML代码的情况,有的程序员居然不知道怎么写。
情况之三:基本概念不熟,比如一些程序员无法区分抽象类、接口之间的区别和关系。
情况之四:自视过高。有一个工作一年的程序在简历上写着“精通数据库设计、设计模式、系统分析和开发工具,对架构设计也有深入的研究”,看了这种话我开始是大吃一惊,后来跟他谈他“精通”的有关领域的话题,他基本没插几句话。
最后,想给正在求职和即将要求职的各位程序员一点建议:抛却急功近利的想法,不管什么行业都注重经验的积累和沉淀,平时学习和工作的时候一定要多动手动脑,通过自己的思考和实践才能加深和巩固印象。不要抱怨自己的工资不高,先问问自己的水平高不高,如果你的水平高的话,公司不敢不给你高工资,因为他不给别人会给的,在这个浮躁的年代,招聘一个好程序员是非常不容易的。
.NET的历史渊源
做.NET 开发有几年时间了,我经历过从 .NET1.0 一直到 .NET4.0 的过程,所以对于它们的历史我可以简单说说。最早支持 .NET 开发的是 VS2002 ,所支持的版本是 .NET1.0 ,第二年就推出了 VS2003 ,所支持的是 .NET1.1 ,主要是修复了 .NET1.0 的一些重大 Bug ,此时 .NET 是向下兼容的,开发的 ASP.NET 的版本分别是 ASP.NET1.0 及 ASP.NET1.1 ;之后推出了 VS2005 ,它支持此的 .NET 版本是 .NET2.0 ,这个版本与以前版本相比主要是增加了对泛型、局部类和可空类型的支持等,注意 .NET2.0 对低版本不是完全兼容的;紧接其后推出的 VS2008 支持的 .NET 版本有 .NET2.0 、 .NET3.0 及 .NET3.5 ,与 .NET2.0 相比, NET3.0 及 .NET3.5 增加了 WindowsCommunicationFoundation ( WCF) 、 WindowsWorkflowFoundation( 早先曾叫过 WWF ,不过现在改叫 WF 了)和 WindowsPresentationFoundation ( WPF )组件,在语法功能上增加了 LINQ 和 Lambda 表达式等,使得编程大大地方便和提高了,基于 .NET2.0 、 .NET3.0 及 .NET3.5 开发的 ASP.NET 应用程序所使用的 ASP.NET 版本都是 ASP.NET2.0 ,在这个时候可以通过安装 VS2008SP1 的方式以内置支持 jQuery 和 MVC ,这个时候使用 .NET3.0 及 .NET3.5 是兼容 .NET2.0 的; 2010 年微软又推出了 VS2010 ,它支持开发基于 .NET2.0 、 .NET3.0 、 .NET3.5 及 NET4.0 ,不过 .NET4.0 不兼容它的低级版本,开发的 ASP.NET 应用的版本也是 ASP.NET4.0 ,在 .NET 中增加了很多新的特性,比如增加了 ADO.NETEntityFramework ,此时集成 jQuery 和 ASP.NETMVC2 。
关于经验
关于经验的积累跟项目有一定的关系,但并不是全部。对于ASP.NET 开发大部分可能会有这么一个过程:
首先是觉得服务器控件挺好用的,在开发中大量使用服务器控件;
经过一段时间的开发之后(也可能是听别人说),会发现服务器控件并不是想象中完美无缺,在VS2010 之前很多 ASP.NET 控件默认会启用 ViewState 来保存控件状态,这样在最终生成的 HTML 页面的源代码中生成了大段的隐藏域字段,影响了网页的传输速度,慢慢地我们会发现其实 ASP.NET 服务器控件最终到客户端时会被转换 HTML 代码,那么使用 HTML 服务器控件也是可以的,并且还省去了转换这个过程,所以在开发时尽量不处处使用服务器控件;
再经过一段时间之后,我们会发现有些复杂的效果与其去层层嵌套服务器控件,还不如直接将这部分特殊效果的HTML 代码输出,这样更方便快捷,然后我们也会想到有些操作其实用 JavaScript 也可以在客户端实现而不是必须要提交到服务器端才能处理,这样又提高了效率;
再过一阵子之后,我们会觉得SELECT*FROMTable 尽管什么时候都不会出错,但是并不是最高效的,在某些时候我们只 SELECT 要显示的字段,除此之外当数据库中的记录一多时每次都将数据库中的记录全部查出来再取出需要显示的部分不显示的数据被弃之不用很浪费资源,所以会想到使用分页查询每次只查询当前页所需要的数据;
再过一阵子之后我们又会觉得原来那种对数据库执行增删改查的操作的代码每页都有,非常不好维护,第一步分析之后会想到使用数据库通用类,再仔细分析之后可能就会发现三层架构的好处进而接受了三层架构这种思想;
再继续思考总结,我们又会发现其实在SQL 方面有很多名堂,比如存储过程、触发器、函数、分组函数、联合查询、 UNION 等,也就是有些结果可以直接在数据库里进行处理而不是将多次结果分别取出来在 C# 中处理,尽管可以实现同样的功能,但是在数据库中处理可能更加方便和直接。
当然这些都还是初级程序员所面临到的一些问题,如果真想提高自己,可能会注意到更多问题。比如到了一定程度之后我们会接触到不同的数据库,我们要对比分析一下这些数据库之间的异同点;我们还会注意到实现同一种效果会有不同的做法,我们要注意不同的做法之间差别——哪种做法效率高?哪种做法占用内存小?哪种做法安全性高等等。比如做ASP.NET 开发,可以使用服务器控件、可以使用 HTML 客户端控件、可以采用 Response.Write() 的方法直接输出及模板替换法,你觉得它们之间有什么区别?同样存储数据, Cookie 、 Session 、 Application 及 Cache 都可以保存,它们之间又有什么差别(提示:可以从保存数据类型、范围、保存周期、安全性等方面考虑)?再比如非 ASP.NET 应用和 ASP.NETMVC 应用之间应用有什么区别?再比如 Convert.ToInt32() 、 int.Parse() 及 Int32.TryParse() 都是可以实现将字符串转换成 int 类型数值,它们之间在用法上有什么区别?有没有想过它们内部的实现呢?如果让你写一个类似于 Int32.TryParse() 的方法,你想过会怎么写吗? XMLWebService 和 WCF 及 .NetRemoting 之间有可比性吗?在使用它们时该考虑哪些因素?参数化 SQL 语句和非参数化 SQL 有什么区别?在存储过程中执行的一定就是参数化 SQL 语句吗? string 和 String 之间是什么关系?什么叫字符串驻留池?什么叫数据库连接池,数据库连接池有什么用途?和诸如此类的问题有很多,实在是举不胜举了。
以上的问题有多少使你感到难以回答?如果你能比较自信地回答上面的大部分问题,恭喜你已经具有中级程序员的开发经验了。我不知道辞海里有没有对“工作经验”这个词下定义,根据我的理解我觉得程序员的工作经验包含了两个方面的经验:社会方面的经验和技术方面的经验。社会方面的经验包括了比如生活与工作产生了冲突该怎么处理及与领导在某些问题上意见不一致该怎么处理等,这个如果不是应聘技术管理方面的岗位面试单位关注得比较少。技术方面的经验招聘单位会更看重一些,通常所说的程序员的工作经验也主要是指技术经验。它至少包含了以下几个方面:
对于一些常见的编译错误和异常描述我们能迅速知道问题出在那里并及时解决;
对于一些可能会有多种方法实现的功能,我们应该如何根据当前项目的实际情况选择比较合适的方法;
对于一些容易影响性能的地方我们应该知道一些如何提高,如果存在多种解决办法,如何去评估那种办法的效率高;
对于一些容易发生安全性问题的地方我们应该知道如何去防范;
对于具体的应用如何去设计数据库或者去评估已经存在的数据库的设计好坏,如何在第三范式和字段冗余之间取舍;
如何在时间复杂度和空间复杂度之间取舍,知道如何用空间换时间(比如使用缓存就占用了内存但是换来了效率的提高,但是缓存并不是使用越多越好,此外对于数据库中索引字段也存在这样的问题);
对于常见的问题我们应该知道如何去处理;
对于从来没有遇见过的问题我们又该如何借鉴已有的经验来处理而不是束手无策。
要解答以上问题,可能要求我们的知识面要相对广,在某些问题上要有一定的深度。实际上上面的这些问题已经脱离了语言本身了。在武侠小说中经常听到高手会说所有的武功最终都是百川归海,在编程开发中我们经常会听到编程高手会说“语言只是一种实现手段,重要的是思想”,那么思想到底是什么呢?为什么有人要求在项目中某个类只允许一个实例存在你就会想到单例模式?这就是经验,但是经验是什么呢?真的不好定义,尽管在上面我列出了经验的一些体现,但是那并不是全部,我只能说“经验是一种很玄很玄的东西”。
如何积累经验
不要晕,也不要倒,其实我们有很多办法增加自己的经验。围绕磨盘转了一辈子的骡子并不是一头有经验的骡子,将木棍捅到蚁窝中来捕食蚂蚁的熊也没有太多经验,因为它们做那些事情不是出于被指使就是出于一种本能,很少去想是不是可以做得更好,而我们的祖先就做到了,所以今天我们成了世界的主宰。
说到这里,也就说出了我的第一个答案: 技术的深度来自于总结 。不管是学习还是做项目,不管是自己编写的代码还是别人的代码,我们都尽量学会分析总结,首先分析一下那些地方做得好,那些地方做得不好,做得好是因为什么方面的原因?安全、高效亦或者是其它?这种好的做法今后可以用在某些场景下?有没有可能存在比这些你认为做得好的方法还要好的方法?对于那些做得不好地方,又该如何去改进?特别是以前自己所做的项目一定不要做完了就算完了,有时间一定要拿出来经常看,看看最近所学的知识有没有可以用于改进这些项目的。
也许有些朋友特别是初学编程的朋友会说自己以前根本就没有做过真实的项目,缺乏实战机会。光凭自己所做的工作上所做的一些项目可能对于个人提高不是很快,会受到公司业务的限制,项目类型不是太多,所需要用到的知识自然也不会是太多;或者在一些大公司里面,由于在这里一个人一个坑,每个人的职责单一,一个项目做上一年你可能仅对自己所负责的模块比较熟悉,对于项目组其他成员的模块不熟悉,时间长了之后就会感觉自己进步很慢,这种感觉我以前也有过。
在当时我做了几件事情,我现在总结起来觉得比较有用:
一是通过论坛、博客了解别人在做项目中使用了哪些技术。多次被提及的多半就是目前大家比较关心的或者流行的,如果自己的项目中没有涉及到这些的话,多了解一下这方面的讨论或者文章看是否满足在自己项目中使用,如果不能的话(比如自己目前是在VS2005 下做开发,而别人经常谈论的是 VS2008 下的开发)那么就尝试在下班后或者工作之余动手实践一下。
二是总结自己以前所做的项目。很多人在做项目时键盘上最光亮的键就是Ctrl 、 C 及 V (因为最经常的操作是 Ctrl+C 和 Ctrl+V ),可能在当时我们这么做有一定的客观原因,比如当时时间紧为了完成任务不得不那么做,这个可以理解,但是不应该在做完之后就将它丢到一边了,等到下次再用的时候依然又是 Ctrl+C 和 Ctrl+V ——这么下去,做多少年都不会提高的(除了提高了使用 Ctrl+C 和 Ctrl+V 的熟练度之外),我就有这么一个习惯,保持着几年前甚至刚参加工作时所做项目及学习用的代码,有时间我还会拿出来看,看看对于以前那个时候做的东西现在可不可以改动得更好,直到经过几次之后确实不能再改了才放弃。
三是总结别人的项目。现在的网络这么发达,可以很方便地从网上找到一些项目的需求文档、设计文档、源代码等,对于一些比较有名的开源项目甚至你还可以找到有高人对这些项目的源代码的分析。接触过的项目多了,你就会发现有很多功能和你以前所做的项目中要实现的功能相似,那么就把你的代码和别人的比较一下吧,有比较就有鉴别,有比较就有高下之分,你就会看到完成同样或类似的功能,别人的做法就比自己好,自己好好想想好在哪里,以后是不是可以借鉴别人的思路。
四是多关注一些基础的东西。武侠小说里正派武功高手在成为高手之前总会被要求长时间练基本功,基本功打好了就很容易打通任督二脉,然后很快就可以练就一身过人本领,这样对自身是没有伤害的,而邪门武功大多不要求武术根基很快也能练成,这样即使练成了绝世武功也会容易对身体造成伤害,还可能走火入魔,著名的《避邪剑谱》及《葵花宝典》都是这方面的例子。很多半路出家的以及一些从培训学校出来的学生大多就是基本功不好,我自己就是半路出家的,在大学里学过一学期的C 语言之后就靠自己自学走上程序员的道路,很长一段时间对数据库的使用仅限于使用 SELECT 、 UPDATE 、 DELETE 、 INSERT 、 ORDERBY 、 COUNT ,在看别人项目源代码时经常看到别人项目中复杂的 SQL 语句,感觉自己有必要加强基础,于是花了很多时间去系统学习了数据库的基础知识。
五是多动手实践。“纸上得来终觉浅,须知此事要躬行”,如果仅仅是看别人的代码,看书可能就在看书的时候有感觉,合上书之后就什么也不记得了。所以还需要大量实践,有一定基础之后系统的实践比单独联系一个知识点要强得多,比如找一个自己觉得不错的BBS 或者 CMS 之类的系统,为防止自己忍不住看它的源代码所以这些项目的语言尽量不要选用 ASP.NET 的,然后要求自己实现一套和它相似度很高系统出来。在这里注意几点,一是在选项目时尽量量力而行,不要一上来就想模仿一个庞大的系统,庞大的系统涉及到知识面很广,知识点要求也比较深,工作量也比较大,一个人可能费时较长还没有看到结果就会产生挫折感,就会放弃,所以可以先模仿小系统然后再模仿大系统;在编程语言方面可以先选择比较容易部署的编程语言开发的,比如 ASP , ASP 的运行环境在 Windows 平台上的 IIS 中部署起来相对较为简单(在 IIS7 之后稍微麻烦一点),等熟练之后可以模仿 JSP 或者 PHP 开发的系统,这些系统的部署相对较为复杂一些,可能数据库会采用 MySQL ,而 Web 服务器可能会是 Tomcat 或者 Apache (它们也可以采用 ISAPI 的方式集成到 IIS 中)。在模仿的过程中会用到 HTML 、 CSS 、 JavaScript 及 SQL 等方面的知识,有的时候还需要了解别人的设计思路,对于自己的提高是想到有效的。除此之外,在提高 ASP.NET 编程能力的同时也顺便了解了其它编程平台和数据库,扩大了视野。
好了,在最后我回答一下你在邮件中提高的几个想法,关于你在邮件中提高没有环境和没有高手带的情况,我想在上面提高的五点中的第五点可以回答你的这个想法,有环境有高手带固然是好,但是没有环境没有高手带我们也是可以通过其它办法来解决的,比如看高手所做的项目并且模仿它,这样也可以达到目的。和高手合作对自身的能力要求很大,大家知道微软、Google 和 IBM 中高手多,在这样的公司里进步会很快,但是没有一定的能力是进不去的,所以在没有机会进去之前我们不妨采取上面的办法——实际上也有很多在民间的高手,他们并不在知名大公司,但是他们一样可以做到很好。
除了上面的做法之外,其实还有一些手头可用的比较方面的资源,比如MSDNWebCast 上面就有微软推出的大量免费视频,我们可以挑选一些下载下来看,在早年的时候我就从上面学到了不少东西,你在邮件中提高的 ASP.NETMVC 在上面就有系列讲座,还有比较热门的 Silverlight 和 Linq 等,只不过不要贪多贪全,千辛万苦全部下载到硬盘里然后一个不看,只看看自己关注的部分,实际上里面的视频大部分是 Level200 的,也就是针对普通开发人员的,比较容易理解。等你有一定能力之后就可以选择不看或者有选择地看了。
除此之外,我不知道你安装VisualStudio 的时候有没有安装随光盘自带的 MSDN ,安装完 VisualStudio 开发工具之后就会提示是否安装它,我建议将开发中会使用到的部分安装了(因为涉及到的知识很多,没有必要全部安装,有些可以不必安装),这样遇到问题之后即使不能上网也能有有地方查资料。在 MSDN 帮助中有 .NETFramework 种每一个类的介绍,包括类的说明、构造函数、方法、字段、属性、显示接口实现、请参见等。对于 VS 开发人员来说它的作用相当于机器猫的口袋,需要的大部分都能从这个里面找到。像你提到的序列化以及一些经常被提到的正则表达式、 WebService 等也可以在 MSDN 中找到,有时间的时候可以看看,在有些地方还有一些提高程序性能或者安全性的建议。
图:在安装完VS2005后提示安装MSDN的界面,在VS2008界面也类似
至于你在邮件中的其它问题,我想我已经在邮件中回答了,在这里我还给你一点额外的建议:建议有时间提高一下英语,如果还有时间的话再学习一下UML 相关的知识,这些东西在短期内似乎对你没有什么帮助,但是对于你的长远发展是大有裨益的。如果你还有不明白的地方,请继续和我保持邮件联系。
周公
2010年 6 月 6 日
后记:看到看此篇文章的读者当中有一些是未毕业的大学生,我建议你们看看我的一篇针对未毕业大学生的文章《与一个即将毕业的计算机系大四学生关于求职的对话》。