程序员成长的烦恼(txt+pdf+epub+mobi电子书下载)

作者:吴亮等

出版社:华中科技大学出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

程序员成长的烦恼

程序员成长的烦恼试读:

前言

这是一本关于程序员奋斗成才的书。四位作者来自不同的技术领域,他们以各自不同的经历,演绎了各自平凡而精彩的人生。

我有幸受邀参与了本书的撰写。作为作者之一,在本书出版之际,我仅从个人的角度谈谈写作的心得,以及此书想要传达的一些理念。

对习惯于编写代码的我们来说,写一部人文类图书,是一个不小的挑战。生活虽很平淡,人生也谈不上成功,但回望一下毕业这么些年的足迹,其间的困惑和迷茫、欢笑与泪水,对于那些有志于在程序员道路上有所作为的大学生,和入行不久正经历如我当年一般困惑的职场同仁,还是有一定益处的。

本书四位作者,来自不同的公司,有着不同的经历,但有一个共同点,就是热爱程序员的工作。当初的我,也是因为热爱这个职业而转行的。工作十年间,遇到过很多挫折,走过很多弯路,始终不变的是对行业的热爱。能把爱好和职业统一起来,是人生的一大幸事。所以,我一直以感恩的心,从事着自己的职业。

曾经有一年时间,由于种种原因,我的生活几乎陷于困顿,似乎看不到希望,当快撑不下去的时候,我对自己说的最多的一句话就是:这是暂时的,终将会过去的。我终于熬过来了。现在回想,那间200元租来的民房,一直充满了温馨;蹲在路边吃的那碗热干面,相当美味;邂逅了那个女孩,她的笑容充满阳光。我想说的是,不管处在人生的什么阶段,也不管是欢笑多还是泪水多,只要心中充满爱与理想,生活处处都有精彩。

是的,对生活和工作充满爱与理想,我们就是这样一群平凡而快乐的程序员。

如果读者能从本书中读到这些并有所感悟,那么我们的写作也就变得更有意义。

此书能够顺利出版,首先要感谢陈禹成编辑和徐定翔编辑。没有陈编辑最初的鼓励与组织,就没有此书的编写;没有徐编辑专业的建议,就没有此书现在的模样。还要感谢曾经的老板与同事,没有你们的严格要求、精诚合作和“勾心斗角”,就没有现在的“我们”,就没有书中那些精彩的故事。

当然,还要感谢作者的家人、同学及朋友,是你们的支持,才让我们有了前进的动力。

最后,请允许我在里这特别感谢一个人:我的二姐——冯广秀。在我女儿小焰焰眼里,你就跟妈妈一样。李春雷2011年2月于武汉

吴亮的故事

想把我的经历写得轻松一些,所以文字就从梦开始吧。这里的梦不是指睡梦中的梦,而是说梦想。什么样的梦想呢?是儿时关于未来的梦想。为什么不说是理想呢?是因为我想表达两个意思,一是梦想带有一丝感性、一份想象力和一点点童话的味道;二是理想可能包含别人对你的期盼,这份期盼也许是长辈、老师、偶像或者身边的人带给你的,这些也许是现实的和善意的,但这不是你的梦想。现在,请你闭上眼睛好好想想,把那些不属于你自己的部分从内心暂时拿掉,剩下的部分,就是你自己真正的梦想。梦想很有用,梦想是一切的缘起,如果有可能,请追寻自己心中的梦,在实现之前,不要停下脚步。

第一章 初识编程

追寻心中的梦

先从我最初的梦想讲起,正是这个梦想使得我最终走上了程序员这条道路。

儿时的我是个很爱玩的小孩,对电子游戏没有多少抵抗力。我的父母都是普通的国企职工,家庭条件虽然还可以,但也谈不上富裕。我很少缠着父母买东西,唯一的一次是在一年过生日的时候,我缠着父亲买了一台任天堂的红白机。

虽然我向父母保证了严格限制玩游戏的时间,但我仍然在周末、寒假和暑假里把各种游戏卡带疯狂玩了很多遍。很快,我就发现了自己面临的问题,旧卡带上的游戏玩腻了,能借的卡带和好玩的游戏也越来越少。有时候事情就是这样奇怪,没游戏机时,也不会觉得什么,可当你一旦有了它,麻烦就来了,没有新鲜游戏玩的感觉是那样空虚和无聊。于是我就想,什么时候要是自己能编写游戏玩该多好。

在我开始梦想有一天自己能编写游戏玩的时候,正是20世纪90年代初。当时个人电脑还未普及,它是大公司和国企里的高级玩意儿,一般人接触不到。

在我还沉迷于红白机游戏的时候,父亲的办公室里就摆着几台电脑,那时电脑给我的印象只是一个键盘接着一个方方的显示器,黑屏幕上滚动着看不懂的英文字母。我想电脑除了打字还不知道能做其他什么。一天,我在办公室里等待父亲感到无聊的时候,看到父亲一位同事的电脑屏幕上显示出图形界面和中文,因为我在红白机上玩过类似的文字游戏,所以我很快便知道那是一个文字类型的三国志游戏,我第一次知道电脑还可以玩游戏。离开父亲的办公室之后,我仍然在不断地回想刚才看到的情形,我发觉自己对电脑产生了无法抗拒的兴趣。当时我并不知道程序是如何编写和运行的,只是认为电脑的输入终端比红白机要复杂得多。我想,也许用电脑的键盘输入一些“魔法”字符,就真的能实现我的梦想——为自己编写好玩的游戏。

三年后,在我初三的那年秋天,家里有了第一台真正的电脑——486的PC,几个月后我在DOS操作系统上编写了一段用QBasic语言编写的程序。尽管那段程序的功能简单得无法再简单,但它是真正的程序。我终于掌握了和电脑自由沟通的语言。能做自己喜欢做的事情是幸运的。我之所以走上软件开发的道路,完全是因为儿时那个简单的梦想。虽然不是什么伟大的志向,但重要的是我始终在为这个梦想而努力,至今未曾放弃。挑选合适的语言

有了电脑以后,我花了几个月时间熟悉操作系统和其他知识。那时的操作系统并不像现在的Windows有友好的界面,记住复杂命令是件比较烦琐的事情,但我却乐在其中。

在熟悉了基本操作之后,我开始研究如何用电脑编写程序——是的,我那时已经知道了程序这个概念。当时,国内流行一种叫学习机的东西,它是一种增强版的游戏机加上一个键盘,在上面可以编写一种简单的Basic代码。

经过摸索和查阅资料之后,我确信我的电脑上带有一种Basic语言的实现版本——QBasic。我沉迷于用QBasic编写各种程序,起先是一些简单的计算和字符的输入、输出,后来编写了一些文字类型的小游戏,比如猜数字之类,还实现了一个交互菜单。但是,经过一段时间的研究后,我发现QBasic的功能很有限。

QBasic代码不能独立运行,而我想要一种真正能以exe文件形式运行的程序(尽管当时我对exe的真正原理和PE(protable executable)头文件等概念一无所知),经过研究之后,我知道了QBasic是解释型的,只是一些跑在解析器上的简单指令。另外,QBasic对底层的支持也很少(现在我知道如何用这样的语言操作寄存器、调用中断以及直接与汇编交互,可当时这些概念对一个初学者来说过于深奥)。经过一段时间的学习之后,我做出了一个决定——放弃QBasic,学习一种更强大的语言。经过仔细挑选之后,我选择了C语言。有人说程序员选择的第一门编程语言非常重要,甚至能决定程序员未来发展的道路。这种说法虽然太过绝对,但从某种程度上来说也不无道理。编程语言不是程序的全部,但是编程语言能影响程序员解决问题的思考习惯,就像语言可以影响一个民族的文化一样。

现在想起来当时的选择并不多,除了BASIC、C和PASCAL等语言之外,少有其他语言能够进入我的视野。Java是后来才流行的语言,而FORTRAN语言几乎只在高校的计算机实验室里才有人使用。

我花了大量时间熟悉C语言的语法、理解指针等概念,因为我确信它是能够实现我梦想的最合适工具。现在计算机和程序设计如此普及,可选择的余地也大大增加了。许多高校都开设Java课程,讲授数据结构和算法,学习算法的朋友还能够选择Scheme这样简单的语言(Scheme是Lisp的一种方言;Lisp是一种善于描述问题本身的优美语言)。几个月下来,虽然我一直在学习C语言的各种特性,但也只弄清楚了其中的一部分。我开始用C语言编写一些模块化的程序,每次写完一个程序,总要很费劲地解决由于自己对语法不熟悉而产生的编译错误。我发现自己还缺少一些知识,但是又不知道究竟缺少的是哪一部分。当时的计算机教材很少,我自学的那本书也缺少很多内容,于是我决定自己去找课上。对于程序员来说,编程语言只是基础得不能再基础的工具,如果你想要成为真正优秀的程序员,还需要掌握语言之外的许多东西。数据结构和算法,是设计和开发复杂软件产品所必须掌握的知识。幸运的是,我很快在课堂上接触到了这些知识。混入课堂偷学

当我逐渐熟悉C语言的时候,升入了省重点高中。我希望高中能有程序设计的相关课程,但可惜的是,学校并没有安排这方面的常规教学课程,只有针对参加信息奥赛班的学生的辅导课。我的一位同班同学是学校信息奥赛班的队员,向他打听到上课时间之后,我开始混入教室去旁听信息奥赛班的课程。当时在信息奥赛班上课的有几所学校的学生,因此相互之间并不认识。而我又是刚升入高中的新人,那些听课的学生以为我是其他学校的,也不会多问。这样我就堂而皇之地偷听完了几乎整个学期的课程。

信息奥赛班的课程主要是用PASCAL讲数据结构和算法方面的知识,虽然当时我并不能完全理解那些课程的意义,但是我想那些知识是有用的。学习这些课程后,我发现我以前对数据的理解非常肤浅,我编写的程序几乎很少出现复杂的数据结构,对指针的了解也仅限于基本的用法,学习算法课程使我理解了线性表、二叉树等数据结构,也让我对C语言的指针有了全新的认识。当时,互联网远没有现在普及。渴望学到更多知识的我,在自己找书本学习的同时,还想出了一个到学校信息奥赛培训班去偷学课程的法子。正是那些课程,使我第一次接触了数据结构和算法,为我将来的程序员之路打下了非常重要的基础。

当我升入高二时,已经能用C语言设计和实现稍微复杂一些的程序了。我开始着手编写实用的小工具,还用Turbo C图形库编写了一些带图形界面的小软件。

编写带图形界面的程序一直是我努力的方向,因为要实现编写游戏的梦想,这一步是必须的。不过我发现手中的那本教材根本没有提及如何编写这类带图形界面的程序,只有一个章节在介绍中断调用时提到过显示器相关的例子,可我当时完全没有这方面的基础,根本不能理解这章所描述的东西(中断调用,这个概念对于当时的我无疑太过深奥)。我很苦恼,直到有一天,我偶然在书店里发现一本介绍Turbo C图形程序设计的书,如获至宝,我现在还清晰地记得当时兴奋的心情。

很长一段时间,我沉迷于使用Turbo C图形库编写带图形界面的程序。比如我编写了一个带复杂的多级下拉菜单的学英文的软件,一个支持鼠标、可双人对弈的五子棋游戏(大一时我还给那个五子棋游戏增加了简单的人工智能)和其他一些小程序。我对Turbo C的热情持续到高二的寒假,直到父亲帮我升级了一次电脑,操作系统换成了当时流行的Windows 95,软件更加丰富,娱乐性也更强大了。不过这次升级也带给了我新的问题——发现自己所用的Turbo C并不能实现Windows下的程序,于是我不得不继续寻找新的答案。操作系统升级为Windows 95之后,编写带有窗体的Windows程序就成为我新的追求目标。虽然这个今天看来无比简单的目标,但在当时困扰了我很长一段时间。那时候,计算机书籍很少,几乎没有教材介绍如何编写Windows下的程序,于是我不得不暂时放弃编写Windows程序的想法,而把兴趣转向另外一个领域。转战互联网

高二那年,暴雪公司推出了一款即时战略游戏——星际争霸。当时我就读于省重点高中,班上的同学也很爱玩这款游戏。在这群玩星际争霸游戏的同学里,有一位外号叫冰魂的,他不但是星际高手,而且是一位数学方面的奇才,在数学计算上表现了很高的天赋。冰魂接触电脑很早,加上他的天赋,很快就成为我们这群人中的高手。在高二开设的计算机课上,当其他同学还在学习打字时,他用Basic编写了五子棋程序。我们经常一起玩星际争霸,也一起探讨程序上的问题,后来还合作写过软件。

高二那年我家里开通了网络。当时的互联网不像现在这么普及,也没有ADSL或者小区宽带,更别说3G网卡了。当时上网,只能选择33.6 KB的Modern(俗称猫),不论上传还是下载,速度比现在以兆字节计算的网络速度慢得多。当时互联网上的内容也少,形式较单调,远没有现在这么好的互动性。即使如此,上网也是一件令我很高兴的事情,因为我发现,用电脑可以迅速地获取信息,与陌生人交流。

那些和我们一起打星际争霸的同学,因为经常去网吧,也学会了上网。慢慢地一些同学家里也有了电脑,于是除了学校和网吧,我们有了一个新的交流场所——互联网。

当时我们在互联网上的交流没有现在方便,既没有免费邮箱,又不流行像QQ这样的IM工具,更没有SNS服务。我们只能通过简单的Web页面、留言簿、BBS和一种称为聊天室的互动网页服务来进行交流。

上网的同学渐渐多起来,冰魂和我就想做一个让同学们交流的平台。当时我学习C语言受阻,于是开始把注意力转向网页。通过学习,我知道了在互联网上看到的页面,是用一种被称为HTML的标记语言和被称为CSS的样式表来实现的。可我对编写标记语言不感兴趣,也没有设计方面的天赋,好在冰魂有不错的美术功底,所以设计和实现页面的工作就交给他去完成。

HTML和CSS是客户端浏览器上的东西,它们只能实现静态的效果。如何让网页变成一个留言簿或聊天室,成为互动和沟通的平台呢?我再次陷入了困境。

这次遇到的困难比较大,我根本不知道如何入手。虽然我会C语言,可是C语言能在Web上跑起来么?而且当时我甚至不懂Web服务器的概念,互联网也不像现在有那么多资源和强大的搜索引擎。所以只能靠自己查阅资料。

后来我才明白原来网页是由远程计算机上的Web服务器提供的,大多数Web服务器支持一种通用的编程接口,叫CGI。支持CGI的服务器可以用一种通用的方式调用服务器端的程序来提供动态内容,而C语言恰好能够胜任这项工作。我非常高兴,立即开始测试,可是当我按照查阅的资料进行操作时,发现资料中只笼统地介绍了IIS Web服务器,并没有说明具体的服务器配置。我对IIS还是一知半解,而且,当时我只懂得用Turbo C的环境来编译源代码,对编译选项一无所知。尽管我经过了多次努力,仍然无法在本地的IIS服务器上顺利运行CGI程序。

接下来我又发现了一个更棘手的问题——在远程服务器上运行程序。那时我虽然找到了支持CGI的免费空间,但是不能在远程空间上编译出可执行文件(远程空间是UNIX系统,本地编译的文件是无效的)。于是,一直对用C语言能编译出exe文件沾沾自喜的我,第一次感觉到编译型语言在Web开发中的无奈。

发现用C语言编写动态Web程序这条路走不了,我只好去寻找另外的路。大约两周之后,我找到了自己想要的答案。转向互联网,是我在使用C语言受挫后的无奈之举。可万万没有想到的是,几年后,我会真正与互联网和Web开发结下不解之缘。也许,一切皆在冥冥中自有定数吧。不过当时,我对Web开发没有足够的认识,以为还像写C程序那样简单,于是在实践中走了不少弯路。选择脚本语言

我发现用C语言编写动态Web程序这条路走不通后,在一个偶然的机会中,一种脚本语言进入了我的视野。这种脚本语言就是后来很多Web开发者和系统管理员喜爱的Perl语言。

Perl语言给了我很大的震撼。我第一次发现还有这样的脚本语言,能够用简洁的表达来实现复杂的工作。同C语言相比,Perl语言简洁得令人难以置信,没有讨厌的指针,只有简单的易于理解的引用,强大的正则表达式让Perl语言在文本处理上的表现极其出色,神奇的符号变量和潜规则将代码省略到极致,这些特点使我很快就喜欢上了这门语言。而且,Perl语言用简单直白的方式提供了CGI模块。

在Perl语言的帮助下,我终于成功地执行了CGI代码,它在本地服务器和远程服务器上跑得一样好。

经过初步尝试之后,我想用Perl语言实现真正实用的Web应用。当时互联网上流行一种简单的访问量计数器,原理是记录每次用户请求,统计出访问网站的次数。

计数器是个非常简单的应用,只需要在服务器响应页面请求时更新访问数值,访问数值保存在文件或者数据库字段中。唯一需要注意的是,不管是使用文件还是数据库字段记录数值,在读/写的时候都要考虑加锁,以避免因为读/写冲突而产生脏数据回写,导致数据统计错误。很快,我实现了在服务器上正常运行的计数器,甚至为它增加了ID的功能,以便在不同的页面上配置不同ID的计数器,让它们互不冲突地统计不同页面的PV(page view,页面访问次数)。

实现计数器之后,接下来实现的工具是留言簿。在这次尝试中,我开始碰到真正的问题,它不是来自于服务端脚本,而是来自于前端。

在我研究Perl语言的时候,冰魂也没闲着,他一个人完成了网站的页面制作——当时我和他合力维护着一个英语学习的个人网站,我用Perl语言编写的工具也正好在这个网站上派上用场。Web开发与传统的软件开发是有很大不同的,进入Web开发领域,意味着你不仅要像传统的程序员一样同数据、应用逻辑打交道,还要同用户端的浏览器打交道,应付各种各样奇怪的问题。HTML、CSS这些看似简单的技术,其实有其复杂的一面。如果把那些在服务器上处理数据和应用逻辑的部分称为后端领域,那么同浏览器、用户界面和用户行为打交道的工作,就称为前端领域。今天的互联网发展速度如此迅速,各种复杂的用户体验随着技术和产品的成熟都慢慢变成现实,以至于Web开发的前端领域变得越来越重要,于是许多公司独立的Web前端开发和用户体验设计部门就相应诞生了。这一方面说明了用户体验的重要性,另一方面也说明了从技术角度讲,前端和传统的后端开发有着很大的差异性。只是当时,初入互联网开发领域的我还不明白这一点。痛苦的Web开发

在决定了使用Perl作为编程语言之后,冰魂和我开始了真正的Web应用开发。我们准备给班级做一个论坛,让同学们自由地发布信息。与其说是一个论坛,还不如说是一个简单的留言簿,支持的功能有限,除了发帖和回复外,没有其他功能,连账号注册也不开放,而是预先设定好的。

这样一个看起来很简单的东西,做起来还颇费神。首先由于经验不足,我不会把CGI输出的调试信息输出到页面上,也不懂如何利用服务器的日志,所以调试程序时大吃苦头,跑不起来的代码就得去猜是哪里的错,或者利用低效的方式逐一排查。其次,冰魂设计的页面是HTML和CSS的纯静态网页,转换成Perl语言输出的动态内容也很麻烦,稍不注意,就可能弄乱布局。

就这样,我做做停停,用了两倍多的时间才把基本功能做出来。当我看着自己辛辛苦苦完成的留言簿终于能够正常访问时,心中不免有些得意。留言簿运行良好,而且有冰魂的设计功底,它看起来简洁美观,一切似乎都很美好。不过我的成就感没有持续多久,很快便发现了问题。对于程序员来说,我认为Web开发是有些特别的,不论你擅长哪一方面,最好具备一点Web开发的经验。因为在Web开发这个领域里,你更容易深刻地体会到程序功能的实现和程序能够无误地被用户所用是有很大差别的。

我邀请几个同学来体验我的程序。大家对清爽的页面赞不绝口,但是没过几分钟页面就不能工作了,服务器抛出了一个HTTP 500状态码。

原来我没有对提交上来的表单内容做任何的校验,有同学提交了内容,却忘了写标题,而我是用Perl的文本数据库简单存储数据的。我在存储记录的时候忽略了没有内容的key,而在读取留言记录的代码里根本没有对这种情况进行处理。经过这件事,我开始认识到用户提交上来的东西是需要验证的,不仅包括检查内容,还包括检查格式和长度。Web程序很容易让用户通过表单提交数据到服务器,而用户提交的数据内容是不可预期的,所以,验证表单提交的数据是Web应用必须要做的工作。

我随之改进了程序,把通过表单提交的数据发回服务器进行验证,只有通过验证的数据才写入存储,否则就返回一个信息,告诉用户验证失败的原因。但是自己在测试修改后的程序时,忽然闪出一个念头,由服务器去验证数据是否有问题,这种方式虽然可行,但如果数据一开始就是错的,那么就不要向服务器传送才对。应该有一种技术直接在客户端校验数据,这样才能大大减少错误数据浪费带宽和服务器资源的机会。数据在发送回服务器前就应该完成验证,这个念头当时在我对Web开发服务器以及客户端原理和机制还几乎不了解的情况下能够在脑子里产生,现在想来还真是灵感一现。多年以后,当我成为职业前端开发工程师时,再回想过去,不禁感叹人生的轨迹往往和不经意间的灵感有着某种关联。第一次接触JavaScript

在客户端验证数据,一方面可以避免浪费服务器资源,另一方面可以避免用户重新输入表单。我想,应该还有一种更好的工具能解决我面临的问题。现在回想起来,当年我在许多时候面对的大都是用什么工具去解决什么具体问题,那是我的一种思维惯性,不见得是最好的,但在我看来,它对高效解决问题很有帮助。我也接触过很多程序员,他们对自己所擅长的语言有明显的偏好,不乐意用自己不熟悉的技术去解决问题,即使那种技术更加适合解决那类问题。

因为有了前面几次寻找工具的经验,这次我几乎没费什么工夫就找到了一种客户端脚本语言——JavaScript。当时电脑杂志和网站把这种语言吹得挺神奇,很多人也热衷于用它实现页面上各种花哨的效果,以此来吸引来访的用户并炫耀其技术实力——尽管当时大部分代码都是相互拷贝的。

我查阅有关JavaScript的资料,知道这是一种嵌入在客户端浏览器中的可执行脚本语言,它类似于C语言的语法风格,但是没有像C语言那样对数据类型进行严格检查,也没有指针等复杂的东西。相对于C语言而言,JavaScript似乎只是个功能简单的语言。

我花了一天时间熟悉JavaScript的语法和一点点DOM知识,第二天我就用JavaScript在客户端验证表单了。这一次如果用户填写的数据格式不对,数据表单就不会提交,直接在页面上给出提示。

完成了表单验证之后,我对JavaScript语言产生了兴趣,开始研究它的其他用处,不过很快,我就失去了兴趣,因为我发现用JavaScript也无非是在客户端浏览器上玩一些骗“美眉”的小花招,搞不出什么大名堂来,和服务端语言所能完成的工作简直有天壤之别,我便把JavaScript丢在一边。那是1999年的寒假,中国的互联网刚刚起步,距离Web前端开发工程师活跃于互联网应用,以及JavaScript成为全球最热门的十大编程语言的时代还有至少五年时间。客户端表单校验,大概是JavaScript最常用的领域。当然,当年很多网站把JavaScript用于分时段给客人问候,动态改变页面文字、字体或图片滚动效果、鼠标特效等,我在查阅JavaScript资料的时候看到了很多类似的例子,我对这些东西不是很感兴趣,我认为简洁的风格更容易受到人们的青睐。我不反对用JavaScript做某些恰到好处的效果,但适可而止就好。现在,JavaScript的重要作用已经没有人怀疑了,随着JavaScript在浏览器数据交互和控制方面愈加活跃,它在表达特殊展示效果方面的应用也渐渐减少。特别是随着W3C组织赋予了CSS更多的展现能力,让大家更加了解了脚本语言的合适定位,不再把一些原本应该由CSS去完成的工作加在脚本头上了,这是个好现象。

高二上学期,除了学业之外,我还有大量的课余时间可以利用,因此我做了许多有意思的事情,其中一部分和计算机有关。玩数学游戏

高中,我们班上有不少数学高手,冰魂是其中一位,另外一位是外号叫老鼠的同学。当时班上盛行益智类的数学游戏,其中一个游戏是从扑克牌的猜24点游戏衍生出来的,是随机取4个数字,每个数字用一次,通过加、减、乘、除得到一个数M,谁先找到一个解,谁就获得胜利。当时我们通常用扑克牌或者书的页码的个位数来玩该游戏,不过不是算24,因为24是一个有很多因子的数,太简单,我们通常会取一个素数,比如29,可以用4个数字7、5、3、2计算出29,通常有多个不同的解,比如7乘以2加上5乘以3,或者7乘以5减去3乘以2,等等。

遇到一些难解的局,我想尝试用程序来解,给出确定的解或者证明无解。这个问题属于比较典型的算法题,我当时的思路是,首先判断它是否是一个可以被分治的问题。如果这个问题可以被简单分治,那么意味着当你手里有N(比如4)个数字时,只需要判断在第N个数字和第N-1个数字进行四则运算后的结果中是否有值为M(比如29)的解。但这个想法是错误的,因为有可能需要先分别对两对数进行运算,例如上面所说的7、5、3、2例子的两种解法都是先对两对数相乘,然后相加或相减。分治法假设运算是顺序进行的,但是运算优先级的存在使得假设不成立。不过分治的思想依然可以解决这类问题。分治思想是程序算法中最基本和最核心的思想之一,分治最直接的表达形式是递归,而熟悉这种形式对于开发者理解程序以及训练思维有明显的帮助,但是在我经历的学习生涯中,发现身边的很多同学有意回避递归,一些教科书也以递归影响效率为理由而不介绍或只粗略介绍一下。虽然大多数线性递归应该通过优化成线性迭代的方式提高效率,但是基本的递归思想还需要熟悉和强化。

第二章 我的大学

第一次面试

在千禧年的夏天,我终于走进了大学校门。回顾大学生涯,影响我人生最大的事情有两件,第一件事是认识了寝室的一帮哥们,和他们一起度过了四年校园生活;第二件事是在一次偶然的机会中加入了一个社团。我在这个社团一呆就是四年,对我后来的职业发展产生了影响。

大一时,有不少社团到校区招收新生成员,但我并不感兴趣,主要是因为当时校区在城郊,离主校区远,且校区内都是大一新生,社团活动不活跃,而大多数社团要交会员费,不划算。自从报了一次棋社后,我对其他社团都不感兴趣了。

2000年秋天的一个周末,我在寝室里无聊地看杂志,室友小白从外面跑进来说:“食堂门口有个社团招收新生,我觉得不错,就报了名。”“哦。”我连头都没抬起来,继续看手中的书。“老大,我也帮你报了名。”小白很兴奋地说。“什么?”我放下手中的书,抬起头来说:“是美女在招人?”我对小白这么积极感到奇怪,以前他和我的态度一样。

小白说:“是微软技术俱乐部,参加是免费的。”

听起来有点意思,是微软的社团,而且免费,那就试一试吧。于是我抱着试一试的心态,从小白手里接过宣传材料和报名表,见宣传材料上面写着“微软技术俱乐部工程中心下属的Blue Strom Team招收新人,请报名者等待面试通知”。什么?加入社团还要面试,我更加感兴趣了。我没想到自己的第一次面试,不是在求职的时候,而是在加入一个社团的时候,当时我并不知道“微软面试”有多么BT,只是觉得面试官问的问题很有意思。

晚上,我来到一间教室,面前坐着一位胖乎乎的同学,他就是我的面试官,也是后来社团的同事,我们叫他小胖。由于我已经经过了一次面试,正当我疑惑的时候,小胖开口了,说:“上次面试官觉得你的技术背景很不错,所以今天我想跟你讨论一些更开放的话题,”并接着说,“请你告诉我。下水道的井盖为什么是圆的。”

这是什么怪题目,脑筋急转弯么?“因为相同周长下圆的面积最大,或者因为圆井盖不容易掉进井里,或者因为圆井盖可以滚动,或者@#@$@##@……”我当时说了一大堆,或许把小胖说懵了。

等我说完后,小胖又问还有没有别的可能,于是我又说了一通,最后直到我真的没有说的了,小胖才点点头。“你觉得杭州市一共有多少盏交通灯?”小胖接着问。

我心里想,哪来的怪问题,一个比一个BT。“大概几百盏吧,可能400多盏?”我答道。“为什么?”小胖似乎对我的回答感兴趣,进一步追问。“从城市规模、道路数量、人口数、交通灯平均距离等可以分析和计算出来。”我说,小胖最终点点头,想转换话题时我突然想到另一种答案,于是脱口而出,“三盏,红灯、绿灯和黄灯。”

小胖忍不住笑了,然后说,“刚才都是一些开放性的问题,没标准答案,就是看看你的思维能力怎么样。”小胖接着说,“有一个机会,不知道你愿不愿意接受,我想让你成为Blue Strom Team的领导者,它是微软技术俱乐部工程中心下属的技术团队。”“如果我成为领导者,要做什么事情呢?”我问道。“它是今年打算要成立的团队,现在还没有队员,你必须自己去寻找合适的队员、组织活动、带领团队参与微软技术俱乐部的各类活动……”小胖说。“如果可以,我愿意试试。”我说。就这样,面试结束,我成为了微软技术俱乐部Blue Strom Team的领导者,在后面的三年多时间里,这个俱乐部给我留下了很多美好的回忆。我曾经也拿交通灯的问题去问一些同学、同事,得到了各种不同的答案,最经典的答案是,“既然是微软的面试题,那就简单了,一共有下面几种交通灯——交通灯95、交通灯2000、交通灯2003、交通灯XP Home Edition、交通灯XP Professional、交通灯Vista以及交通灯7。”逃课的日子

我学的是电子类专业,大一上学期,我基本每天都去上课,对待课程认真,几位室友也一样。到了大一下学期,觉得上课没意思,就开始选择逃掉一些不喜欢的课程。

因为逃课,我有了很多空余时间。当时由于学校在郊区,校外没地方玩,要打发时间,室友不是打牌就是玩电脑游戏。因此在那时,我重新开始玩星际争霸。

在我们寝室里,除了我以外,还有小白、文煜、阿骚、阿顾等,我们几个人经常一起玩星际争霸。一开始,我们自建二对二本地局域网游戏,但后来很快就不满足于自己PK,所以组建了一个战队找其他同学PK,偶尔也去外面战网找些高手单挑。

总之,在很长一段时间里,游戏成为我们寝室的主流,除了星际争霸之外,我们还玩其他一些游戏。不过,我除了游戏,还继续自学编程方面的知识,主要学习C和C++语言,也学习PHP。我看了课表的安排,要到大二才开设计算机组成原理课程,所以我提前去图书馆借了些书开始学习计算机组成的相关知识。

提前学习硬件知识,对我的帮助是比较大的,当学到寄存器这部分内容的时候,我终于明白了什么是中断,有一种豁然开朗的感觉。于是我回头把C语言中关于中断调用的章节重新拿回来仔细翻看,这次没有费多少力气就完全掌握了。Turbo C图形程序设计那本书里关于驱动鼠标的例子,我之前不是很理解,现在已完全明白了。大学之前,我是老师眼里的好学生,学习用功,不贪玩。但到了大学之后,我就开始逃课,尤其是大一下学期和大二,我几乎逃掉了一半以上的课程。但幸运的是,每次考试我总能勉强过关,甚至有些科目的成绩还考得不错。当然,在这里我并不是要鼓励大家逃课,而是说在大学里当你有了自己支配时间的权利时,一定要想明白两个问题,一是来学校究竟为了什么,二是毕业后究竟想成为什么样的人。招到第一批组员

大二时,搬回主校区是件令人高兴的事,一是因为主校区位于西湖畔——风景优美,二是因为这里集中了几乎所有研究生和大部分本科院系,社团活动也能更好地开展。

搬迁后不久,一天小胖来到我的寝室说,“明天俱乐部工程中心招新会员,你跟我一起去吧。”工程中心招收新人,我盼望已久,这样我就能从中挑选出Blue Strom Team合适的组员了。

由于微软技术俱乐部是学校为数不多的工程技术类社团,又得到微软公司的支持和赞助,并且不收取会员活动费,因此招人现场比较火爆,短短一个小时,我们收到了很多份报名表。

由于微软技术俱乐部要招收有特定技术背景或有活动能力的会员,因此,我们发放了类似于简历的报名表来收集报名者的信息。报名表中既包括一些技术类的基础问题,也包括一些非技术类的问题。俱乐部招收的会员除了工程中心主要的技术人员之外,还有行政中心的活动组织人员,管理中心的俱乐部管理人员和研究中心的高级研究人员,等等。

收集好简历以后,我从小胖手里要走了一半,希望从中选出Blue Strom Team的合适人员。在经过仔细挑选之后,我最终确定了初步人选,并决定在接下来的几天约请他们聊一聊。

第一名同学外号叫小猫,广东人,不是学计算机的而是学生物医学的,但是对计算机很感兴趣。小猫的技术水平虽不高,但是他善于思考,很有学习劲头,而且有很好的团队精神。

第二名同学外号叫星爷,他这个外号和周星驰没有半点关系。星爷是软件学院2000级的学生,他不是一个幽默的人,相反,他是个典型的技术人员,做事很踏实。后来他也成为我们工程中心的核心开发人员之一。

第三名同学的外号叫巴拉克,也是计算机系2000级的学生,基础好,编程能力强,算法也好,后来我们参加学校的ACM比赛,他是其中的主力。

几天后的一个周末,我把他们三个人叫到一起,在学校的一个小餐馆吃了顿饭,就这样微软技术俱乐部工程中心的Blue Strom Team正式成立了。作为技术领导者,经历了这些年之后我发现,团队最初人员的选择,是一件非常重要的事情。因为一个团队的文化,往往是由最初建立团队的那群人所决定的。头批人员不仅仅是创建了团队,还将自己的性格、能力和做事风格注入团队,深远地影响团队的发展。俱乐部的活动

当时的微软技术俱乐部,是由微软亚洲研究院高校事业部直接资助的,每月提供固定的经费,定期提供软件和硬件供活动之用,而学校作为合作方,提供场地作为活动地点。我一直认为微软扶持高校社团是一个聪明的做法。我曾经计算过,微软投资俱乐部,每月大约提供2000元的经费、定期提供一些软件,加上一两台服务器,一年下来成本也不高,但换来的是在高校中持续产生影响力。相比之下,IBM采用另一种方式,固定每年在学校举办为期一周的IBM技术周活动,不但花费巨大,而且宣传效果远不如微软。

当时学校为俱乐部提供的活动室离我的宿舍不远,所以有活动时比较方便。但是,我发现在没有活动的时候活动室不让人进,而工程中心的同学们平时的技术研究又缺乏场地,因此,我和几位组员讨论后决定说服管理层开放俱乐部活动室。

我通过小胖找到管理中心的负责人,表示希望开放俱乐部活动室。管理中心的负责人很为难,因为活动室里有微软提供的服务器和书籍,如果东西丢失怎么办?但在我和其他几位负责人的坚持以及一再保证下,最终他答应了。

活动室开放之后,我和工程中心的几位组员做出第二个决定,小猫、星爷、巴拉克和我一起把寝室的电脑搬进了俱乐部活动室。在后来的大概一年多时间里,我和组员们在活动室一起研究技术,一起写代码,度过了很多愉快的时光。自从我们将电脑搬进活动室,其他组员也陆续搬了进去,这样就形成了比较好的技术氛围。对俱乐部的定位,微软一是希望通过俱乐部组织活动帮助在高校传播其企业文化和先进产品,二是希望通过俱乐部在高校培养一批核心技术人才和管理人才,为其储备优秀的毕业生和实习生资源。从这两个角度来讲,我认为当初做出开放活动室的决定是正确的,自有了活动室之后,工程中心的同学们就能在一起交流,一起工作,从而共同提升技术水平和管理水平。

有了活动室以后,我们又做了第三个决定。微软每个月给俱乐部一小部分经费,这部分经费是不够组织大型的技术宣讲活动的,所以我们想,与其做大型技术活动,不如用来做其他非技术的团队活动,因此我们就把一些经费拿去组织户外运动——购买烤肉和啤酒,路过的同学都可以来一边分享一边讨论技术或者其他话题。“挥霍”这些经费,虽然有助于俱乐部的发展,也没有招致管理层的反对,但是它也间接带来了一些问题——微软觉得我们的技术实力不足。但是我认为,俱乐部技术实力的不足,应该和我们在团队管理上的经验不足有关。一个技术团队如何有效地发展,是我直到今天依然要面对的问题,值得好好思考。一个技术团队如何定位自身,是一个非常值得探讨的话题。说实话,我们那一届俱乐部是备受争议的一届,从技术方面讲,可能不如后面几届,但是,我们那一届俱乐部又是在学生中影响力最大的,也是活动办得比较成功的一届,所以我认为,这一切在于对俱乐部本身的定位和资源状况的认知。

学习程序设计

因为我的专业不是计算机,课余时间如何补充自己的程序设计知识已成为一个问题。我除了在俱乐部和会员们交流之外,就是寻找各种自己可以阅读的书。

现在想来,当时我买书是很疯狂的。因为只能靠自己摸索,找不到方向,互联网又不像现在这么发达,并且也没有很好地学会利用互联网,所以只能到书店把自己觉得顺眼的书买走。这些书包括各种编程语言、数据结构与算法、设计模式、网络编程、人工智能、黑客、计算机语言原理以及软件工程。我把生活费省出来,一个学期下来,购买几百上千元的书是很正常的事。虽然花了很多冤枉钱,但是也读了几本很好的书,这几本书对我的成长起了很大的作用。

第一本对我帮助很大的书是Charles Petzold的《Windows程序设计》,这是一本非常实用的书,它让我彻底掌握了Windows编程的方法,解决了一直以来困扰我许久的“Turbo C不能写Windows下程序”的问题。在学校时我对待程序的态度属于实用主义,偏好于放在手边就能用的一类书。《Windows程序设计》和《Windows API程序设计参考大全》陪伴了我三年多的大学生涯,大学时写出的几个软件,几乎都是这两本书的功劳。

第二本帮助我较大的书是《程序设计语言:设计与实现》,这本书全面介绍了现代计算机体系结构下的程序语言的特点、设计、解析、过程控制和数据抽象。在当时国内还没有翻译《Structure and Interpretation of Computer Programs》(《计算机程序的构造和解释》)的情况下,这是一本不错的替代教程。通过对这本书的学习,让我跳出了具体程序设计语言、语法的狭隘视野,加深了对计算机语言本质特点的认识。

第三本经典的书是《设计模式》,相信很多读者读过或者至少听说过。它的四位作者是国际公认的面向对象软件领域的专家。要深入理解面向对象和设计模式,这本书是很好的选择。不过当时这本书对于还在学校的我来说显得晦涩了一些,它的价值直到我工作了一段时间以后多次翻阅才逐渐体现出来。

除了上面这几本书外,还有其他一些关于算法、人工智能、软件工程类的书,这些书或多或少对我起到了一些帮助。学习程序设计,我不建议像我这么瞎碰,如今互联网这么发达,豆瓣、社区也有很多信息和资源,它们都能够帮助你规划学习程序设计的道路。所以不要自己埋头看书,建议多加入社交圈子,主动交流,不懂就向有经验的前辈请教,那样你的职业发展道路会顺利很多。黑白棋剪枝算法的设计

在2002年夏天的微软杯软件设计大赛上,我的作品有幸入围,因此获得了一次到微软中国研究院(即后来的亚洲研究院)参加决赛的机会。

这个作品本来不是为了参加比赛,而是自己写着玩的。因为我对棋类游戏感兴趣,大一时写过五子棋的程序,所以看到论坛上有人把黑白棋的软件放在一起比较棋力时,我就萌生了写一款黑白棋打败软件的想法。当动手写这个游戏时,我对棋类游戏的人工智能所知不多,对黑白棋也没有深入研究过,只知道一些规则和边角价值的基本判断法。黑白棋,又叫反棋(reversi)、奥赛罗棋(othello)、苹果棋或翻转棋。黑白棋在西方和日本很流行。游戏通过相互翻转对方的棋子,最后以棋盘上棋子多的来判断胜负。它的游戏规则简单,上手容易,但是它的变化却非常复杂。有一种说法:只需要几分钟学会它,却需要一生的时间去精通它。

从算法层面来说,棋类游戏的AI(artifical intelligence)实现比较简单,即在当前状态下分析自己有几个可选点,然后判断自己选择这些可选点后盘面形势的优劣如何,之后针对每个可选点分析对手有几个可选点,再分别假设对手选择这些可选点后盘面的优劣情况,依此类推,类似于人的思考原理。因此这种算法包括两个方面,一是树的搜索,二是对局面的判断。

树的搜索比较简单,就是尽可能高效地判断每个可选分支,从而在有限的时间内提高搜索的深度;对局面的判断则和人对棋的理解有关,根据规则判断出棋局的优劣分值,作为搜索结果选择的依据。

对于树的搜索,开始时我选择所有可能的点进行完全遍历,比如假设当前局面下黑棋有五种选择,分别为A、B、C、D、E,白棋有六种选择,分析这两步之后,共需要判断的次数为5×6=30次,这是搜索深度为2的情况,但是只搜索两步显然是不够的,随着搜索深度的加深,判断次数呈指数级增长,当搜索深度超过七步时,就需要花费很长的时间才能计算出来,所以必须对程序算法进行优化。

实际上没有必要对所有可选点进行完全遍历。例如,假设程序判断自己走了A之后,2*N步以内,盘面得到的最好结果是10分,而选择走B,如果对手走了B的可选的下一步a,发现盘面得到的最好结果是6分,那么也就是说,如果程序走B,只要对手走了a,无论怎么走,盘面最好也只有6分,程序就不可能选择走B了,B的可选下一步的其他选点也就没有必要再计算了,这样就形成了一个“剪枝”的情况。事实上,这是一种叫做α-β的经典的剪枝,其基本思想是一边生成博弈树一边评估计算各节点的倒推值,并根据评估出的倒推值及时停止扩展已无必要再扩展的子节点,即相当于剪去了博弈树上的一些分支,从而节约了机器开销,提高了搜索效率。具体的剪枝方法如下。(1)对于一个与节点MIN,若能估计出其倒推值的上确界β,并且这个β值不大于MIN的父节点(一定是或节点)的估计倒推值的下确界α,即α≥β,则不必再扩展该MIN节点的其余子节点(因为这些节点的估值对MIN父节点的倒推值已无任何影响),这一过程称为α剪枝。(2)对于一个或节点MAX,若能估计出其倒推值的下确界α,并且这个α值不小于MAX的父节点(一定是与节点)的估计倒推值的上确界β,即α≥β,则不必再扩展该MAX节点的其余子节点(因为这些节点的估值对MAX父节点的倒推值已无任何影响),这一过程称为β剪枝。

搜索应用中常使用“剪枝”算法,运用上面的原理可以减少很多搜索步骤,缩短搜索时间。

程序经过改良后,搜索深度有了明显提高,从原来的中盘6~7步,残局7~9步提升到中盘8~9步,残局最大可达14步,这基本上已经接近人脑的极限。不过,即使达到了这样的搜索深度,但我的程序的胜率还是不高,我判断是估值算法的问题。基于自己对黑白棋的理解,我认为盘面的优劣由两个简单的因素决定——棋子的位置和数量,因此我简单把处于角部、边以及中央的每颗棋子记一个分值,然后通过计算己方总分减去对方总分的办法来评估局面,导致程序在选择时总是优先占据边角以及让自己的棋子数量最大化。

后来,我发现其他程序在选择落子点的时候,并不是让自己的棋子尽可能地多,相反,而是让自己的棋子尽可能地少,让对手的棋子多。

原来黑白棋的关键是在中盘的棋盘上占据8×8的要点,因为是自己和对手轮流下棋,为了能让自己尽可能多地占据要点,所以要尽可能少给对手选择的机会,而一般情况下,自己的棋子剩得越少,对手可选择的着手点就越少,这样的局面下,自己的优势才比较大。想明白这个道理之后,我修改了估值策略,采用了少子策略和抢占关键位置相结合的估值算法,这一次程序的AI果然大幅提高了。黑白棋的战术是尽量不给对手可选择的余地,不让对方占据好点,尽可能逼迫对方因为别无选择而下坏棋,这种战术,在实战中被证明是最有效的。

在完成这个程序之后,恰逢2002年微软杯程序设计大赛开赛,我把这个程序拿去参加了比赛,取得了不错的成绩。第一次面试

作为俱乐部的核心成员,我获得了一次被推荐到微软亚洲工程院应聘的机会。当我绕过香格里拉宾馆长长的走廊,忐忑不安地站在房门前按门铃时,我的内心是复杂的。一方面我非常想进入微软工作,另一方面,坦白来讲,我对自己没有信心。

面试官非常年轻,叫林斌,是微软亚洲工程院的技术负责人。在简单的寒暄以及自我介绍之后,林斌开始问一些测试相关的技术问题。虽然我了解过一些微软面试,但是这次我面试的职位是微软亚洲研究院的测试工程师,由于我之前从来没有接触过测试类的工作,所以对此一点也不了解。

第一道面试题是围绕一个基础的场景展开的。林斌让我想象在一家软件公司,开发人员根据手册实现了C++中的atoi函数,并将字符串转换为一个整数,而我作为参与单元测试的工程师应该为它设计什么样的测试用例。atoi是C++语言的一个基本函数,定义在stdio.h中,它将字符串转换为一个整数并返回结果:int atoi(const char*str);

这个问题看起来没什么难度,但它考验你的是程序设计基本功。首先需要你理解这个问题的输入和输出,其中输入是一个字符串常量,输出是一个由字符串转换而成的整数。接着要充分理解这个函数的定义,考虑测试用例的类型,根据C++手册的定义,atoi要转换尽量长的字符串为数字,直到无法成功转换下一个数字为止。理解手册的定义,才能找出正确的测试边界。手册中提到的一个关键词是“尽量长”,它意味着形如123abc的字符串只需要解析到数字123并返回就行,后面的abc不能解析就忽略掉,实际上对字符串做了“部分转换”,所以,测试用例根据成功转换的内容划分为完全能转换、部分转换和完全不能转换三类。完全能转换为形如12345之类的纯数字字符串,部分转换为形如数字+非数字组合的字符串,完全不能转换为首字母非数字的字符串以及空字符串。更进一步,能被转换的部分不完全是全数字,还有正负符号,另外还包括以0开头和非0开头的数字,除此之外,当数字字符串超过整数的最大精度时,也要算做部分转换。下面给一组例子:

说实在的,我并不知道如何有条理地回答这类问题,在林斌的一步步提示下才慢慢得以完善。接下来林斌又让我思考,作为开发人员如何实现这个函数,检查所有这些情况。我发现这个简单的函数其实不好写,需要考虑很多东西。最后,林斌又和我讨论了关于手机黑盒测试的一些问题后就结束了这次面试。这样我的第一次求职面试以失败而告终。通过这次面试,我认识到很重要的一点——基本功非常重要,它会影响你今后在工作中解决问题的方法与效率,进而影响你的职业发展。几年后,我在面试一些同学时也比较看重他们的技术基本功,基本功既是一种实实在在的能力,也是一种专业素质的表现。第二次面试

第一次面试失败之后,我又去参加了几次招聘面试,拿了几个做电子产品和做软件的公司的offer。大四上学期,由于课程少,我正想从这些offer里挑选一个去实习时,微软亚洲研究院又面向高校招收访问学生,我又一次被推荐。所谓访问学生(visit student)是微软亚洲研究院从高校招收的全职实习生,不属于校园招聘,也不保证实习生毕业以后一定能进入微软工作,如果要进入微软,还需要走正式的招聘流程。

这次面试我的是一位学长,叫刘利刚,学校数学系的博士。由于有了上次的经验,我不再那么紧张了。但是,也许是因为研究院和工程院的要求不同,研究院更偏向于基础研究,所以整个过程里我没有被问到太多的程序方面的问题,而是一些数学问题。

第一道面试题:abc-cba=cab,问a、b、c各是多少。

刘老师问完这个问题后,起身给我倒水,在他转身的一瞬间,我报出了答案,a是9,c是4,b是5。刘老师非常惊讶地问我,“你是怎么这么快得到答案的?”

我几乎无法回答,我做这种数学题,常常用直觉的方式去找答案,然后代入验证,但是没有明确的思路。

看得出刘老师对我无法解释如何推导出答案不满意。在他的示意下,我继续研究等式,我注意到中间的一列字母,b-b=a,意味着a不是0就是9,由于abc的第一位a不可能是0,所以只能是9,那么第一列a-c=c, c就是4了,a、c确定,b就为5了。

第二道题是关于天平和砝码的问题,刘老师让我用尽可能少数量的砝码,称出1克到100克的物体的重量。我又用直觉给出了答案,用1克、2克、4克、8克、16克、32克、64克一共7个砝码就能满足要求,但也无法说清楚理由。在刘老师的提示下,原来砝码称重量和二进制计数的原理是等价的,砝码放在天平上表示1,不在天平上表示0。这个问题就等价于用多少位二进制数表示1到100的十进制整数,答案是7位。之后,我们继续就这个问题展开探讨。对于天平来说,如果把砝码和物体放在同一侧,就等于做减法,记状态为-1,其他两个状态依然是0,1。对于-1,相当于0-1,在前面补一个1,记为10-1=2,等价于一个三进制,所以可以把问题等同于用多少位三进制数表示1到100的十进制数,答案是5,砝码的设计为1克、3克、9克、27克、81克。我们讨论完后,简单聊了一些其他话题就结束了这次面试。这次面试对我的影响也是很大的,我从中学到了很重要的一点,即要将数学模型和计算机模型联系起来。在我面试的一些学生中,我也会同他们讨论一些和程序设计联系在一起的数学方面的问题。我也听到一些观点,说学前端开发懂数学没什么用,甚至说程序员没必要数学好,只要能理解业务就行了。我坚持认为,程序设计本质上是抽象现实世界模型为计算机模型的过程,而在抽象过程中,数学无疑是最好的工具。实习经历

在经过面试之后,我又经历了两轮电话面试,最终我幸运地成为微软亚洲研究院的访问学生。再次进入西格玛大厦,我内心无限感慨。一年多前在这里参加比赛时我就对自己说,我还会再回来的。微软有着非常优秀的企业文化和非常好的研究环境。在西格玛大厦不足半年的实习,有些辛苦,但从中学到了非常多的东西。现在,从我居住在北京的房子步行十分钟,就能走到西格玛大厦,这栋楼依然如我当年看到的那个样子,变化不大,但是回想往昔,在微软研究院,实习已经是六年前的事情了。

在办理好入职手续后,我被分到了网络图形图像组,也就是刘老师所在的组,负责协助刘老师做一些基础研究。微软亚洲研究院是微软做基础研究的主要机构。在这里工作不像在商业公司做产品,反而有点像在学校里跟着导师做一些研究课题。我的任务主要是研究图形变换,阅读论文,分析其中的算法,用程序实现,然后再加以改良。接手第一个任务时,刘老师问我,大概多长时间能完成,我也不知道如何估算,随口回答“三天”。后来刘老师说,这个用一周左右比较合适。

研究院的项目完全是探索型的,大部分是未知的东西,很有挑战性。因为是未知的,所以我也不知道能否完成,压力自然也伴随而来。最开始的一两周,我也遇到了很多困难,经常是方法上的问题,这时候刘老师总会耐心地指导我。那段时间的经历,使我也更进一步了解了数学方法的重要性。记得有一次在处理2D图像变形的时候,我一开始采用的是代数方程的办法,计算非常复杂,花了很大的精力,效果还是不理想;后来刘老师说,遇到这种问题,最好利用向量。他向我详细解释了用向量处理这类问题的要点和方法。我回去采用向量的方法重构了程序,很快得到了很好的结果。数学模型非常重要,同样的问题采用不同的模型,往往会有很大的差别。例如求点到曲线的距离、曲线的切线和法线等问题,用向量方法比用代数方程容易得多。还有一类问题我们在前端开发中也会遇到,就是让元素做曲线运动,比如圆周运动。如果采用圆的代数方程来做,实际上增加了难度,因为代数方程在开根号时需要判断象限的符号,而如果用圆的参数方程来做就简单很多。

除了一般的基础研究之外,我还协助参与了部分项目的产品开发,但主要都是一些不太重要的琐碎功能,不过微软当时采用的.NET的开发模式以及大公司的开发流程和开发规范,也让我学到了很多,积累了很多的经验。

2004年4月,我在微软亚洲研究院实习了四个半月后回到了学校,完成我的毕业设计论文。毕业前夕

回到学校以后,我把时间都花在了毕业设计和跟随学校导师进行的一些研究上。我的专业是电子信息,除了学习软件知识外,还学习一些硬件和通信方面的内容。对于普通的硬件原理、通信以及电路,我不感兴趣,但是对于单片机、控制芯片、可编程逻辑门电路还比较感兴趣,所以我把大部分时间花在了对单片机汇编程序的研究上。

汇编语言是面向机器的指令式语言,它的优点是对机器的精确控制。我喜欢这类语言,因为这类精确控制流程的语言能够高效把握。我比较喜欢精确的流程控制和过程抽象,不喜欢程序设计方面隐藏了细节的可视化东西,更愿意用一行行代码去控制内部的逻辑。所以汇编语言这类底层的语言更符合我的爱好。我想有些程序员应该和我一样,“痛恨”一切表面化的东西,比如靠拖曳生成界面的那些程序。我喜欢精确控制,所以我一直没有去深入学习MFC,同样是Windows编程,我更喜欢通过直接调用API的方法来实现我的程序。

单片机的程序设计还有一个特点,是用仿真器在PC上模拟运行,之后将程序最终写入芯片,再自己布线和焊接电路去验证它,所以这是一个要求动手能力的活。当时我和另外几位同学白天写汇编程序,晚上焊电路板,日子过得也蛮有趣的。不过这种汇编程序有个非常头疼的问题,有时候会有莫名其妙的错误,是软件错误还好,一般能通过调试器定位问题,但是有时候仿真器运行正常,而电路板出了问题,就比较麻烦了,得按照走线一一排查,有时根本不知道哪里出了问题,同样的电路,前一块板子能够正常运行,后一块就不行,排查每个元件和焊点的问题,最后发现是芯片自身的不合格导致的(部分芯片出产就有次品率,一些次品会流落市场)。当遇到最难查的问题时,常常好几天毫无进展,这非常考验人的意志力和耐心,我一直认为现在自己从不轻易放弃的习惯,是那时培养出来的。学习汇编语言其实是一个不错的选择。也许有人认为它上手难,其实它不会比数学分析之类的基础课难,而且可以看到实实在在的结果。如果在PC上研究,你只需要安装一个宏汇编器,而如果想研究单片机,可以跑跑电子市场,自己买些材料,去网上下载一个免费的仿真器,这些都不会有多大的成本,但是当你学过这些内容后,收益是巨大的,你会更加理解计算机体系和指令集,也能养成抽象思维的能力,这对程序员的生涯帮助很大。回顾大学经历对于即将进入学校的读者或者正在学校读书的读者来说,可能比较关注在大学里应该学习什么,应该怎样学习,才能成为一名优秀的软件工程师。在这里,分享一下我的一些想法和经验。

大学四年,我并没有把时间完全花在课程上。相反,我把大部分时间花在了课程之外。我的专业是电子信息,课程相对来说多一些。尽管要学的东西很多,但我大二和大三还是逃掉了不少课,专业课只在考试之前参照习题把一些东西死记硬背下来,因此效果可想而知,并没有真正掌握多少有用的东西。虽然我的学习方法有待商榷,可是我认为国内高校的课程安排也有问题。大一、大二的基础课内容深,学习任务重,往往强调授业,却忽视了告诉学生为什么要学习这些内容。比如大学里的工科数学给我的感觉是陷入细节,将学生拖入到做习题和应付考试的泥潭中去,丝毫没有体现出数学作为工具的实用性,以及作为一门“抽象艺术”的美感。

很多时候,我们需要的是视野和背景,数学应该理解“为什么”和“有什么意义”,而不是去记忆某个复杂的积分公式或者数列展开式。学校应该针对不同专业开设拓宽视野和培养兴趣的课程。大一、大二是培养专业兴趣和专业感觉的最佳时间,课程设置应该偏重于这些方面。应该建立合理的方式去评价学生是否适合他或她所选择的专业,以及今后发展的潜质。例如学校应该向计算机专业的学生开设类似于《计算机程序的构造和解释》(据说北大有开这门课)之类的作为入门课程。这种课程既能够培养学生系统全面地看待计算机科学,又强调动手实践,既能够培养学习的方法,又能够很好地回答“为什么要学习”的问题。

作为学生,在踏入高校大门的时候,重要的是自己应该认真去规划在校园里的几年时间,必须清楚自己需要什么。你进入这个学校,不是为了玩和混日子的,也不是为了考试拿高分得奖学金的,而是实实在在通过努力提高自己的能力,将来走上工作岗位去追求自己的事业。

机会不会等你,环境不会因你而改变,但是你可以去抓住机会争取对你有利的环境。如果我大二一直玩下去,也许我现在不能拥有自己喜欢的事业。由于对程序设计的热爱,我参加了微软技术俱乐部,俱乐部的工作让我放弃了玩游戏。我喜欢玩游戏,但我内心一直有个声音告诉我,游戏总有一天会玩腻的,你小时候不是希望自己能够自由设计游戏么,现在你可以去努力实现这个梦想。我清楚要成为软件工程师应该怎么做,我一直在为此努力,最终这种努力也会给我回报。

也许你在学校里有和我类似的经历,也许你在学校里遇到过和我同样的问题,那么你也可以去想、去做,去成为自己想成为的人,好好利用校园里的几年时间,你可以做到。

第三章 踏入社会

深圳入职深圳是我步入职场后停留的第一座城市。这座毗邻我国香港的经济特区给我的第一印象远比想象中要好,我原来听说的深圳是个很乱的地方,但是从第一眼看到这座城市,就觉得这是个美丽的南方都市,市容整洁,绿化良好,交通便捷。

作为一名职场新人,当我走进公司时,我的心情是比较激动的。虽然之前我在微软亚洲研究院实习了几个月,但是研究院给我的感觉和学校的实验室差不多,而现在,当我即将成为真正意义上的职业软件开发工程师,实现自己的第一步职业理想时,心里难免有些得意。甚至当HR让我填写入职表时,脑中已经开始幻想坐在宽敞的工位前敲代码的情景。但是很快,一个通知彻底打破了我的幻想。

填写完相关入职表后,HR告诉我们,公司为了让开发人员更贴近客户,从今年开始所有的新人在完成入职培训后将下放到分公司实习半年,实习岗位为客户服务、系统实施或者二次开发,下派的地点为深圳或广州。

听到这个消息,我非常失望。我根本不想去机构做客服或系统实施人员,只想成为真正的软件开发人员,在电脑前写代码,而不是成天在外面跑客户。对于不了解接触客户对写程序有帮助的我来说,我认为去做客服或者系统实施纯粹是浪费时间。但是不管怎样,既然来了,也只有先做了。

我带着失望的表情坐班车来到公司安排的宿舍,在我将行李搬进宿舍的时候,一位先到的同事出来热情地迎接我并帮我一起收拾房间。

这位同事是山西人,也是在杭州读的书,和我同一届入职,但他硕士毕业,所以大我两岁,人挺实在,也很会和人相处,还喜欢喝酒,我们很快彼此熟悉了,经常一起出去喝酒。他的网名叫笨笨,所以我和其他同事也这么叫他。笨笨和我成了非常好的朋友,同时他也是我们团队中非常棒的同事,也是在他的推荐下,我们一起从客服提前转到了系统开发,后来又一起从分公司回到总部信息部,开发公司一套核心的业务管理平台。来深圳大约一年后,他开始负责公司整个核心信息平台的总体需求,成为非常出色的需求规划师,而我则以项目经理的身份带领研发团队配合他的工作,在一起的两年多里,我们始终配合默契,工作愉快。2007年的时候,笨笨由于个人原因离开了深圳,而我则在2008年离开了公司,去了另一座城市。到机构实习

两周左右的新人培训结束后,我被分派到了深圳分公司,实习客户服务。分公司卖给客户的软件通常需要工作人员上门安装、做培训和售后服务,因此配有专门的客服人员来完成这些工作,我的主要工作是当客户遇到问题时,上门拜访解决问题。

公司的软件功能复杂,有时根据不同客户的需求,还要做一些定制开发,因此维护成本高,客户也经常遇到问题,所以每天要派出大量的人员上门服务。公司对新人还比较重视,一开始几天会派经验丰富的老员工做师傅指导,学习师傅怎么解决客户的问题。

一段时间下来后,我对客户可能遇到的问题心里有了数,这些问题基本上可以分为三类,第一类是因为某些原因导致软件不能正常工作,比如防火墙、杀毒软件或者系统等出现com组件的故障,这时需要耐心排出故障,或者重新安装软件甚至重装系统。第二类问题不是软件不能工作,而是某些功能模块因为意外出现bug产生错误数据,这时需要在数据库内修复数据。第三类问题是由于某些模块的功能不能满足客户的业务需求,需要记录下问题,反馈给研发人员开发补丁,解决客户遇到的问题,但这种情况极少。

一开始我跟随师傅在分公司附近上门服务,后来慢慢开始独立到客户那边处理问题,工作的范围也慢慢扩大,去一些比较偏远的地方。在分公司的时候,每天的工作大约是两到三家客户,遇到的问题基本上没有超出前面三类问题的范围。当时,虽然一段时间内我都是在做客服工作,但由于处理数据问题需要熟悉业务和表结构,所以对一些产品的部分文档甚至源码,需要从总部研发部那边调来学习、研究。由于可以阅读代码,加上自己在工作中发现的问题,促使我思考公司产品在架构上的一些缺陷。这套产品是基于微软的com+体系开发的,编程语言是VB,局部的代码结构比较科学,对规范的要求比较严格,体现了大公司对技术质量细节的把握。但是从大局上来看,混乱的com组件体系,过于分散的各个模块缺乏统一管理,以及业务层面上的随意耦合,不规范的外部接口,加上一些匆忙开发的二次开发组件,使得整个软件的安装变得极其复杂,而且运行稳定性不高,经常因为组件冲突导致bug,甚至不能使用。

在深圳分公司实习了差不多两个月后,我被调到了位于布吉关外的龙岗办事处,那里不仅离住处较远,而且传说治安也乱。那段时间,我每天要坐一个半小时的公交车到办事处。

第一天到布吉报到的时候,经理对我说,小吴啊,以后一些客户可能比较远,在这边出勤要比分公司辛苦。行,我回答得很干脆,完全没能理解经理所说的“远”是个什么概念。第一周经理说,小吴啊,你刚来不久,今天派你去一个比较近的地点。我接了单往外跑,倒了两趟车,个把小时,终于找到了地方。我这才意识到经理所说的“远”是什么意思了,原来倒两趟车、个把小时单程算是“近”的。第二周经理说,这次去个稍微远一点的地方。有了上次的经验,我对倒三趟车,两小时左右的路程丝毫不惊讶了,只是有点好奇,真正的“远”是什么概念。第三周经理终于说,小吴啊,今天去的地方很远,你带上点干粮和水,如果时间晚了,在那边找个地方过夜,回来报销。结果我跑到了深圳和惠州交接的一个小村庄,早晨9点半不到从办事处出去,到晚上10点半才一身疲惫地回到家里——我实在不想在那种地方过夜。

办事处也不是一无是处,至少比分公司清闲。在布吉那边我每周基本上只需要上门服务2~3次,有时候一整天都待在公司内。不只是我这样,实际上其他一些客服人员也比在机构清闲,无聊时他们会在办公司里打打星际争霸游戏和CS,偶尔我也参加,感觉又像回到了学校,但更多时候,我会利用这些时间仔细思考和总结这段时间以来的工作心得和收获,也开始思考公司派我们来实习的意图和我真正的所得。公司说让我们到机构实习,是因为发现研发团队和实际用户脱节,不像一线员工那样理解用户的需求。为了更深入理解用户的想法,急用户所急,改善研发过程,公司才决定派新人到机构锻炼。但是我慢慢对公司的看法产生了怀疑。我认为是因为需求管理不当,开发人员直接面对客服反馈的用户需求,甚至以外派的形式直接面对客户,客户把未经整理的需求直接压给研发,加上资源调配不力,项目周期评估和控制不当,从而导致研发片面追求进度,质量不高。管理层是创业者,他们将以前小作坊模式的开发经验搬到现实中,希望继续按小作坊的方式进行开发。但不管怎样,这段实习的个人经历,对我后来的职业发展还是有较大的帮助。二次开发经历

在深圳分公司和龙岗办事处实习了三个月之后,我转去做二次开发。所谓二次开发,是指在公司现有产品的基础上,针对客户的业务需求,进行一些扩展开发。但是由于产品的扩展接口不规范,二次开发并不是想象中的那样容易,甚至有些功能是完全在数据层面上自己实现的,与原本的产品除了用同一套数据库实现之外,没有任何联系。我来到深圳分公司的第四个月中接的任务,就是这种情况。

公司派我去一家大客户——啤酒生产厂,他们的业务系统是采用公司的企业管理产品定制开发的。这套定制开发的产品之前运作良好,但是,当他们决定在汕头新建一个啤酒厂时,事情有了变化。

啤酒厂的业务包括进货、销售、提货、回瓶四个阶段,原来那套系统只是针对深圳本地的业务情况设计实现的,不但未考虑异地进货、销售和跨地区回瓶的情况,连单据上的“深圳”等字样都是死的,无法修改。我的任务是协助修改以前的程序,支持该啤酒厂在汕头新开的业务。

原本我以为这样的问题不是很复杂,但是当我拿到程序源代码时,我发现错了。面对几年前使用VB写的代码,没有任何文档,甚至代码中有价值的注释都寥寥无几,一时间我不知道该如何入手。负责编写这些代码的程序员几年前已跳槽到了这家啤酒厂,因此我去找他请教,可是我很快发现,他面对自己几年前写的代码,也是一片茫然。公司给我的期限只有两天,怎么办?

无计可施,我决定采用笨办法,不去试图理解程序的逻辑,只简单搜索所有文件中的“深圳”字样,然后把那几十处文字都找出来一一替换,运行程序,看看它们分别出现在什么地方。这个办法的效果比我想象的要好很多,也幸亏原先的程序都是完全写死的,没费太多时间,我就找出了十几处要替换成汕头的地方,然后将这些地方的文字改为可配置项,在文本库中进行配置,一天内就顺利解决了这个问题。这个问题解决之后,接下来就要对业务进行修改了。我仔细询问了业务员相应的流程后,发现啤酒的分销模式一般不允许跨地区进货和销售,但是可能存在跨地区回瓶的情况,需要对这种情况进行处理。虽然我不太理解整套系统的业务流程,时间也不允许我去深入理解,但是,不同地区回瓶的状态是一定的,无非就是本地回本地、异地回本地、本地回异地三种,分别对应三个不同类型的单据即可,所以做起来也就简单了,直接从输入对应输出去考虑就可。

两天内我修改出一个基本够用的支持异地开酒厂的系统版本,接下来,就是去汕头的啤酒厂实施该系统。很多开发人员有一种完美主义倾向,对质量不好的代码有一种仇视的心理,恨不得把它彻底重构。修改别人的代码时不要马上推翻逻辑,认为自己的总是好的。如果你在有限的时间内无法彻底重构代码逻辑,最好不要去碰那些逻辑,采用“笨办法”有时候未尝不是最恰当的。

系统实施比我想象中的要复杂得多,首先是新厂的业务部门不熟悉这套流程,需要做深入的培训;其次是新厂的单据格式和流程与原厂有细微的差异,所以软件还需要进行细节的修改;再次是领导对软件本身提出了一些细小的需求,这些额外工作使得系统实施的时间比预期的长。回到总部

2005年1月初,我结束了实习,回到了公司总部。说实在的,实习期间的经历对我是有帮助的,通过接触客户,我学到了很多程序开发之外的技能。

分公司的领导向我许诺一些条件,希望我留在那边,但是我知道自己要回到总部,去做自己应该做的事情,这就是我当时内心中的想法。

回到总部的时候,有个小插曲,本来我被分配到研发部负责公司的一个产品开发,但是不到一周的时间,我被调到了公司的信息部。

这件事情的起因是这样的,在分公司除了二次开发外,我和笨笨一起参与了一个客户服务部内部使用的信息平台的开发,主要给客服人员管理他们的服务工单。之所以要做这个系统,是因为深圳分公司希望通过加强对客服人员的管理来提升业绩,而我们正好实习过客户服务,对客服的流程比较清楚,所以就安排我们俩来实现这个系统。这是一个完整的业务系统,包括客户服务工单的分派、管理和审批,以及客户问题的积累和集中管理。因为分公司要求我们做成一个用浏览器就能访问的Web系统,所以我与笨笨商量后,决定采用JSP服务和SQL Server数据库来实现该系统。在收集了所有的需求之后,我们用了大约三周多的时间来完成该系统的编码和测试,最终该系统在11月下旬正式上线。这套系统,在分公司内部得到了客服人员的高度认可。总部的人经常来分公司参加会议,总部信息部的同事看到这套系统后,认为和他们想做的系统相似,因此建议将这个系统拿到总部去开发,于是,也把我和笨笨直接转到了信息部。

说实话,到信息部我还是比较高兴的,虽然我也想在产品线上做开发,但是我分配到的产品是用VB开发的,而我又恰巧不喜欢VB那套东西,相比之下,我对Java更感兴趣。而那套客服用的系统是我和笨笨从头开发的,我们非常熟悉。虽然有些地方不是很完善,还需要重构,但比较有挑战性,所以我更愿意在信息部继续完善那套系统。人生中将面临很多选择,有些选择会对你职业发展的道路产生关键影响。现在想来,如果当初我拒绝调回信息部的安排,继续留在分公司,或者在总部做一名产品开发人员,那么很可能我就不会和Web开发以及项目管理结下不解之缘,我的人生道路很可能也不是现在这个样子。“MOP”系统开发

信息部是负责开发公司内部系统的部门,主要包括公司的ERP系统、研发管理系统和总部以及渠道的业务系统等。

刚回到信息部的时候,我和笨笨继续负责完善那套给客服人员用的系统,以便向全国机构推广。这套系统完全是用JSP实现的,没有复杂的架构。说到此,我要提一下之前的一个插曲。当我们接到分公司做这样一个系统的要求时,我和笨笨讨论用什么语言来实现,因为我在学校里只用过.NET,而笨笨只用过Java,所以我们必须从.NET和Java中选择一种。考虑到公司的技术积累中,由于Java相对比较强,如果使用Java开发,一是可以用到公司的中间件服务,二是将来让其他同事接手维护比较方便,所以最终采用Java来实现这套系统,这也是我第一次接触Java。

回到总部后,除了我和笨笨外,又增加了一些开发人员,包括和我们同一批入职的阿日、老巫,以及后来加入的大琴、建新、老丁等。这些同事在Java方面有丰富的经验,我也跟他们学到了很多Java方面的技术。几个月后,随着业务系统功能的逐渐增多和复杂化,信息部决定重新开发一个包括售前、售中和售后服务的一整套流程的业务平台,新的平台被定名为“Marketing Operate Platform”,因此有一个响亮的简称为“MOP”。这套系统比较复杂,需要专门的需求规划人员,因此笨笨主要转向做需求规划,另外一名叫吉儿的女生负责整理整个平台的业务需求,老丁、老巫等技术实力强且经验丰富的同事则负责系统架构的设计,而我主要转向项目管理和前端这块。

新的系统采用MVC架构,不再是简单的JSP。一开始我们用Hibernate+Spring+EJB,后来发现EJB过于庞大,于是将EJB换成Struts,后来又升级成Webwork。模型—视图—控制器(MVC)是Xerox PARC在20世纪80年代为编程语言Smalltalk-80发明的一种软件设计模式,至今已被广泛使用。MVC的好处是通过强制的分层让代码的数据、处理和表现分开,各层分别完成自己的任务,使代码的逻辑清晰,而且易于维护。

由于我第一次接触完整的Java版MVC框架,所以少不了要进行一些研究。我发现采用框架确实能很好地规范代码和约束开发人员,从而降低成本,提高效率。但是框架也有其自身的问题。首先,采用的框架配置文件多,比较烦琐,而且配置出现的问题不像程序中的错误那么好定位。其次,框架的层次多,接口多,层层调用,即使一个很简单的功能,也要很多框架代码,因此写起来既麻烦,运行起来效率也不高。最后这些框架并没有解决前端的问题。

Struts和Webwork为后端Java开发工程师提供了解决前端问题的方案——采用封装好的XML标签组合,不用接触任何与浏览器打交道的东西,例如DOM、事件模型、JavaScript。这个想法当然很理想,可事实上却很难做到。封装好的标签确实可以很快地完成任务,但是无法满足灵活多变的前端需求。因此,我发现要解决的问题是,在没有专业前端开发团队的情况下,要尽可能满足用户对Web交互的复杂需求。要解决前端问题,还需用前端的工具,同浏览器打交道。于是,我在参考了微软.NET代码的框架结构后,设计了一套纯粹的JavaScript前端框架。技术人员总倾向于用自己熟悉的技术来解决一切问题,正所谓当你手中拿着锤子时,看到的所有问题都是钉子。我认为这种想法不好。问题应该由适合它的技术来解决才能事半功倍。前端问题还是要同浏览器打交道,这就是前端开发者的意义所在,强行用封装的方式解决不了根本问题。应该把职责分开,如微软设计的WPF就是把performance和logic彻底分离,分别交给各自擅长的角色去完成,而不是用单纯的一种技术或者架构来解决问题。

要解决问题,先要定位问题出在哪儿,而信息部要解决的现实问题是没有专门的前端开发团队,诸多平台只有一名设计师兼页面工程师,这就使得完成复杂的前端交互系统几乎成为不可能完成的任务。所以,我设计JavaScript框架的目标是,约束和强迫不想和前端浏览器打交道的工程师们必须同浏览器打交道,但是,又可以用接近于后端代码的形式去开发。

在框架里我把一个具体应用作为一个Application,一个页面作为一个Page实例,每个Page总是通过Application.Run方法工作,在生命周期里有自己的消息流,在InitializeDocument(DOM Ready)方法中进行DOM元素的事件集中注册,使整个框架结构看起来非常像.NET的形式。

在底层,我对脚本做了扩展以支持更多的基础方法,完善对象继承机制,同时对DOM进行一次封装以兼容各种浏览器。在完成这些工作之后,技术人员要做的事情就是为每个HTML缩写对应一个单独的脚本文件,按照框架约定的方法去实现前端交互代码。

完成上述工作后,后端工程师以这种方式编写脚本代码没有大问题,工作得以顺利进行,一年后,集公司主要业务为一体的支撑运营平台MOP系统正式上线,得到了机构和渠道业务人员的认可。框架按照严谨的规范约束开发人员编写代码,它的最大作用是让各个程序模块有章可循,从而增强代码的可维护性。无论是MVC框架还是JS前端框架,目的都一样。但是,框架也有自己的问题,例如多余代码,严谨有余灵活不足,效率损耗等,因此不是所有的情况框架都适用。如果要想让产品在Web交互上有很大的优势,则必须组建一支专业的前端开发团队。而框架作为技术手段,它只能保证“有效性”,不能保证“卓越性”。从技术到管理

在MOP团队成立之后,随着业务需求规划越来越复杂,团队人员逐渐增多,产品也越来越复杂。因为MOP系统是公司内部很重要的业务平台,同公司多个业务部门打交道,因此组织协调的工作需要专门的人员来负责。于是笨笨和我承担了一部分管理项目的职责,他主要负责协调需求的部分,我主要负责技术这边的接口。

原以为做管理者很简单,然而,当我发现职责变化之后,一切都开始变了,最明显的是技术工作不再是我一个人可以控制的事情,我需要将项目需求分解之后再分配给MOP团队的每位同事去负责,还要确保他们能够按时按质完成任务。除此之外,我还要和不同业务部门的负责人进行沟通,说明什么工作可以优先完成,什么工作建议往后安排,以及解释为什么工期不能提前,必要时还要一边忍受他们的抱怨,一边安抚自己团队的成员。我不像以前那样亲自写代码,但我感觉自己比以前任何时候都忙得多,而且还失去了写代码的乐趣。

除了工作上的变化外,我发现自己和以前相处很好的朋友之间产生了距离,特别是谈工作的时候。我开始感觉到一些同事对分配的工作有意见,特别是临时任务。我可以理解,因为没有人喜欢不干事的管理者(在他们看来我没有干事,因为工程师通常不大理解技术之外的工作),总把事情丢给他们处理。但是我尝试自己来做技术工作,往往又产生更糟糕的结果,持续的编码工作导致我没有时间整理计划,团队的项目控制一团糟。渐渐令自己身心疲惫,感觉到以前做技术时从来没有过的压力,也曾经产生过要放弃的念头。在大部分时间里,MOP团队总是非常忙。当时我们加班特别多,记得有时连续几个晚上超过12点,甚至通宵工作,大家的压力可想而知。工程师们会看着我这个管理者,他们不明白为什么自己总有那么多活要做,觉得是我分配给他们无穷无尽的工作。表面上看起来也如此——我分配工作并检查计划,于是,他们会对管理者产生抱怨。除了项目外,一些小细节也经常让管理者头疼。比如绩效考评时给一个同事高分,另一个同事产生意见;不经意间给人过多的苛责;或者强迫他人按照自己的思路来工作——工程师出身的管理者经常有这种毛病。这些细节问题日积月累下来,最后会产生极其不好的结果——下属对你失去信任。

长时间地加班令团队感到不满,协调沟通技巧不到位,让业务部门也颇有意见。另外讨论需求和技术的时候,原本可以自由争论,但因为我是管理者而强迫对方妥协,最后产生的结果又不理想,这类事情堆积起来后,对于平时又没有沟通习惯的我来说,最后的结果就是让一些同事对我的能力产生怀疑。为了一些细节问题,我也经常和部分同事争吵,这样给整个团队氛围带来了不好的影响。最不可思议的是,这些问题发生后,我自己还蒙在鼓里,自我感觉良好。直到我和吉儿与笨笨之间发生过几次大的争吵后,才醒悟过来,原来管理真的不能忽视细节,一定要从团队的“人”这个重要因素抓起。想起这一点,让我回忆起在学校俱乐部时,“以人为本”的口号还是我提出来的。

我开始重新审视自己的工作,从小处着手,真正站在团队成员的立场上去考虑问题,同他们重新建立信任关系,并且收回所有的苛责,取而代之的是赞扬和鼓励,我发现心态和行为改变之后,一切都回到了正轨,工作变得轻松,和大家相处也更融洽了。

作为管理者,要让成员做好工作,需要做到三点,第一,做任何事情要先找对人;第二,找到合适的人之后尽可能提供他所希望得到的帮助;第三,站在他的立场同他沟通,多鼓励。管理是一门艺术。在大学的时候,虽然接触过MSTC中的团队管理,但我一直认为自己爱好技术。从没想过自己有一天会走上管理的岗位。从技术到管理的转变是痛苦的,但我坚持了下来,也让自己成长了起来,学会把自己的目光从自身转向团队,寻找管理者应该承担的责任,学会享受提供支持和协助他人成就的乐趣。我想,如果没有在MOP团队的这段经历,我不会成为现在这样一支优秀前端团队的一员。新的机会

来到新的团队,缘于一次偶然的机会。我在QQ上碰到meizz,他是CSDN的名人,Web前端的大牛。他问我愿不愿意尝试去一个新的团队,专注于前端开发方面的工作。这也许是一个很不错的机会,所以我把联系方式告诉了他。过后不久,一位叫东宝的人联系了我。

实际上在这之前,我已经准备离开原来的公司,加入深圳一家大的互联网公司从事前端开发的工作,所以当东宝联系我的时候,并没有很大热情去接触这个新的团队。但东宝是一个很特别的人,从电话中要了我的邮箱之后,他立即给我发了一封超千字的邮件。

在收到邮件之前,我从来没有想到,一个素昧平生的人这样不遗余力地为我介绍他的团队。一个团队有这样的人,已证明了这是一支好的团队,如果能和这样一位充满激情的同事共事,也未尝不是一件好事。

东宝的一段话让我印象深刻。他说,一个人的职业生涯有三个阶段,第一个阶段是把工作当成工作,第二个阶段是把工作当成职业,第三个阶段是把工作当成事业。他希望优秀的同伴加入团队,大家一起把工作当成事业去努力。这句话引起了我的强烈认同,也开始反思自己,在公司三年,逐渐没有了激情和方向,只是为了工作而工作,经常加班,完善系统,开发新功能,却不知道做这些究竟有多大的价值。回想起在学校的团队里,大家为了自己的梦想而努力的情形,我觉得自己应该加入一支有激情、有战斗力的团队,和大家一起并肩战斗。

经过几次交流后,我对这个团队有了进一步了解的兴趣,于是我向东宝提出去北京和他们见面交流一次。

12月底的一天,我从深圳到达北京,这是自2004年之后时隔两年后我再次踏上北京的土地。

由于飞机航班延迟,我比预期的时间晚了两个多小时。当我坐机场大巴匆匆赶到目的地时,东宝、meizz和另一位叫晓萌的同事已经等候我多时了。尽管我来之前已得知航班会延误,一再要求他们先去吃饭,但是大家依然在等我一起共进午餐。

吃饭时,我同东宝、晓萌聊了我想要做的事情。首先,我希望自己能做一些对前端开发圈子有意义的事情。其次,我希望自己能够为互联网公司带出一支专业的前端开发团队,做出真正专著于互联网前端开发的产品,也为提升专业前端工程师的知名度和地位做一些贡献。从当时聊天的情况来看,这个团队给我提供的机会完全能满足我的这两个目标。

经过午餐和下午的沟通,我内心已打定了要加入这支团队的主意。当天晚上我匆匆返回深圳,一路上,我甚至开始勾画未来我在这个团队中要实现的蓝图。四季花与WED的由来“四季花”是我们前端团队的别称,之所以有这样一个别称,是因为我们刚加入的时候,由于公司座位紧张而我们部门人数较少,所以就把我们搬进会议室办公,会议室的名字恰好叫四季花。

2008年初加入公司,我很清楚自己的首要任务是为新成立的部门组建一支专业的前端开发团队。但是团队究竟要什么样子、需要哪些人,说实在的,初来乍到的我心中没底。

在前一家公司,我做过客户服务、系统实施、二次开发、系统开发、前端开发和项目经理,但是我并不了解怎样从无到有组建一支团队,我唯一一次组建团队的经验,是还在学校时组建的俱乐部技术团队。

刚入职时,前端团队只有三个人,其中两个是和我几乎同时入职的新人,团队甚至还没有正式的名字,没有邮件组,没有发展预算。接下来的一两个月,我要把所有的精力都放在团队建设和人员招聘上。

4月,我还成功把aoao同学从广州“骗”到了北京,成为团队的前端架构师。

aoao同学是无忧和蓝色理想的双料版主,前端开发圈子的名人。还在深圳的时候,我们有过接触,他来深圳参加论坛聚会的时候,住在我当时租的房子,我们同食同寝。aoao同学有两个鲜明的特点,第一个特点是想法多,他对产品和技术既有比较深刻的理解,又对业内的资讯很敏感,所以成为团队中以技术视野把握全局的关键角色。第二个特点是他懒,印象最深的一次是,他在我即将离开深圳之前来玩,仍住在我那里,当时我已经把房子退了,搬家公司也在打包东西了,可他还在床上睡,直到整个房间都搬空了,就剩下一张床,也没见他动弹。

4月底,团队人员基本稳定下来,开始了平台的建设工作,团队也有了自己的名字,一是“四季花”,是我们临时办公的会议室名字,二是“WED”,是“Web Engineering&Development”的缩写,后来我们还为这个缩写找了一个新的含义,叫“We Enjoy Days”,因为我觉得团队的文化核心,应该是“Enjoy Working”。

5月初,工作开始忙碌起来,经过四个多月的连续奋战,我们和部门其他团队一起创造了奇迹。随着平台的上线,意味着这支初成立的团队已经通过了第一道考验。年底时,校园招聘又加入了新鲜的血液,给团队注入了新的活力。到今天,这支不满三岁的新生团队,已经从最初的三人发展为二十人左右的专业前端队伍,它正在为新的互联网产品贡献自己的力量。

WED是一支很有活力的团队,每天的工作氛围是轻松愉快的,这既得益于公司的大环境,也得益于WED团队自己独特的文化。

在团队里,大家喜欢相互起外号,组员们叫我小亮亮或者月影姐姐。前面的外号还容易理解,后面的外号可能只有圈子内的人才知道,因为我的QQ性别是女,文字也柔,读起来像女生写的。之前在论坛上也曾经被当作过“美眉”,月影的性别之谜直到我出《JavaScript王者归来》一书之前,一直是网友喜欢八卦的主题。

WED是一支年轻的团队,我们的战斗力也很强。作为国内有实力的专业前端团队,我们对技术质量的要求和项目的把控能力也是一流的。

团队里有不少牛人,有些可能是很多人知道的,比如aoao同学、阿肆同学、rank同学和加宽同学,也有一些是很多人不知道的,这些同学在业界可能默默无名,但他们在自己的技术领域绝对是专家级人物。

有的公司对做前端的技术人员不重视,甚至认为只是写写页面的“美工”,但是在我们团队,前端工程师和后端工程师拥有完全相同的职业发展通道,我们组员在各方面的机会都不会比后端工程师少,他们所要做的只是考虑自己的职业发展规划以及如何提高自身的能力,而我则尽可能想办法创造条件帮助他们达到。

WED团队是一支年轻的团队,到写下这段文字的时候,WED团队才成立不到三年的时间。过去,我们持续关注互联网产品的前端技术和自己的项目相结合,未来除了项目能力的不断提升之外,也会更多地把注意力放在项目之外,希望通过努力为前端开发圈子多做一些事情。我们也期待WED更加开放,期待将来用我们的技术实力和团队活力把前端开发这个圈子变得更好。关于职业发展

职业发展,是一个很重要的问题。当你刚刚离开学校走进社会的时候,应该问问自己,几年以后希望自己成为什么样的人。

记得和圈内朋友交流的时候,不止一次讨论过这种问题:什么是专业的开发工程师?我认为除了必须精通该职业需要的基本技能之外,首要的一点是必须很清楚地知道这个职业要做什么,以及自己想做什么。真正优秀的人,在规划他或她职业发展道路的时候,永远是努力把自己想做的事情和职业目标相匹配,让追求职业的过程变成追求满足与快乐的过程。

我也思考过为什么会成为软件开发者,我的答案是,这项工作让我感到快乐。我也曾经没日没夜地玩过游戏,但是那种经历过后,没有快乐有的只是疲惫和空虚。我曾经连续三十小时设计软件和编写代码,但我从中获得的快乐远比同样时间花费在游戏上的要多,而且软件的完成和发布后可在很长时间内给自己带来巨大的满足感。

我喜欢挑战,喜欢解决问题后的喜悦,所以我觉得自己适合软件工程师这个职业。我喜欢跟团队交流,喜欢和比自己优秀的人一起为了达到目标而奋斗,所以我努力成为一名合格的领导者。在我的职业发展中,我始终努力让兴趣成为我的老师,向前展望未来的时候学会先倾听自己内心深处的声音,知道自己真正要什么,而不要被一时的机会所蒙蔽,不要被听起来很酷的职位所诱惑。aoao同学说,做程序员不可耻,可耻的是不知道为什么做程序员。当然这是一句玩笑话,但是也包含很深刻的道理。

程序员大概都向往“架构师”这样的高级技术职位,对我来说也一样,我也曾经差一点成为一家著名互联网公司的“前端架构师”。但是后来我拒绝了,不是因为机会不好,而是因为如果我过去,意味着我需要从无到有组建一支专业前端团队,也就是要我重新做两年前已经做过的事情,而这显然不是我的职业追求,我不愿意再用两年的时间来换取高薪和更高的职位。

身边有些人,他们对技术的追求和热爱超过我,他们是天生的专家,是值得学习和尊敬的榜样,也有一些人,他们发现自己并不适合软件工程师这个职位,而最终选择了转行,其中不乏成功者。真正碌碌无为的那些人,要么痛苦忍受,要么安于现状,得过且过,这两种人,向环境屈服,被环境改造,失去自己的目标,所以也就远离成功之路。

有的人以适应艰难的环境为荣,但我的观点是,只有让自己快乐的环境才是最有可能成功的环境。人在职场,对外界压力要有足够的韧性,但是对周围环境,不能太逆来顺受,该有的原则一定要有,如果环境不适合自己,则要果断放弃,重新选择,这样对自己才是最好的。

迎接挑战时,一定要问自己的内心是否快乐,只有自己内心快乐了,才能适合自己发展的状态,真正的成功者,在克服别人看来很痛苦的困难时,实际上他或她的内心深处,依然坚守一份快乐。

造就成功的,不是忍受痛苦,而是坚守快乐。关于民间交流会

我始终认为,发展一个圈子,最好的方式是创造环境让每个成员都能彼此充分交流。

2009年底的时候裕波同学告诉我,他准备和圈内朋友一起组织Web标准化交流会。我非常赞成和支持这种把大家组织在一起讨论的交流会,这也是我曾经想做而没有去做的事情。Web标准化交流会最终定为每月的最后一个周末举行,人数控制在30个,每期一个开放主题,尽量让每个人参与发言和讨论。交流会采用网上报名的方式,前几期只在北京组织,后来发展到北京、上海、广州、深圳四个城市。

由于组办者非常用心,每期交流会都很成功,北京的报名人数屡创新高。交流会基本上采用圆桌会议的方式,不邀请或者少邀请主讲人,让每个人先自我介绍,然后参与发言,气氛比较活跃,通过彼此讨论,交换发言,让大家都有收获。

交流会回避非常专业的技术问题点,而是选择大家工作中比较关心的话题来进行讨论,比如有“网站重构中的文件组织”、“css sprites的应用”、“页面重构合理化讨论”、“前端开发”、“在研发流程中与其他岗位协作效率的提升”、“前端开发团队现状调查和未来展望”、“分享你在开发中的经验”、“前端工程师的知识收集与管理”等,因此能引发大家的讨论热情,甚至展开激烈争论。

参加完交流会后,组办者鼓励大家积极写博客,分享心得,这样让交流会的作用更大,也让那些没能参加交流会的同学通过博客分享有所收获。

交流会的形式非常好,首先,它是以民间组织的形式举办的,没有站在任何互联网公司的商业立场上,保证了纯粹的技术交流。其次,它在形式上抛弃了一个人在台上讲PPT,台下人听的传统模式,鼓励每个人直接参与讨论与分享,锻炼了大家的表达能力,提高了大家的积极性。

交流会的主办者,完全是义务组织这个活动,不收取任何费用,因此活动也得到了业内各大公司的支持。

通过参加这个活动,让很多前端开发圈子内的朋友彼此认识,活动本身对国内前端的发展也起到了积极的作用,并且这个作用随着活动影响力的扩大会变得越来越明显。Web标准化交流会正在让国内前端开发环境变得更好。前端开发圈子

2005年,国内前端技术交流的圈子不大,论坛社区主要有CSDN的Web开发版、蓝色理想论坛和无忧脚本。下面主要谈谈无忧脚本。

2005年年初,我开始关注无忧脚本这个论坛。蓝色理想的人气比无忧脚本旺,但是蓝色理想是一个偏设计的论坛,而无忧脚本给人感觉更偏重于程序开发。

一开始时,我主要在论坛里查找资料,偶尔发表一些自己写的小代码和小心得。因为我不太喜欢在论坛上问问题,更多的时候我只把论坛当作一个分享的平台。

2005—2006年,无忧脚本上的一批老用户都非常活跃,比如宝玉、幻宇、海浪、dron等,他们分享的东西也十分精彩。宝玉同学于2004年初发表了一篇精华帖,汇总了他自己的Java Script作品,并且在接下来的两年多时间里陆续添加新作,一直更新到2006年5月。这篇帖子直到现在还有人阅读和回复,堪称论坛最有生命力的精华帖。

海浪同学是JavaScript版的前版主,他创作的JavaScript版音乐播放器是当时国内最好的前端纯JavaScript音乐播放器,带有歌词同步的功能,代表了当时国内JavaScript应用的顶尖水平。

幻宇同学的作品带给人的是惊艳的感觉。2004年,他在网上发布了一款用纯Web实现的星际争霸,虽然只实现了一小部分功能,但是能运行起来。2007年他扩展了一套独立的针对纯Web页面开发游戏的evml语言。后来幻宇同学转向了flash,2007年他逐渐淡出JavaScript开发,而Web前端技术依然不可阻挡地向前发展,直到今天,HTML5的悄然问世也许代表着JavaScript在Web游戏应用领域终将王者归来,幻宇的梦想比现实跑快了整整五年。

2006年夏天,在未见到dron本人前,我怎么也想象不出无忧脚本的超级版主是一个1985年出生的小伙子。他发布了许多优秀的前端作品,还独立开发了一套简单实用而备受欢迎的前端框架Dronfw。dron后来成为了我们的同事,如今已成为孩子父亲的dron,还在为前端开发的理想而努力。2005年以前,前端开发是一个不被人看好的小圈子。为什么前端开发一直以来被技术人员所轻视?我想原因在于前端开发技术的学习门槛比较低。我进入这个圈子之前,也认为写HTML、CSS没有什么技术含量,JavaScript是一种简单的脚本语言,没有什么技术深度可言。然而,随着对前端开发的深入理解,我渐渐改变了这种看法。前端开发随着互联网的发展,正变得越来越复杂,也需要越来越多的专业人才。HTML、CSS、JavaScript这些看似简单的东西,事实上也远没有想象中的简单。围棋的入门规则也简单,因为每颗棋子都一样,所以学起来比象棋更容易,但围棋的技术含量比象棋低么?当然不是。同样,规则简单的HTML、CSS和JavaScript,在复杂的Web环境和丰富的互联网应用中是变化多端的。前端工程师和后端工程师各有擅长的领域,所谓“术业有专攻”,它们彼此的作用是不可替代的,也没有什么高低贵贱之分。JavaScript王者归来

2006年底,aoao同学问我愿不愿意写一本关于JavaScript的书,而我那时正在考虑为前端开发的圈内朋友整理一些关于脚本的学习资料。2006、2007年Ajax开始在国内Web开发界流行起来,Web 2.0也初露头角,各种脚本框架也渐渐为前端开发者们所熟知。前面提到过,我们团队平台采用的DWR就是一种基于Ajax-callback的脚本框架,我设计的Silverna框架在实际开发中也逐渐被同事们接受,因此我想把这些资料整理出来介绍给前端开发者们。2008年6月,清华大学出版社出版了我的第一本著作《JavaScript王者归来》。

把《JavaScript王者归来》定位为初学者入门的读物,既符合我的愿望,也符合出版社的期望。虽然开始时我本打算只重点阐释对常见JavaScript认知和学习方法的误区,但出版社认为当时市场上需要一本比较全面介绍的JavaScript入门教材,因此编辑说服我将这本书定位为一本真正针对JavaScript初学者系统学习的入门教材。

创作一本厚厚的教材,对于我来说,说实话心里没底。可以说在接这个活之前,从来没有想过我有一天要写那么多文字。好在编辑拥有丰富的经验,他一步一步指导我,帮助我最终完成了这部我之前无法想象的700多页的技术书籍。《JavaScript王者归来》的编辑也是你们现在看到的这本书的编辑之一。他是一位经验丰富的编辑,曾经策划了《大话设计模式》等一系列优秀的计算机技术畅销书和《程序员羊皮卷》等受到圈内读者喜爱的IT人文类图书,同时他也是一位非常优秀的作者,创作中的《电脑使用说明书》语言幽默风趣,别具一格。

2008年6月的一天,当我拿到《JavaScript王者归来》的样书时,我的心情是复杂的,一方面为自己两年多的努力有了回报而感到高兴;另一方面心中有些忐忑,因为自己水平有限,书中错误在所难免,有些想法没能很好地表达给读者,感到有些遗憾。

尽管在样章发出时,书中的部分内容已引发争议,但是书问世后在互动网的迅速畅销还是给了我惊喜,大部分读者对这本书还是认可的,更有一部分热心读者耐心地指出了书中的错误,令我非常感动。我唯一能够回报这些读者的方法就是快速及时地整理和发出勘误,同时在新版中采纳一些合理建议。我希望将来如果有机会再创作这类技术图书的时候,争取写出更加优秀的作品来回馈读者对我的帮助。后记

故事到这里结束了,但是生活还要继续下去。

以前有朋友问我,月影,你作为职业程序员、团队领导者,既有兴趣写诗词、小说,还下围棋、研究股票和外汇,并出版了书,你哪里有这么多的时间和精力,又是怎样让自己做到这些的呢?

是的,这些问题有时我自己也会问自己,我究竟是把自己定位于一个怎样的角色。以前我不明白,但是,通过这次写回忆的机会,通过对自己这段经历的认真思考,我明白了一个道理,做好自己想做的事情比什么都重要。相信读者读了前面的故事会发现,其实我也是个普普通通的搞技术出身的开发人员,我做过的事情,你们多半也做过,我遇到过的一些困难,你们多半也遇到过,我想过的一些问题,你们多半也想过,所以,我能做到的,你们也能做到,而我的这些经历,无非是平时一点一滴细小的积累,没有什么特别之处。

如果要我给自己一个职业定位的话,那么我在几个月前拒绝了一直以来梦寐以求的前端架构师职位的时候,我心中其实已经有了答案。毕业时我是一个人,现在,身边多了一个团队,多了一群可爱的同学。我并不在乎我的职位,如果可以,我更愿意呆在这个团队中和大家一起成长,做自己想做的事情,坚持自己的目标,永不放弃。“职业”二字意味着不逃避责任,不背叛理想。业余爱好者可以不面对不想面对的状况,但是职业者必须学会承担。我有很多兴趣爱好,我会在生活中继续保持,但是作为职业程序员和团队领导者,我会持续努力,坚持自己的目标,恪守知行合一的信念,继续前行。

也许将来我还可以和大家分享其他更有趣的故事,但现在,我希望所有热爱前端开发的读者朋友,我们一起努力,把前端开发这个圈子变得更精彩。

周金桥的故事

最近看过不少开发人员或者曾经是开发人员的回顾或总结,感触很深,首先是金山公司的雷军先生在一次会上提出精通一行至少要练习10万小时的说法,不久后又看到一篇老外的文章说要成为高手必须做十年以上开发,最近一段时间又了解了几个做了十年以上开发的朋友的经历,联想到自己将近八年的工作经历,感触很大,心有所悟,所以想要把自己这些年来的工作经历写下来。这些年我虽然取得了一些微不足道的成就,但经历的挫折更多,也许后来人可以从我的经历中吸取一些经验和教训吧。

第一章 高中时代

1995年,我考上了县城教学质量最好的第一中学。一年前,姐姐参加中考,结果以几分之差没有考上县一中,虽然流行“分不够,钱来凑”,但是对于一个有着两个孩子的山区农村家庭来说,凑钱买分太奢侈,所以姐姐再也没能踏进学校的大门。虽然父母把希望寄托在我身上,但小考我有时会考得比较好,有时又考得很糟,所以他们还是没有抱太大希望。当得知我考上的消息时,父母还是很高兴的。

高一时,虽然我已开始接触计算机,但是我从来没有想到它会与我结下不解之缘。1995年秋天Windows 95发售,但不是一般人能买得起的,所以我们当时用的还是Windows 3.x。

当时我们每周一节微机课,由本校一位数学老师任课,在他讲了如何开机和关机之后,我们就没有兴趣听他讲五笔字型了,因为发现了计算机里的游戏。当时软件和游戏我记得不太清楚了,但我记得有一批活跃的软件开发者,比如UCDOS的开发者鲍岳桥(现联众总裁)、国内第一套文字处理软件WPS的作者求伯君(现金山董事长),我很羡慕他们,只是没有想过自己以后也会走上软件开发的路。

本来考上县一中时我的成绩还可以,在年级500多人中我排名第107名,而当时县一中三本以上的升学率超过50%,如果我能在以后的三年中保持差不多的名次,就能在高三毕业时考上一所“211工程”高校。但不幸的是,我遇到了一个刚从师专毕业的老师,他有着极高的工作热情和责任心,只是他教育学生的方式不恰当。那时我在学校寄宿,周日下午洗完衣服之后,我这个刚从农村走进县城的孩子因为好奇去看了一场录像,回去后跟同学讲述了录像的内容,结果被团支部书记反馈到了班主任那里,从此我被班主任打入冷宫。

幸好黄冈地区各高中在高一下学期期末分文理科,我选择了理科,而当时的班主任因为管教班级不力已不再担任班主任。进入高二之后有幸遇到了几个不错的老师,我的成绩有所提高,特别是化学和英语,每次考试的成绩总在120分以上(满分150分),在年级排300多名,在班上排30多名。二

进入高三不久,我在学校图书馆看到有人介绍金明凯编写的高考最佳复习方法的书,据说很多学生通过他的复习方式大幅提高了高考成绩,我从生活费里挤出了一部分费用邮购了一本。

这不是一本讲述高考知识点的书,而是一本讲述高考复习方法的书。作者认为要提高成绩不仅要努力,还要注意方法。比如记忆的科目放在临近高考时复习,逻辑性强的科目提前复习,每天将课外时间分段,并标注应复习的科目。我按照作者的建议结合自身特点制定了一个180天的学习计划,然后严格按照复习计划执行。

复习一段时间后,我感觉确实有效果了,信心也更足了。那时是考前填报志愿,考前黄冈地区统一组织了一次模拟考试,很多学生根据这次模拟考试及上一年的高考分数线填报志愿。那次模拟考试我考得不错,我觉得在实际高考中应该会考得更好,我预估自己可以上一所不是特别有名气的“211工程”高校,所以在填报高考志愿时我第一批第一志愿是湖南大学,第二批第一志愿是湖北大学,第三批第一志愿是湖北师范学院,专业都是第一选择计算机,第二选择科技英语,第三选择化学。为什么选这三个专业呢,因为高一时简单玩过计算机觉得它很有意思,而选择科技英语和化学则是因为我这两门课成绩都不错。

事情的发展最终出乎我的意料。高考前一天晚上自觉心态正常的我居然失眠了,凌晨才睡着,结果影响了第一天的考试,而第一天的不理想导致我的心态发生变化,也影响了后面的考试。最终我的高考成绩是560分,而第二批也就是一般本科的分数线是558分,这就意味着我只能上一般本科了。由于在第一、二、三批高校中我只填写了第一志愿和专业,在刚刚达到分数线的基础上没有我挑选的余地。最终我被江汉石油学院(这个学校自2002年起和荆州其他几所院校合并之后更名为长江大学)的建筑工程专业录取。因为我没有填报这个学校,所以去之前对它一无所知,被录取到这个学校是调剂。尽管高考失利,但是在高考复习中使用的那本书带给了我一生的影响。做好一件事情仅仅凭努力是不够的,还需要讲方法,正所谓“铁棒可以努力磨成针,木棒再努力也只能磨成牙签——方向不对,再努力也没有用”。刚开始学习时,我们还不能总结出规律,只有努力去学习打好基础,然后再尝试用正确的方法去学习。除此之外,遇到庞大的计划,我们应该尝试一步步分解,直到每一步都可以实际操作,然后按照这个计划坚持执行。不仅要埋头做事,还要总结方法,并将远大目标分解成可以执行的细小目标,这些习惯我一直保留到现在,对我现在的工作和学习都很有帮助。

第二章 大学时代的学习

1998年9月8日是我上大学的第二天,这个日子我永远记得。因为这一天我第一次接触到网络,尽管当初是用传输速率很低的Modem拨号上网且每小时十元的费用,但我还是被互联网深深地吸引了。

和很多人带着成功的喜悦到大学报到不同,我当时是相当郁闷的,我一直没能从高考失利的阴影中走出来,本来我想复读,可是母亲以家庭情况为由“逼”我上大学。

在刚上大学的前两个月里,我除了睡觉在寝室外,其他时间都和老乡在一起,和室友之间的关系很疏远。大一上学期开的一门计算机基础课,是整个学期我唯一感兴趣的课。当时学校机房的操作系统是Windows 95,并安装了Office系列软件,所以每次上课我都打开Word练习打字,最后我使用全拼输入法一小时能输入3000多个汉字,在班里算是输入速度最快的。因为经常练习,我知道了一些Windows和Word的快捷键和使用技巧,所以上课时经常有同学向我请教,这使我的虚荣心得到了满足,课后花了很多时间来学习计算机相关的知识。比较讽刺的是,班里学习计算机基础花时间最多、平时成绩最好的我居然在期末考试挂了,原因是我提前完成了考试,于是在Word中重新开了一个窗口写文章,结果软件出现bug,输入的汉字与我原先的作业都变成了方块,最后只好为这个2.5学分的科目交上125元人民币参加补考,这是一次惨痛的画蛇添足的教训。

大一下学期开了一门编程课,教材是谭浩强编写的《C语言程序设计》。我刚开始学习时并不顺利,常常会遇到奇怪的问题:明明照书上敲进去的代码,编译时却提示有很多错误;改正了一个错误,再次编译时编译器提示有更多的错误。有时用两节上机课的时间还不能将书上一段不超过30行的代码,输入到计算机里并编译通过和输出正确结果。当然,若干年后再回想这段经历时只会笑自己,其实书中的代码没有那么多错误,之所以出现那些情况往往不是我单词拼写错误就是少敲了符号。当时我在计算机方面的能力表现一般,期末考试全班同学的C语言成绩都不理想,如果按照卷面分来算两个班的及格人数不超过五个,最后老师只好将卷面成绩的平方根乘以10作为最终考试成绩(如果原来的成绩是100分,采用这种算法之后仍然是100分)。最终,我的C语言成绩是70分。大一下学期期末我们学校安排了一个社会实践,使用C语言编写一个简单的成绩管理系统,我没有珍惜这次上机机会,让计算机系的老乡代编写的。大二时由于我对计算机图形学感兴趣,于是又重新学习C语言,并用C语言做了一个简陋的图形用户界面,尽管这个界面简陋,但是实现起来并不太容易,因为不是使用控件拖出来的,而是在Tubro C下一点一线画出来的,用它能实现简单的画直线、圆及矩形的功能。

整个大一我的心态都没有调整过来,除了计算机,对其他课程都不感兴趣,所以考试成绩都很一般。我记得1999年暑假收到学校邮寄给家里的大一下学期期末考试成绩的情景:一天下午,我们一家人刚吃过午饭,收到了学校的成绩单,爸爸打开一看大都是六七十分,妈妈像发现新大陆一样找到了一个90多分的,仔细一看居然是体育(体育能拿90多分得益于我在高中时的锻炼计划,高中毕业时我可以做40多个引体向上,在大学校运动会上拿了1500米全校第二、10000米全校第二十六的成绩),我能感受到父母的失望。二

大二上半年,中文网站慢慢多了起来,并开始流行制作个人主页。当时的ChinaRen主页大巴吸引了不少人制作个人主页,我也是其中的一个。刚开始时使用Word制作,完成后存成HTML格式,后来发现这种方法对页面的控制极为有限,于是转用HTML,一段时间之后发现HTML也有限,要想实现一些漂亮的效果就不得不使用JavaScript,好在JavaScript不需要服务器支持,因此学习起来也很快。

我把个人主页发给同学和网友看,他们都说做得不错。受到鼓励之后,学习的动力更大了,甚至上课期间我也会拿出网页制作方面的书籍来学习。一次我像往常一样向朋友炫耀我的个人主页,朋友什么都没说,还发给我一个网址,看完他的网站后,我也什么都没说,因为高下立现了——我的个人主页是HTML+JavaScript的,仅仅能实现一些简单的客户端动态效果;而他的个人主页是用ASP做的,向网站中添加新文章时无须重新制作HTML网页并上传到服务器上,只需录入就可,访问者还可以在网站上留言。

从那时起我知道了什么叫CGI(common gateway interface,通用网关接口),什么叫动态网页。我到图书馆查阅了大量有关动态网页编程的书籍,知道了可以使用C、C++、Perl、PHP、ASP等编写动态网页,我还将一本CGI编程的书中的用C++编写的代码输入电脑中,看是否能编译通过——我能做的也就这些,因为那时安装软件都要求重启,而学校的计算机都使用了还原保护措施,重启之后就恢复到上一次的样子,相当于什么也没做,这样就看不到程序最终运行的效果,学习的乐趣也大打折扣。

我们班有个同学负责看管系里的机房,在请他暂时关闭还原功能后我安装了PWS(personal web server,个人Web服务器)和FrontPage,利用FrontPage来制作ASP网页。不过学了没多久我就放弃了,因为已经习惯C语言风格的我实在不习惯类似于VB风格的VBScript。那时我更想做类似于心理测试之类的软件(觉得心理测试之类的软件挺好玩),而以前所学的编程语言不是只能做Web界面就是只能做GUI软件,难度太大,这时我从网上知道了Java语言。

有次去图书城看到一本Visual J++方面的图书(Visual J++是微软推出的扩展的Java语言,语法和Java一致,但是编写的程序受到Windows平台的限制,不能在别的平台上运行,现在微软已不再支持了),是博彦科技出版的。它的介绍很有意思,我就买了下来。这是我买的第一本计算机方面的书籍,在回来的路上我又买了一张Visual J++的光盘,如获至宝的我每天呆在系机房里一边看书一边上机实践。第一个比较系统的上机练习就是编写一个有关时钟的Applet。当时我很想将该网页中运行的Applet转换为可独立运行的应用程序,不过很遗憾,费了很多时间和精力都没有成功。事实上,这种方式成为我以后学习编程的一种标准方式:拿到一个自己不熟悉的示例,首先照别人的代码输入一遍,编译运行看是否和别人有一样的效果,这一步相当于模仿;其次,如果效果一样,则看代码是否有啰嗦或者自己难以理解的地方,对存在问题的地方按照自己的理解加以改进,再看编译运行的结果是不是和别人的一样;最后,增加一些自己期望的功能,比如增加几个其他功能的菜单或者按钮,添加相应的处理代码以达到自己期望的效果。对于一本书中的每段代码如果都经历这三步,我相信理解和掌握起来会相当快。以后我学习新知识点或者新语言时都按照这种方法来做,事实证明效果都很好。三

由于学习Visual J++受挫,所以我的兴趣又发生了转变。听说网络工程师是个吃香的高薪职业,于是我的兴趣转到了网络工程方面。据说通过了CCIE认证的工程师可以拿到10万元的年薪(1999年的时候这几乎是一个天文数字,即使到了2010年的今天,在一些二线城市10万元的年薪仍很诱人),我完全被这个年薪吸引住了,因此不惜一切代价去学习网络相关的知识。

当时我学习网络知识的决心很大,刚进大学时买了一个牛皮纸封面的备课本,原本是准备用来做笔记的,可我对专业课一点也不感兴趣,所以一直没有用上,这次为了学习网络知识就派上用场了。网络配置管理有大量需要记忆的基础知识,为了加强记忆我就抄在备课本上。那段时间,课余时间我都泡在图书馆里,记网络相关的笔记。后来听别人说思科认证考试需要不菲的报名费,而我——一个从大别山区走出来的穷学生确实拿不出那么多钱去报名,最后不得不放弃。这时我特地统计了那个快要用完的、被我用来记笔记的备课本,足有20多万字。这个笔记本我一直当成当年辛苦历程的见证小心保存着,可惜在2009年的一次搬家中不慎丢失了。

由于不能参加思科认证考试,所以对网络的学习热情有所下降,在之后的一年多时间里,只要是网络和编程方面的书,我基本上都看,但是很多看过之后就没有印象了。学校把书分为两种,新书和旧书。新书保存在图书馆二楼新书阅览室,每本书每次只能借阅三天,不能续借;旧书则放在图书馆一楼,每本书每次可以借阅一个月,可以续借。由于经常在图书馆借书,时间长了跟图书管理员熟了,所以都允许我续借新书了。记得有一句话:“当生活向你关闭了通向明媚阳光的门时,不要哭泣,它一定会为你留一扇通向清风明月的窗”。这句话用来形容我当初的大学生活是相当贴切的。在大学里因为我对专业不感兴趣,专业课成绩都不理想,甚至要交钱补考。但是,无意之中的学习做引导我慢慢走上了编程的道路。四

大一的我是迷茫的,大二的我是躁动的,到了大三我才慢慢认清了自己将来的职业之路,从事与计算机相关的工作。

这里说说我在大学里发生的一件事情。大三上学期我接到一家名叫“伽利略咖啡”的电话,要我过去上班。到了那家单位后,经理告诉我他们想对公司网站进行改版,想增加网上订座功能(这在2000年的时候已很前卫了)。我一看,网站上使用了大量的Flash,顿时傻眼了。增加留言和订座功能放在今天比较简单,随便哪个培训学校的学生都能做,可是对当时的我来说却是一件很难的事情。实现留言和订座功能需要使用动态网页技术,需要使用数据库存储,而数据库我以前从没有接触过。第一天下班后我去图书城买了一本SQL Server的书和一张SQL Server的安装盘。书中介绍的是中文界面的SQL Server,而我买的却是英文版的SQL Server,这可苦了我,本来没有接触过还得看英文界面。当时有个物理系的老乡买了新电脑,在我死磨硬泡下他答应让我用一个下午。当时我对数据库一点也不了解,看书也是一头雾水,但是既然有书,就不管看不看得懂,先对着书敲代码好了,只要能得出书上的结果就行。这是我的第一次数据库之旅,非常狼狈。第二天上班时我无意中打开了一个包含工资的Excel文件,在上面我看到了咖啡厅经理一个月的工资是1100元,我知道我在这里的工资不会太多,因此有了放弃的打算(2002年我在天津参加工作时薪水才930元,我才知道2000年1100元的薪水不低了)。最终我还是放弃了这个工作,除了上面说到的薪水问题外,还有我基本不具备开发网站新功能所需要的知识,不可能按照他们的要求开发出一个新网站来。五

2001年的时候,听同学说信息产业部举办网络认证考试,报名费用也比较合理,我认识的人中有不少报考了中级程序员。网络方面的认证考试是新开的,和程序员认证考试一样也分为初、中、高级,中级是网络程序员,高级是网络设计师。尽管当时很多同学建议我报考高级,但为了稳妥起见,我报考了中级。

网络程序员考试是第一届,没有以前的题目可以参考,唯一的办法只有多复习、多做题。当时班上也有一位同学感兴趣,买了几本网络程序员的复习参考书,但不知什么原因他最终没有报名,这几本书后来被我借来天天抱在图书馆啃。经过几个月专心的复习备考,终于顺利地通过了考试。当时不管是程序员认证考试还是网络程序员认证考试都分上午、下午两次考试,考试成绩满分都是75分,要通过考试必须都达到指定的成绩才行。考试那天的情景很有意思,上午考点人山人海,下午就冷冷清清了,而我所在的考场下午只有三个人了。以前那种没有目标的学习反而帮助了我顺利通过了这次考试,我成了第一届网络程序员。六

大四上学期,虽然课程轻松了,但我还要参加多门专业课补考。好在学校没有为难我,每个学分交了50元重修费并参加一些老师的指导课,最终顺利通过。大四也是我们开始找工作的时候,那时已经开始双向选择,有的同学没有参加学校的招聘会而去了外面,我知道自己难以找到与计算机相关的工作,所以通过学校的招聘会,签到了天津大港油田集团下属的一家单位。因为我知道能力有限,所以求职时我没有强调一定要从事计算机方面的工作。尽管我很喜欢计算机行业,但是,与别人相比,我根本没有优势,所以决定先找一份非计算机的工作保障生活,然后利用业余时间学习计算机,能力提高了再去找计算机方面的工作。有个做职业规划的老师曾给我们讲了爱好、职业和事业的关系。爱好是喜欢做但没有能力做好、不足以借此养家糊口的事情;职业是不喜欢做但为了养家糊口不得不做的事情;事业是喜欢做并且有能力做好、且做好后还能养家糊口的事情。对于我来说,计算机是我喜欢做的事情,但是不足以养活我;建筑不是我喜欢做的,但是却可以养活我。因此短期内我只能将计算机作为爱好、把建筑作为职业了。

大四下学期主要是做毕业设计,翻译一篇建筑方面的英文科技文献和完成一栋楼的设计,比如楼层多高、窗户数量及位置、柱子的尺寸等。这些对我来说是枯燥的,但为了毕业证和学位证不得不做。

大学前两年,我都是以一种消极的心态来学习和生活的,直到大三我才找到方向。一次我在图书馆跟一个低年级的学弟说:“我大学四年算是浪费了,希望你好好学习。”旁边一位同学说:“你的大学还浪费了?几乎每天都在图书馆。”我问他怎么这样说,他说因为他也长期在图书馆,那时流行占座,我占的座一直没换,他恰好在我旁边,我听了他的解释笑了。

每个人都希望自己样样精通,但时间和精力是有限的,与其遍地撒网,不如将时间和精力投入一两个点上,这样可以最大限度地发挥效用。而我恰恰犯了这样的错误,大学四年里我从图书馆借阅了500多本关于计算机方面的书,可以算是博览群书了(我有不少同学大学毕业时图书证的使用次数仍是个位数甚至是零),可惜泛而不专,从长远来看这些书对我的职业发展有帮助,但是效果不明显。希腊哲学家亚里士多德一次和弟子在海边玩时,弟子问他如何能够成为一个像他这样有名的哲学家,他没有说话就将弟子的头按进水里,等弟子挣扎出来后问,“刚才在水底下最迫切想得到的是什么”,弟子说是空气。他告诉弟子,如果以刚才那种心境去学习,就可以超越老师了。开始做一件事情时,由于以前对这件事情一无所知或者只是道听途说,内心或多或少会感觉有些神奇,但在真正接触之后这种神秘感就会逐渐消失,甚至可能觉得枯燥。学习编程语言也如此,当听别人说或者看别人做的时候总会觉得很神奇,当自己开始学习时就知道那些神奇的功能是通过键盘一个字符一个字符地输入进去的,神秘感就会消退,时间长了甚至感觉枯燥。要想成为编程高手,就要做好像唐僧取得真经之前有八十一难的考验一样。我的一位张姓朋友是一家公司的常务副总,大学专业也不是计算机,他只是由于个人爱好而去学习计算机。他大学毕业后在一家工厂工作,为了学习C++,他报名去北京学习,周五晚上走,周日晚上回,这样坚持了一段时间终于学有所成。在山西一起吃饭时他总感叹当年的艰辛,也正是由于他的坚持才有了今天的成就。

第三章 初入社会

2002年6月28日,是我在大学的最后一天,那一天在“长亭外、古道边,芳草碧连天”的歌声中与同学们告别,从此天各一方。

2002年7月初去单位报到,这是我第一次坐火车出行,第二次出湖北省(第一次是在2000年去湖南登岳阳楼)。当火车徐徐开出汉口火车站时,我不禁想起了“风萧萧兮易水寒,壮士一去兮不复返”的悲壮诗句,对于距离湖北一千多公里之外的天津我是一无所知,突然心里隐隐有种荆轲刺秦王的悲壮和孤单。

当时武汉到天津只有一趟慢速列车,单程耗时19小时。第一次坐火车,我很兴奋,在火车上和一个小伙子聊了一路。

火车到达天津站时是早上8点,走出火车站后我决定坐的士去就业合同上写的天津大港油田人才交流中心,之所以坐的士是因为我询问了老家在天津大港油田的同学,只要十元。当时我注意到司机听说我要去天津大港油田时露出了异样的表情,不过急于要赶到单位报到的我没有想太多。

的士很快在天津的大街小巷中穿梭,然后驶出了市区,坐在车后排的我瞄了一眼计价器已经是45元了,想起同学说只需十元的话,我想是的士司机故意欺生绕远路,于是我指着路边一个小区跟司机说我不去大港油田了,想先去同学家。付了账下车后,我借买矿泉水的机会向摊主问路,摊主告诉我坐去油田的公交车还需四元车费。

我上了一辆去油田的公交车,越往南走越感到荒凉,然后看到了油田的井架,我想是到了采油区。下车后我一看和家乡一样的小镇,真难想象这是直辖市天津,我当时的第一个念头就是想回家,但是我没有那么做,最后经过打听终于找到了人才交流中心,他们的工作人员联系了单位的人事科。半个小时之后人事科长来了,然后我和他坐一辆老式的吉普车去新单位,那感觉真像知青下乡。

到了之后科长先把我送到单位下属的招待所住下来,一周内陆续住进了七个人,其中包括跟我说从天津站到单位只需十元的同学。再次打听才知道十元钱是指乘坐公交车的费用。二

由于我们都是刚从学校走出来的年轻人,所以很快就有了共同语言。当时天津市区一般地段的房价是每平方米2300元,而我们的工资是每月1170元,扣除三险一金之后就更少了,这个工资水准我们自然不满意(事实上单位很多老同事对我们也不满,因为我们一进单位工资就比他们高),所以几个年轻人决定集体到人事科长那里讨说法,搞“非暴力不合作”运动,尽管如此,工资还是没涨。几天之后,我们被分配到单位的各个部门,“非暴力不合作”运动宣告失败。

除了一人被分配到财务科之外,其他人都分配到了技术科。当时技术科正在准备几份项目的标书,我们过去帮忙处理图纸、计算数据、打字及装订,每天从早晨7点忙到晚上11点。一次在网上和一个同学兼朋友聊天,他和我同年毕业,毕业之后分配到长庆油田,干了一个多月后他就辞了职回到学校帮以前的老师做事,体会过油田环境的他很理解我的不如意,建议我辞职。枯燥的工作早就让我失去了兴趣,

试读结束[说明:试读内容隐藏了图片]

下载完整电子书

若在网站上没有找合适的书籍,可联系网站客服获取,各类电子版图书资料皆有。

客服微信:xzh432

登入/注册
卧槽~你还有脸回来
没有账号? 忘记密码?