精华内容
下载资源
问答
  • 但它同样也有问题,就是对于应聘者来讲相当花费时间,而且并不是花时间(在Stackoverflow上回答问题)就一定能到点子上。 到底什么特征才是既通用,又能够有效地鉴别高低应聘者的特征呢? 这个特征必须不像博客...

    http://mindhacks.cn/2011/11/04/how-to-interview-a-person-for-two-years/

    Joel Spolsky曾经感叹:招聘难,难于上青天(此处笔者稍加演绎:))。他有两个辛辣但不乏洞察力的断言:真正的牛人也许一辈子就投大概4次简历,这些家伙一毕业就被好公司抢走了,并且他们的雇主会给他们不赖的待遇,所以他们也不想挪窝。(刚刚去世的Dennis Ritchie就是这样一个人)而“人才”市场上能找到的大多都不是什么人才。招到这帮人轻则费钱重则把你公司搞挂。

    (当我把这篇文章给邹欣老师review的时候,他说了另外两点:1. 最好的人也许不投简历,就决定去哪里了。所以要在他们做决定前找到他们。2. 比较差的会投很多次简历,找不到工作的时间越多,投的简历越多,给整个pool 带来很多噪音,top10%的简历也许根本不算全部人的top10%。)

    诚然,也许没有哪个行业像IT行业这样,无形资产占据公司的绝大多数资产。拒坊间传言比尔·盖茨就曾经说过类似这样的话:只要允许我带走100个人我可以再造一个微软。这话没搜到原版出处,但是从一个侧面反映了IT公司当中智力资产所占的比例之重。

    所以一个自然的推论就是,招聘也许是一个公司决策当中最最重要的一个环节。Joel Spolsky把他在这方面的观察,体会和洞见集结成了一本小册子《Smart and Gets Things Done》,开篇就挑战“产品是公司成败的关键”这个传统观念,他认为创造最适合工程师生活的环境,留下最优秀的人才才是最先最重要的一步,接下来好的产品是水到渠成的事情。国内iapp4me.com创始人郝培强正是这个理念,所以他在微博上说

    我们是小公司,工资开的不高,也不招太多的人,但是电脑都是iMac27,iMac21,Macbook pro15,基本上比很多大公司都好多了。软件没盗版,刚才photoshop的正版我也收了。中午管饭,公司备伞。哈哈。节日假正常放,从不加班,早晨11点上班,下午6点下班。我是有资格说某些大公司的员工苦逼的。

    事实上,米国找个人尚且难成这样,搞得Joel还费心费力写本书语重心长地劝企业们要善待好工程师,国内找个人更是难上加难,国内高质量问答社区知乎创始人周源就曾经在知乎上分享他呕心沥血的招人历程,看完真是让人慨叹这年头找个靠谱的人多不容易(这条知乎问答还有很多精彩的跟帖):

    其实从 08 年到现在,我一直想这事能不能有点窍门,或者是实用的方法,结论是几乎没有。我用过的大家都用的方法:

    • 在水木上发贴子(有点效果)
    • 在蓝色理想上发贴子(无效)
    • 在技术邮件组里发贴子(无效)
    • 买 51job/智联 最便宜的服务(有点效果)
    • 给所有可以想到的人打电话,请他们推荐(无效)
    • 给所有和你讨论过创业,喝过点小酒的人打电话(无效)
    • 约前同事私下谈(有效)

    我用过的大家可能没有用的方法:

    • 上 twitter,看 XXX 的 follower,一个一个看,看他们的 twitter,博客,Google Reader 分享,想办法搞到邮件,联系,半夜电话骚扰。
    • 上豆瓣,前端后端挑几本重量级的书,去找想看,看过,正在看这本书的人,一个一个看,看他们的活动,博客,Google Reader 分享,想办法搞到邮件,联系,半夜电话骚扰。
    • 找同事,问他们都看什么技术博客,想办法搞到邮件,联系,半夜电话骚扰。

    正是这样的不容易,才有不少公司走内部培养的办法,这里的逻辑是:一上来就招到靠谱的人太难了,但找一块靠谱的璞玉然后雕琢雕琢相对就简单很多。这倒是个办法,但这样做的人难免就陷入了纠结:培养好了,人跑了怎么办。这也不能怪招聘的公司,的确是人之常情。其实解决的办法也很简单,培养的时候进行适当引导,让员工发挥自己的主动学习能力,这样不但人得到更多成长,公司也不会觉得投入太多患得患失。所谓师傅领进门修行在个人。

    但是,这仍然还是没有解决根本的问题,就是招聘真的很困难。应聘者固然觉得自己是在“海投”,大海捞针一般。而招聘者何尝不也是这种大海捞针的感觉。这就好比两个人谈恋爱,都想和对方好上,但是偏偏就聊不到一块去。

    招聘真的很困难。以至于招聘者每年需要绞尽脑汁出新笔试题,以免往年的笔试题早就被人背熟了。出题很费脑子,要出的不太简单也不太难,能够滤掉绝大多数滥竽充数的但又要保证不因题目不公平而滤掉真正有能力的,要考虑审题人的时间成本就只能大多数用选择题,而选择题又是可以猜答案的(极少有人会在选了答案之后还敢在空白的地方写为什么选某答案的原因的)。更悲催的是,有些题目出的连公司的员工们自己都会做错(真的是员工们做错了吗?还是题目本身就出错了?)

    笔试完了之后如果还没有被鄙视就要进入面试环节,姑且不说笔试题的种种弊端,就说面试环节,短短几个小时的面试(大多数公司也许连几个小时的面试时间都没有),既需要全面考察基本知识,又要考察编程素养,还要考察(也许最重要的)性格心态。再然后还有一项根本没法考察但却占据程序员相当一部分工作时间的:debug能力。面试官不但得找准问题,不因对方一题答对而妄下结论,也不因一题打错而就扼杀机会,还要以管窥豹,从一朵花看到整个世界,从面试人的举止言谈,分析问题的方式,甚至写程序的笔迹来观察这个人的性格,做事的方式和心态,简直是要面试官具备心理分析师的水准才行。

    这厢要招人的雇主苦不堪言,那边找工作的人也是一团乱麻。绝大多数应届生直到毕业也不清楚他们想要去的公司到底需要什么样的能力,或者说,他们到底需要具备什么样的能力才能在应聘季节拥有自己的选择权。中国虽然本科教育环境差,但是同样有很多的人在本科希望整点东西出来,他们有一腔的激情和抱负,有强大的动力,但就是不知道自己需要掌握哪些技能才能满足雇主的要求,求告无门,整年整年苦闷的像没头苍蝇一样乱撞(我就收到过很多次这样的来信,他们往往很想学点东西,但又不知道哪些重要哪些不重要,到底该学到什么程度,不知道导致不确定,不确定导致决策瘫痪,干脆嘛也不动,荒废时间)。

    什么叫熟练?什么又叫精通?那么扎实呢?两年的YY经验又意味着什么?能这么简单的量化吗?同样是两年的“实践”有的人能真的学到点东西,有的人也许近似一无所得。那么实习呢?很多人都一定要在简历上弄个实习经验,这个又能说明多少问题呢?大作业呢?得奖呢?有一次我面试一位同学,据简历说编译原理课的大作业得了一等奖,可我一问什么是递归下降,就傻眼了。

    这个现实的结果就是,现在绝大多数应届简历而言,也许最具信息量的部分不是“精通XXX,熟悉YYY,掌握ZZZ”,不是“在UUU实习过”,也不是这个项目那个作业,反倒是越来越被认为不重要的一项:毕业学校毕业学校本不应该是最具信息量的,它之所以最具信息量只是源于一个悲剧的事实:简历上其他条目实在信息量太少了。所以靠谱的面试者往往学会了无视简历上华而不实的内容,只相信面试的时候亲眼所见,扫两眼简历也就罢了,最后还得自己捋起袖子慢慢面。而应聘者也许也知道招聘的也不会细细纠简历上的条目,所以什么词也都敢往上捅,反正先过了HR筛简历这关再说。从经济学角度来讲,应聘者的这种策略是正确的,没有代价(因为目前似乎没有公司会去给已经申请过的人做一个诚信数据库),但至少有可能会带来巨大的收益。应聘成了博彩。而博彩式的应聘给招聘公司带来了巨大的筛选压力。简历成了摆设。

    那么招聘这个关系里面的第三者——学校——所处的位置呢?学校更关心的是毕业率和就业率,这似乎是件好事,有这个为目标,那么老师们似乎应该努力让自己的学生多学点东西。可惜就业的质量似乎不是最重要的指标,此其一。其二老师本身大多数没有丰富的业界经验,根本不知道企业整整需要的人才是什么样的,可能花了精力,但却培养不出雇主真正需要的人。另一方面,老师所起的作用很多时候甚至是一个负面的作用,例如布置大作业表面上看上去是培养学生的能力,我们姑且不说抄袭,假设每个人都做了,那么大作业本身能够衡量多少东西呢?能否衡量代码质量,能否衡量团队协作能力?能否衡量交流能力?考虑到大作业用到的东西往往都是书里面现成的,大作业甚至不能衡量学习能力。而学习能力简直算是这个行业最重要的能力没有之一了

    所以,简而言之,如果把人才培养/招聘这件事情本身类比做一个项目,那么这整个项目迄今为止就是一个巨大的失败。为什么这么说呢:

    • 和需求严重脱节:作为人才需求方的雇主的需求到底是什么?绝大多数应聘者都没搞清。更严重的是,这却一点都不是应聘者的错。因为雇主是stakeholder,是雇主自己的责任得去说清楚需求是什么。结果应聘者实现的不是雇主想要的,雇主想要的应聘者没有实现。
    • 应聘者雇来培训自己的人根本不管事:学生交了学费,就相当于雇老师来培训自己,可培训者根本也不了解(或不关心)他的客户们的需求。这里,学生是需求方,老师则是实现方。弄清需求的职责在后者,可后者也弄不清。
    • 学生自己也弄不清:学生自己既是需求方(需要特定技能),也是实现方。可他们自己也弄不清需求到底是什么。

    以上三点还不是最严重的,最严重的在下面:

    • 明白需求是什么的也不知道怎么实现:怎么去培养现代IT企业真正需要的人才?特别地,实战能力怎么培养?代码素养怎么培养?协作沟通能力怎么培养?学习能力怎么培养?就算这些都知道怎么培养,又怎么给在象牙塔里头,离催命之日还遥遥无期的学生提供足够的动力呢?而学生自己就算知道该学哪些技能,又怎么知道具体怎么着手?什么是最有效率的学习方法?又如何让自己保持学习的热情?

    以上这些问题,就是当下人才培养/招聘的惨淡现状。简而言之,在雇主和学生之间,横梗着一条巨大的鸿沟,两头都很着急,两头都有动力,但就是没有方法,君住长江头妾住长江尾。像微软谷歌这样的,干脆和高校合作,直接插手本科或硕士的教育,从而保证到时有足够强的候选,某种程度上,这的确是根本解决之道,可一来这代价太大了,非一般企业承受得起,二来这影响面也太小了。

    这一切,也许将在未来的5年发生根本的变化。

    《Switch: How to Change Things When Change Is Hard》(中译《瞬变》)里面指出,表面上看来非常困难的改变,也许是因为根本就没有抓住要害。在书中作者通过大量案例分析和心理学研究,雄辩地指出以下几点促成改变的关键之处:

    • 触动内心的大象:要改变的人必须要有情感层面的动力。有一些特定的方法能够比另一些方法更能对人的情感产生触动。
    • 给出清晰、明确的目标:目标一定不能含糊,模棱两口的目标让人无所适从,导致决策瘫痪。例如最近我们组在招实习生,我在微博上发了一条招聘信息,其中提到“扎实”的系统底层知识,有同学就写信来问,怎么叫“扎实”。我傻眼了。比尔·盖茨就以目标清晰明确著称,不仅在战略制定上,“每个人桌面上都有一台PC”,而且居然还体现在招聘上——“如果你读完了TAOCP,那么就给我投简历吧”。多么清晰,明确的目标啊——虽然高了点,也许这就是比尔·盖茨至今还没被应聘邮件淹没的原因:)
    • 给前进的道路扫清障碍:人是懒惰的,只要有借口就会不想往前。如果既有明确的目标,同时道路又直直指向目标,一览无余,只等你开始往前走,那么便没有借口,一往无前。

    那么让我们对照上面看看,可以做什么?

    首先,内心的大象不需要触动,中国有足够多的人足够早就开始焦虑就业的事情,只是不知道往哪使劲,这部分人如果把劲头用到正确的事情上面也许足以满足现在的IT企业人才饥渴了。至于其他人,好吧,也许身边的人开始动起来他们也会被触动。

    然后是清晰、明确的目标。这一点上目前雇主们的做法可谓好坏参半,好的一点是大家都强调要有实践经验,要有团队协作精神,坏的一点就在基础知识和技能的要求方面,可谓再含糊不过了:“精通XX语言”,“扎实的XX功底”,“熟悉XX技术”,甚至看上去最具量化感的描述“X年YY经验”其实都根本说明不了多少东西,在信息量方面还不如我家门口菜市场上一家卖酥油饼的店门口挂的横幅——“三天不硬、至少六层!”。

    很多朋友也许注意到一个现象,现在企业对招聘者简历的要求也在变得越来越灵活变通,例如ThoughtWorks在招聘的时候就希望招聘者能给出自己的博客地址,博客对IT行业的意义也许胜过其他所有行业,一个积累多年的技术博客比任何简历都更能说明问题。台湾的郭安定也说“为什么写技术博客对新人如此重要”。可惜这个做法也有一个弊端:并不是所有技术牛人都写博客,有人就是只干不说型的,而就算写博客,乃至动手写过一阵子的,写一个常年的博客,也远比你想象的更为困难,因为很多时候,写(说)得靠谱比做得靠谱更难。所以这个过滤器很多时候用不上。

    但是这的确表明了一个思考的方向,就是寻找更具鉴别力的过滤器,Stackoverflow Careers 2.0之所以强大,是因为Joel Spolsky和Jeff Atwood这两位常年混社区的资深博主创造性地将一个人在社区的活动历史浓缩成为一系列的量化数值,由于这个历史很长期,所以鉴别力非常高。但它同样也有问题,就是对于应聘者来讲相当花费时间,而且并不是花时间(在Stackoverflow上回答问题)就一定能花到点子上。

    到底什么特征才是既通用,又能够有效地鉴别高低应聘者的特征呢?这个特征必须不像博客那样难以实现,同时又必须有足够的区分度

    有的地方在要求填写简历的时候必须填上平时都访问哪些技术网站。恩,很不错的尝试,可区分度仍然还是不够,因为上网站上查东西毕竟只占现阶段大多数应届生的少数信息来源,特别是当我们看重得更多的是应届应聘者的系统性的知识基础的时候,网上的东西虽然丰富,但属于提高班,也更为琐碎,什么是更系统的知识来源呢?答案其实大家都知道——

    书。

    我一向认为,很多时候,是否好好看完一本好书,对一个人的提升往往能达到质的区别。就算不好好看完一本好书,马马虎虎看完,只要书是真的好书,也肯定会有很大的提高。我在面试的时候就经常询问对方看过哪些技术书籍,经常上哪些网站,订哪些博客。这里头尤其数书籍这一项的区分度最高。此外,好书和坏书的差别,从本质上,就是学习效率和大方向的差别。一本烂书可以浪费你半年的时间,但一本好书却可以为你带来真正扎实的基础和开阔的视野。人们常常用“内功”来形容扎实的基础,认为学好了内功以后学什么都快,其实一点没错,好的“内功”书不仅讲清楚深刻的原理,而且指明技术的本质,刻画领域的地图。好的书抓住不变量,让人能够触类旁通。好的书不仅介绍知识,而且阐释原则,介绍那些万变不离其宗的东西。读烂书浪费时间,但读好书却节省时间

    象牙塔内的学生受到视野的限制,往往择书不慎,事倍功半,烂书不仅浪费时间,还会打击人的积极性,让人对知识心生恐惧,认为很难掌握,殊不知只是作者没有讲好(或者没有翻译好)。因此,为招聘头疼的公司完全可以给出“应聘俺们公司前必读的十本书”,也不一定要每个公司都不一样,在某个技术子领域有影响力的人,或者创始人们,可以来定义具有代表性的书单。

    我们姑且把这个计划叫做“书单计划”,容易看到“书单计划”具备以下几个卓越的优点:

    1. 清晰、明确。完全可度量。
    2. 防伪:读没读过,随便一问便知。而正因为应聘者也知道这事不像实习经验可以忽悠,所以也不敢乱往简历上捅词。
    3. 不在乎是否“泄题”:书单完全公开的,无所谓,本来就是要你去读的。想背题?背书吧。真能背下来说明认真看了。
    4. 管你用心不用心读,只要读了,读完了,就有区别。真正的好书,你想不被吸引都难。据我观察很多人就是不知道该去读什么书。
    5. 不存在“怎么做”的障碍:所有人都知道怎么读书——一页一页读。
    6. 不需要招聘者投入精力:书单在此,就这么简单,您看着办。
    7. 评估的负担很大程度转移到了应聘者的身上:是不是认真看完了,有没有心得体会,您自己掂量。没看完别来找我们。

    “书单计划”能很大程度上起到强鉴别器的作用,看了就是看了,必然能学到东西,没看就是没看。知道和不知道,区别是本质的其实很多企业内部培训,根本上其实还不就是叫员工去看之前没看过的书或者资料嘛。最后,除了鉴别作用之外,它还是一个清晰促进的目标,是完全不花精力的培养

    当然,“书单计划”的背后是另一个悲剧的现实,如果不是因为这个现实,这个计划也完全没有必要,那就是,中国IT大学教育当中要求要学的书,和企业真正需要你去读的书相比,不是完全不够用,就是写的不够好,或者更悲剧的就是根本用不上,所以在这个大背景下出来的牛人都是自己淘书自己学的。微软高级开发测试工程师,《Windows用户态程序高效排错》作者熊力就在微博上说过:“我当年毕业的时候总结了一个公式:第一份工作的月薪=大学四年买过的技术书籍价格的总和。”

    但是光有“书单计划”还不够,因为书籍只能管基础知识这一块,一些更难以量化衡量的实战“能力”又怎么办呢?至少目前为止,除了“练”之外好像还没有特别好的办法。可是在象牙塔里面做的项目,或大作业,真的能起到练的作用吗?前面说了,学生会知道自己最终要交差的不是雇主,而是老师,于是就以老师能够评判的标准来默认要求自己了,老师能够评判编码素养?代码风格?文档?设计?协作?甚至连著名的Joel 12条的第一条“是否用源代码管理系统”都没法通过。所以大多数时候,大作业能起到的作用近乎0。

    但是如果这一切是由雇主来评判的,这个“作业”是由雇主来给出的,就完全不一样了。一想到作业是要作为简历的一部分的,能不紧张嘛。能不好好做嘛。能不学到点东西嘛?

    可是这事儿能实现吗?雇主能给学生出大作业吗?也许一两个关系好的高校可以,可是中国那么多学生呢?

    为什么不能呢?如果像书单那样,列出各个技术领域“推荐在学校期间尝试的项目”,至于动不动手做,那是学生自己的问题。做的,自然能够得到锻炼,面试的时候自然能得到更大的优势。

    可问题是,面试的人又怎么来评估呢?这不又回到了没法有效评估的怪圈了吗?答案很简单,但这个答案,直到最近几年,才真正成为现实——

    GitHub

    GitHub诞生于08年春天,第一年便产生了4万6千个公共项目,大约一年半之后用户就已经达到10万用户之巨。而到今年九月份,GitHub已经迎来了百万级用户。Host超过两百万个项目。

    增长的太快了!就像Twitter一样。这样疯了一般的增长只能说明一个事实——人们等待这个产品太久了

    Social Coding

    真实的项目,真实的流程,真实的人名,一切代码review, check-in, test, build, document, 甚至讨论,计划,brianstorming,流程,一切的一切,都是项目历史的一部分,都可以像棋局那样复盘。有经验的面试者只要稍稍扫两眼一个人的GitHub历史,挑出几个check-in历史看一看,便完全能够迅速判断这个人是否满足他的要求。不再需要费劲心机地去想题目,去观察,去揣测,去花费大量的时间的同时还只能采样到几个极为有限的点。

    不像象牙塔里面大作业,这里有源代码管理系统,自动化build,有check-in,有review,有分工,有合作,最重要的是——这是一个集市,一个超出象牙塔的集市,牛人相互吸引,你可以在互联网上找到和自己拥有共同兴趣的一帮人,真正做起一点事情,而不是交差,不需要受限于几十个人的一个小班级。Here Comes Everybody

    为什么我这么有信心?因为这事儿已经发生了。这个想法也完全不是我原创的

    正如很多事情一样,现在在国内发生的事情,往往是美国那头的历史。今年7月中旬,纽约一家公司的工程师老大发了一篇博客文章:Github is Your New Resume。指出一个惊人但再合理不过的事实:越来越多的IT公司在招聘的时候要求应聘者给出GitHub账号。甚至已经有人为GitHub写了根据GitHub上的历史自动生成简历的工具

    仔细想想,这是必然的趋势,没有比这个再合理的事情了,既然StackOverflow的历史能够作为简历,GitHub的历史不本该就是更好的简历吗:你想要具有实战经验,懂check-in懂review懂test和代码质量的重要性,懂交流和沟通的重要性,你本就应该在一个真实的项目当中去锻炼这些东西,而这些在目前已经完全可以办到。正如邹欣老师所说,你的工作就是最好的面试

    这件事情放在早几年,是完全没法做到的,因为我们那时候还没有GitHub。正如没有Twitter,没有微博之前,很多事情都不会成为可能一样,你有千钧之力,缺乏一个合适的支点,也没法撬动一整个社群。无组织中的组织,具有强大的杠杆效应。

    这个事情里面,我唯一提出的东西就是:在目前国内这个现状下,苦闷的招聘者应该主动行动,给出一些建议项目,正如前面提到的书单计划一样,招聘者需要给出的只是引导和清晰明确的目标,剩下的事情,应聘者自然会去完成,这些项目可以是实验项目,也可以是完全能做出点卖钱的东西的项目(如果好好做的话),唯一的不可或缺的前提是,项目不能太小,单人就能完成的项目不理想,一两个月就能完成的项目不理想,最好足够大到能够锻炼到方方面面,偏大一点倒是无所谓的,因为一个尚未完成的项目完全可以作为简历。当然,可以想见的是,真到了那个时候,学生们肯定又是不会满足于仅去做那些已经有许多人做过的项目了所以这里企业们一开始所建议的项目只是一个《Nudge》,是滚雪球之前需要的一点初始动能。后面的事情,他们自己会完成。

    “GitHub计划”同样有一些明显的、甚至不可替代的优点:

    1. 清晰、明确,完全可度量。
    2. 防伪:同样不担心“泄题”。你伪造不了GitHub历史,伪造不了check-in历史,review comments,文档,交流记录…
    3. 它不但是招聘,也是不花精力的培养。善哉善哉。
    4. 评估的责任很大程度上交给了应聘者自己。

    从你的GitHub旅程开始,你就已经一脚踏进了真正的企业,而企业的面试也已经开始。

    书单+GitHub,就相当于一个两年左右的面试。

    没有什么面试比持续两年的面试更具有信息量。

    书单,加上项目,已经基本上覆盖了所需的全部技能。最妙的是,有太多的人在焦急的等待着他们未来的雇主给出明确的信号,他们想投入精力,去学习和实践,去成为企业需要的人,但是他们就是不知道往什么方向走,所谓有动力没方向。所以,雇主给出了清晰明确的要求,相信对于很多人来说反倒是一个解脱:“终于知道该干什么了”。《编程之美》为什么常居畅销榜?因为它透露了雇主眼中的需求,明确、清晰的需求,可以实现,并且知道怎么去实现的需求。

    你提前两年就开始面试和培养未来的候选者,而且还不需要你花出一分精力,而且人家还很乐意,没有比这更完美的面试了。

    想一想,以后那些没见过世面的公司看见你拿出GitHub账号给他看,该是多么惊讶同时又觉得多么合理。

    而这一切,只是因为两个小小的改变:

    1. 由需求方(雇主)给出了清晰、明确的目标。
    2. GitHub这样的平台。

    那么,学校/老师在这个事情当中的位置呢?说实话我不知道。没有哪个行业像IT行业这样特殊:没有什么东西不能够(应该)在互联网上学到的。自组织的力量完全大过传统的教育方式。而且,既然雇主都当了领路人了,我不知道还有中间开发商什么事儿。(注:这里说的是软件开发,并非计算机科学研究,后者另当别论

    那么,这个改变会发生吗?多久会发生呢?当然,它在国外已经发生了,所以问这个问题多少有点无趣。但我还是预计很快就会在国内发生,毕竟,不是已经有人要求出示博客,和经常浏览的网站了吗?也许5年左右(4年本科和6年硕士的中间值?))就会深刻改变整个人才培养/招聘的格局。当然,我并不是预言家,所以不要把我的时间估计当真,我能肯定的是,这种方式是必然的大势所趋。

    刚才我就收到一位同学邀请我上知乎回答一个问题“找工作的首要原则是什么?”,当然,这个问题的答案是:“弄清雇主的需求到底是什么”。


    列一下我所认为的,你面试微软前必须要读的十本书:

    1. Code: The Hidden Language of Computer Hardware and Software (《编码的奥秘》)
    2. Computer System: A Programmer’s Perspective (《深入理解计算机系统》) / Windows via C/C++ (《Windows核心编程》 / 《程序员的自我修养》
    3. Code Complete 2(《代码大全》)/ The Pragmatic Programmer (《程序员修炼之道》,我也把这本书称为《代码小全》)
    4. Programming Pearls (《编程珠玑》) / Algorithms / Algorithm Design / 《编程之美》
    5. The C Programming Language
    6. The C++ Programming Language / Programming: Principles and Practice Using C++ / Accelerated C++
    7. The Structure and Interpretation of Computer Programs (《计算机程序的构造和解释》)
    8. Clean Code / Implementation Patterns
    9. Design Patterns (《设计模式》) / Agile Software Development, Principles, Patterns, and Practices
    10. Refactoring (《重构》)

    (注:1. 以上同一条目下用“/”隔开的表示任选,当然你也可以都读了,相信我,时间是足够的。2. 读这些书并不意味着逐字逐句从第一页读到最后一页——当然你也可以这么做。怎么是聪明高效的读法,可以参考我之前写的关于如何阅读和查找/鉴别书籍/资料的博文

    注意:以上是我个人认为你面试微软开发职位前必须要读的10本书,它不代表我的雇主的观点。它也只是一个初步的书单,肯定会受到我个人经验和眼界的限制。欢迎大家提意见。

    此外,IT不同子领域的必读书单可能千差万别,所以在发布之前我把这篇文章发给了一些朋友,他们给出了自己的书单(你是不是能看到一些有趣的共同点呢):

    云风(中国游戏编程先行者,前网易游戏部门资深程序员,简悦创始人):

    如果面试,我会挑以下的我自己读过的书,让人选择他也读过的部分,再了解他对这些书的理解。这些书其实本质上就是两类,对所面对的东西(程序语言也好,操作系统也好,底层设施也好)本身的理解程度。以及另一类:对设计思想和原则的理解:

    1. C++编程思想
    2. Effective C++
    3. 深度探索C++对象模型
    4. C++语言的设计和演化
    5. C专家编程
    6. C陷阱与缺陷
    7. C语言接口与实现
    8. Lua程序设计
    9. Linkers and Loaders
    10. COM本质论
    11. Windows核心编程
    12. 深入解析Windows操作系统
    13. 程序员修炼之道
    14. 代码大全
    15. UNIX编程艺术
    16. 设计模式
    17. 代码优化:有效使用内存
    18. 深入理解计算机系统
    19. 深入理解LINUX内核
    20. TCP/IP 详解

    冯大辉(丁香园CTO,贝塔咖啡创始人):

    1. 软件随想录
    2. 黑客与画家
    3. 重来
    4. UNIX编程艺术
    5. 编程人生

    洪强宁(豆瓣技术总监):

    StackOverflow上有一个程序员必读书单帖子,这里仅列出top10,更多参考这里

    1. Code Complete 2
    2. The Mythical Man-Month (《人月神话》)
    3. Code: The Hidden Language of Computer Hardware and Software (《编码的奥秘》)
    4. TAOCP (不解释)
    5. The Pragmatic Programmer (《程序员修炼之道》)
    6. Design Patterns (《设计模式》)
    7. The Structure and Interpretation of Computer Programs (《计算机程序的构造和解释》)
    8. Refactoring (《重构》)
    9. The C Programming Language
    10. Introduction to Algorithms (《算法导论》)

    郑昀(窝窝团研发副总裁):

    1. 工程师入门:
      1. Code Complete 2
      2. 程序员修炼之道
      3. 深入理解计算机系统
    2. 工程师升级:
      1. 设计模式
      2. 重构——改善既有代码的设计
    3. 工程师转型:
      1. 快速软件开发——有效控制与完成进度计划
      2. 人月神话
      3. IT项目管理那些事儿
      4. 软件随想录
      5. 最后期限
      6. 走出软件作坊
      7. 你的灯亮着吗?——发现问题的真正所在

    张峥(微软亚洲研究院副院长):

    1. Algorithms (by Sanjoy Dasgupta, Christos Papadimitriou and Umesh Vazirani)
    2. Data Structure and Algorithms
    3. The C Programming Language
    4. The Design of the UNIX Operating System
    5. Compilers (龙书)
    6. Computer Architecture: A Quantitative Approach
    7. Flow
    8. Outliers (why hard work and luck are both important)

    邹欣(MSRA创新工程中心首席研发经理):

    关于创新的书籍(http://book.douban.com/doulist/1253169/):

    1. The Myths of Innovation
    2. The Innovator’s Dilemma
    3. The Innovator’s Solution
    4. Crossing the Chasm
    5. Inside Intuit
    6. 盛田昭夫
    7. 杰克·韦尔奇自传
    8. 梦断代码
    9. Innovation
    10. 浪潮之巅

    关于“精通”的一篇博客《技能的反面:魔方和模仿》:

    http://www.cnblogs.com/xinz/archive/2011/08/07/2129751.html

    在我教的《现代软件工程》课上,除了教科书,每个学生要看另一本相关的书籍并写读书分析。这个博客有一些同学的读书报告:
    http://www.cnblogs.com/OMG-Team/archive/2011/10/25/2223247.html


    读好书是如此的重要,因为好书往往带领你去到更好的书,更大的世界。


    展开全文
  • 2、对你欣赏,肯花时间给你建议,给你机会。3、不轻易跳槽。跟了好老大,行业平台等其实于我看都是浮云。   c work life balance.   这个倒是看自己的情况了,我除了编程以外运动音乐什么的都很爱好,...

    作者:寒小阳
    时间:2013年9月。
    出处:http://blog.csdn.net/han_xiaoyang/article/details/11683589
    声明:版权所有,转载请注明出处,谢谢。

            

           找工作季来了,互联网大潮也将至。近来陆续有不少师弟师妹校友求分享各种资料和经验,想来手头上确实还有一些资源,也包括当初博主的师兄师姐们以及某些无私的大牛们分享的资料,笔经面经以及感想。于是翻出来看看,倒是也勾起了不少博主当初找工作时候的记忆和感想,于是一并整理整理,发上来吧。前面已经有找工作笔试面试那些事儿(15)---互联网公司面试的零零种种和多家经验找工作笔试面试那些事儿(14)---轻松一下,谈谈面试注意的点谈谈找工作过程中的那些环节、注意点和经验三篇文章了,这里再上一篇长文吧。其实博主打心底里也不大赞赏这类快餐似的知识补充突击准备,也觉得技术这个东西应该踏踏实实,一步步积累,积累的量到了,技术到位了,自然就找到好工作了;但是也理解第一份工作的意义,大家都想要一个好的平台,好的起点,可观一些的收入(博主当年找工作的时候也是这么一种心理)。这里暂且先不议好坏,该分享的还是分享上来吧,大牛们一笑而过就好,其他的同学们若看过文章后感觉能对自己有那么一些些的帮助,那也挺好的。

             某师兄留下过一篇比较诚恳的找工作感想,博主回忆了一下自己的经历,想来很多东西也比较类似。于是在其基础上,增删修改了一部分内容,整理成一篇文章发上来了。

    找工作前: 

            1)多动手解决实际问题。

            实验室的任务也好,自己感兴趣的事情、项目(现在有很多非常不错的开源项目,能参与进去对自己的提高也会很大)也好,多多主动折腾。

             来自别人的知识很容易遗忘,来自自己的知识是最扎实的。 没事上各大高校的OJ刷一下acm题对现场写代码很有帮助。这个听起来很泛,但是感觉性价比还是很高的。也可以读读“如何用两年时间面试一个人”这篇文章和一些相关的延伸(博主在本文后面附上了),看面试官都想要怎样的人。        

            2)确定自己的方向。

            首先要找到自己的核心竞争力,这个竞争力是多元的,有人算法厉害,有人懂设计模式工程能力超NB,有人做页面效果很炫丽……不妨问问自己,最擅长的是哪个,最喜欢做的是哪个。假如能够找到两个方面,你能在周围的人里面都做到前10%,那找到一个同时需要这两方面能力的工作,你的竞争力就是10%*10% = top 1%了(先抛开这两个东西是不是独立的吧呵呵)。可以把自己的特长和兴趣组合到一起的工作,对于我来说就是dream work。        

            3) 写简历。

            简历上的东西多而杂是一把双刃剑。刘未鹏(如何用两年时间面试一个人作者)也说,简历上写兴趣广泛的他都不想要,这不是优点。有些人为了凸显各个方面都有尝试,写了很多方向的内容。这导致了要预期面试官问一些扩展的问题,因此准备简历的时候也要花更大的精力进行整理,补上自己的盲点以防万一被问到。虽然如此,大多厉害点的面试官都能探到我的底,也建议我在某个方向做深做细。扯远了,但这样也有好处,有些地方就喜欢要这样的人,觉得这样的人有潜力,有主动性。所以大家还是分职位去准备简历吧。 

            4) 投简历。

             确定方向以后,就去投。但不要一直海投(在另外一篇文章谈谈找工作过程中的那些环节、注意点和经验也提到了),面试跑来跑去挤公交车地铁的感觉让人真的想投海,还不如省下点时间好好看书或者和同学讨论讨论问题。

            当然,也不能全投特别好的公司,不然前前期积累不够或者一时没有状态,很容易就挂掉。初期可以先投一些公司练练手,预先感受一下面试的感觉,调整出一个比较好的状态。

            不过要额外考虑的是,互联网每年的形势都不一样,去年如此今年不一定就这样。例如某年搜狗和美团突然给力了(指的待遇哈),很多人当时根本就没有考虑要投,叹息不已;而曾一度吵得热得不行的人民搜索,却又弱了。

            5) 可以到各个渠道去找工作信息,不要只是局限于招聘网站。

            例如现在好些技术牛人都会在微博上发招聘信息,感觉自己有希望的话,主动投一下。在牛人身边学习还是会快很多,无论是工作方式、习惯、视野等等,都不是一个普通团队可以企及的。另外,提供一个渠道让别人找到你。平时多干点事情,求职时通过各种媒介主动宣传一下自己。有些论坛也是非常不错的,帝都的话,IT互联网这块,水木和byr论坛还是很不错的。 
      

    找工作时面试前: 

             1) 看书补充基础知识。

             程序员面试宝典什么的过一遍总是好的。如果是C/C++的话,这里再脸皮厚着推荐一下我之前写过的找工作笔试面试那些事儿系列,或者你可以直接看林博士的《高质量C++/C编程指南》。

             2)算法多积累和思考。

            好吧,虽然博主不喜欢,但是这里又要提到那几本快餐式填补算法的书了。是的,《编程之美》《剑指offer》《代码之美》《编程珠玑》还是要好好过一遍的,尤其前两本,要仔细把代码都写一遍。说起来好玩的是,博主和同学当年面试时,发现不会的题有70%以上都在前两本书上有原题或者母题……有一次面试某公司的时候,吃惊地发现,某道当时想破头也没想出来的题,确实在某美上有原题,而自恃完整看过一遍的我居然完全没有印象了。。。

             3 )找些好战友。

            真的,找工作你不是一个人在战斗,事实上,团队努力可以让每一个人都有更好的结果共享消息,交流面经等等废话我就不说了。在求职的过程中,往往两个人的盲点互补一下,效果会比一个人默默看书好;讨论问题很容易得到正确的结果;假如你们一起参加笔试了,他过了,你没过,你霸面也起码能知道点消息。再阴暗点说,笔试也可以相互关照一下吧(好吧,这个求轻喷)。 

            4 )不要轻易松懈。

             用某师兄的话说,前中期他找工作都比较顺利,也感觉各家的面试大概都那样了,所以给自己的压力就减轻了,偶尔还打打游戏什么的。导致后期的面试无论是想算法还是写代码的状态,都不怎么好了。事实上很多好的offer都在后头,想起来还是很可惜,大家不要重蹈覆辙。觉得自己要懈怠下来的时候,要好好想想第一份工作的意义——按自己的能力,可以如此奢侈地不那么努力吗? 
      

    笔试时: 

             没什么好说的了,基本的门槛,不是要求太高的话,通常都能过。不会的也不要放弃,用意志坚持住,越用心做,机会就越大一分。师兄自己就说当时完美的图形学部分一点不会,但是坚持自己推理,硬是答了半份……

             程序题时间充裕的话,最好先打个草稿吧。这样卷面能整洁一些,不然鬼画符一样,即使程序是对的,改卷的工程师也不乐意给满分。
      

    面试时: 

            1)要自信!!

             气场足是成功的开始。自己都不相信自己,在自己这关上就弱掉了,还指望别人欣赏你, 很难是吧。

            2)遇到挫折时心态要放好。

            笔试和面试随机性都挺大的。笔试可以通过团队作战减少不稳定的因素,面试就不一样了,面试官不一样的情况下,很可能两个求职者的命运也截然不同,不管两个人的水平和最后的结果是否相对匹配。当然实力压倒一切,但人总会有一些盲点,我想强调的是,保持一个积极的心态去面试比较重要。 

             3)面完好好做总结。

            这点太太重要了。找工作的时候,有些同学的习惯很好,每去一次面试回来都会写一个总结,过了会写长一些,反之会短一些,但是一定要总结,特别是不会的题目,第一时间搞清楚记下来。

            根据生日攻击的理论,假如总的面试题目有365道,那随机抽23道,就有50%的概率出现重复。不想被再次恶心到的话,就搞明白好了。能面试的算法题目大概来来去去也就这么几道。

             4)代码写好后要有review的习惯。

            释放内存,边界条件,循环退出条件等等。最次也要拿一个case出来,把程序走一遍,走通了再让面试官看。只要活好,没人会嫌你做得慢。 

             5)鼓起勇气霸笔霸面。

             霸笔情况太多了,博主和同学当时都经常收不到通知,反正觉得公司靠谱的就去霸。除了微软这种明文禁止的没去,100%成功率。霸面就比较讲技巧和RP——一是要表示出诚意和和蔼的态度,二是要把自己的亮点展示出来,剩下的就是看RP了。  

             6)随身携带中英文简历。

             有时HR可能会忘了让你带简历,你真不带的话,万一……,在面试官那里,印象会比较吃亏。    

            7)充分准备好英文相关内容,最好能找个有共同需求的同学一起联系。

             博主自恃英语口语还算OK,但第一次自我介绍的时候真的是挫得一塌糊涂,准备过后效果就完全不一样了。全英文面试基本就不能临急抱佛脚了,但最差也要mark几个关键技术的关键字,什么polymorphism啊,object-oriented programming啊,千万要会。 
      

    选择: 

             1)选行业,选公司真的没有一概的定论。

            各取所需,有人就爱技术昼夜编程,有人喜欢安稳的节奏,有人有伟大的事业追求……没有高低之分。只有适合不适合一说。师兄提到,他寻找的准则有三个,可以参考一下: 

            a 可以做我喜欢做的事情。

              假如不认同自己的工作,每天去工作就是完成任务了。那会是很不爽的。当然每份工作都会有脏活累活,看看比例是不是能够接受吧。当然也有人很厉害,总可以从自己无聊的工作中找到有意思的部分,我真希望我能培养出这种能力。

            b 周围有比我厉害的人。

            有了好同事,才能快速进步。再刨深一些就是要跟对老大,我定义好老大有三个条件:1、有眼光和阅历。2、对你欣赏,肯花时间给你建议,给你机会。3、不轻易跳槽。跟了好老大,行业平台等其实于我看都是浮云。       

           c work life balance. 

           这个倒是看自己的情况了,我除了编程以外运动音乐什么的都很爱好,所以目前还是选择了留一点时间,做做自己喜欢的事情,结识新的朋友,参加些有趣的活动等等。毕竟我们找好的工作是为了给自己和家人更好的生活,不要忘了找工作的初衷。当然有人会反驳,安逸的环境成长慢啊,这样的工作没有意义,或者这些事情是要分阶段考虑的等等。但还是要考虑身体和家人。当前的想法是这些,也有可能是我还没遇到让我奋不顾身的事业吧,仅供参考。  

           d 户口神马的,恩,在帝都的话,还是得考虑一下的

          2)公司信息获取。

            这时就是八仙过海了,上论坛问,找在公司里工作的师兄师姐问,或者加招聘群等等都可以。这个时候人脉的作用也体现出来了,平时多给师兄师姐打打下手什么的吧,吃亏就是占便宜。 

          3)纠结的时候,问问自己的第一直觉。

           例如有人问搜狗和百度,我觉得差不多的话就follow自己的第一感觉吧。纠结主要是因为两种原因:1 信息量太少,无法决策; 2 两者之间真的没有什么差别。 把握足够主干信息以后,一些细微的差别,可能就不用太较真了。


    附:怎样花两年时间去面试一个人 by  刘未鹏

    Joel Spolsky曾经感叹:招聘难,难于上青天(此处笔者稍加演绎:))。他有两个辛辣但不乏洞察力的断言:真正的牛人也许一辈子就投大概4次简历,这些家伙一毕业就被好公司抢走了,并且他们的雇主会给他们不赖的待遇,所以他们也不想挪窝。(刚刚去世的Dennis Ritchie就是这样一个人)而“人才”市场上能找到的大多都不是什么人才。招到这帮人轻则费钱重则把你公司搞挂。

    (当我把这篇文章给邹欣老师review的时候,他说了另外两点:1. 最好的人也许不投简历,就决定去哪里了。所以要在他们做决定前找到他们。2. 比较差的会投很多次简历,找不到工作的时间越多,投的简历越多,给整个pool 带来很多噪音,top10%的简历也许根本不算全部人的top10%。)

    诚然,也许没有哪个行业像IT行业这样,无形资产占据公司的绝大多数资产。拒坊间传言比尔·盖茨就曾经说过类似这样的话:只要允许我带走100个人我可以再造一个微软。这话没搜到原版出处,但是从一个侧面反映了IT公司当中智力资产所占的比例之重。

    所以一个自然的推论就是,招聘也许是一个公司决策当中最最重要的一个环节。Joel Spolsky把他在这方面的观察,体会和洞见集结成了一本小册子《Smart and Gets Things Done》,开篇就挑战“产品是公司成败的关键”这个传统观念,他认为创造最适合工程师生活的环境,留下最优秀的人才才是最先最重要的一步,接下来好的产品是水到渠成的事情。国内iapp4me.com创始人郝培强正是这个理念,所以他在微博上说

    我们是小公司,工资开的不高,也不招太多的人,但是电脑都是iMac27,iMac21,Macbook pro15,基本上比很多大公司都好多了。软件没盗版,刚才photoshop的正版我也收了。中午管饭,公司备伞。哈哈。节日假正常放,从不加班,早晨11点上班,下午6点下班。我是有资格说某些大公司的员工苦逼的。

    事实上,米国找个人尚且难成这样,搞得Joel还费心费力写本书语重心长地劝企业们要善待好工程师,国内找个人更是难上加难,国内高质量问答社区知乎创始人周源就曾经在知乎上分享他呕心沥血的招人历程,看完真是让人慨叹这年头找个靠谱的人多不容易(这条知乎问答还有很多精彩的跟帖):

    其实从 08 年到现在,我一直想这事能不能有点窍门,或者是实用的方法,结论是几乎没有。我用过的大家都用的方法:

    • 在水木上发贴子(有点效果)
    • 在蓝色理想上发贴子(无效)
    • 在技术邮件组里发贴子(无效)
    • 买 51job/智联 最便宜的服务(有点效果)
    • 给所有可以想到的人打电话,请他们推荐(无效)
    • 给所有和你讨论过创业,喝过点小酒的人打电话(无效)
    • 约前同事私下谈(有效)

    我用过的大家可能没有用的方法:

    • 上 twitter,看 XXX 的 follower,一个一个看,看他们的 twitter,博客,Google Reader 分享,想办法搞到邮件,联系,半夜电话骚扰。
    • 上豆瓣,前端后端挑几本重量级的书,去找想看,看过,正在看这本书的人,一个一个看,看他们的活动,博客,Google Reader 分享,想办法搞到邮件,联系,半夜电话骚扰。
    • 找同事,问他们都看什么技术博客,想办法搞到邮件,联系,半夜电话骚扰。

    正是这样的不容易,才有不少公司走内部培养的办法,这里的逻辑是:一上来就招到靠谱的人太难了,但找一块靠谱的璞玉然后雕琢雕琢相对就简单很多。这倒是个办法,但这样做的人难免就陷入了纠结:培养好了,人跑了怎么办。这也不能怪招聘的公司,的确是人之常情。其实解决的办法也很简单,培养的时候进行适当引导,让员工发挥自己的主动学习能力,这样不但人得到更多成长,公司也不会觉得投入太多患得患失。所谓师傅领进门修行在个人。

    但是,这仍然还是没有解决根本的问题,就是招聘真的很困难。应聘者固然觉得自己是在“海投”,大海捞针一般。而招聘者何尝不也是这种大海捞针的感觉。这就好比两个人谈恋爱,都想和对方好上,但是偏偏就聊不到一块去。

    招聘真的很困难。以至于招聘者每年需要绞尽脑汁出新笔试题,以免往年的笔试题早就被人背熟了。出题很费脑子,要出的不太简单也不太难,能够滤掉绝大多数滥竽充数的但又要保证不因题目不公平而滤掉真正有能力的,要考虑审题人的时间成本就只能大多数用选择题,而选择题又是可以猜答案的(极少有人会在选了答案之后还敢在空白的地方写为什么选某答案的原因的)。更悲催的是,有些题目出的连公司的员工们自己都会做错(真的是员工们做错了吗?还是题目本身就出错了?)

    笔试完了之后如果还没有被鄙视就要进入面试环节,姑且不说笔试题的种种弊端,就说面试环节,短短几个小时的面试(大多数公司也许连几个小时的面试时间都没有),既需要全面考察基本知识,又要考察编程素养,还要考察(也许最重要的)性格心态。再然后还有一项根本没法考察但却占据程序员相当一部分工作时间的:debug能力。面试官不但得找准问题,不因对方一题答对而妄下结论,也不因一题打错而就扼杀机会,还要以管窥豹,从一朵花看到整个世界,从面试人的举止言谈,分析问题的方式,甚至写程序的笔迹来观察这个人的性格,做事的方式和心态,简直是要面试官具备心理分析师的水准才行。

    这厢要招人的雇主苦不堪言,那边找工作的人也是一团乱麻。绝大多数应届生直到毕业也不清楚他们想要去的公司到底需要什么样的能力,或者说,他们到底需要具备什么样的能力才能在应聘季节拥有自己的选择权。中国虽然本科教育环境差,但是同样有很多的人在本科希望整点东西出来,他们有一腔的激情和抱负,有强大的动力,但就是不知道自己需要掌握哪些技能才能满足雇主的要求,求告无门,整年整年苦闷的像没头苍蝇一样乱撞(我就收到过很多次这样的来信,他们往往很想学点东西,但又不知道哪些重要哪些不重要,到底该学到什么程度,不知道导致不确定,不确定导致决策瘫痪,干脆嘛也不动,荒废时间)。

    什么叫熟练?什么又叫精通?那么扎实呢?两年的YY经验又意味着什么?能这么简单的量化吗?同样是两年的“实践”有的人能真的学到点东西,有的人也许近似一无所得。那么实习呢?很多人都一定要在简历上弄个实习经验,这个又能说明多少问题呢?大作业呢?得奖呢?有一次我面试一位同学,据简历说编译原理课的大作业得了一等奖,可我一问什么是递归下降,就傻眼了。

    这个现实的结果就是,现在绝大多数应届简历而言,也许最具信息量的部分不是“精通XXX,熟悉YYY,掌握ZZZ”,不是“在UUU实习过”,也不是这个项目那个作业,反倒是越来越被认为不重要的一项:毕业学校毕业学校本不应该是最具信息量的,它之所以最具信息量只是源于一个悲剧的事实:简历上其他条目实在信息量太少了。所以靠谱的面试者往往学会了无视简历上华而不实的内容,只相信面试的时候亲眼所见,扫两眼简历也就罢了,最后还得自己捋起袖子慢慢面。而应聘者也许也知道招聘的也不会细细纠简历上的条目,所以什么词也都敢往上捅,反正先过了HR筛简历这关再说。从经济学角度来讲,应聘者的这种策略是正确的,没有代价(因为目前似乎没有公司会去给已经申请过的人做一个诚信数据库),但至少有可能会带来巨大的收益。应聘成了博彩。而博彩式的应聘给招聘公司带来了巨大的筛选压力。简历成了摆设。

    那么招聘这个关系里面的第三者——学校——所处的位置呢?学校更关心的是毕业率和就业率,这似乎是件好事,有这个为目标,那么老师们似乎应该努力让自己的学生多学点东西。可惜就业的质量似乎不是最重要的指标,此其一。其二老师本身大多数没有丰富的业界经验,根本不知道企业整整需要的人才是什么样的,可能花了精力,但却培养不出雇主真正需要的人。另一方面,老师所起的作用很多时候甚至是一个负面的作用,例如布置大作业表面上看上去是培养学生的能力,我们姑且不说抄袭,假设每个人都做了,那么大作业本身能够衡量多少东西呢?能否衡量代码质量,能否衡量团队协作能力?能否衡量交流能力?考虑到大作业用到的东西往往都是书里面现成的,大作业甚至不能衡量学习能力。而学习能力简直算是这个行业最重要的能力没有之一了

    所以,简而言之,如果把人才培养/招聘这件事情本身类比做一个项目,那么这整个项目迄今为止就是一个巨大的失败。为什么这么说呢:

    • 和需求严重脱节:作为人才需求方的雇主的需求到底是什么?绝大多数应聘者都没搞清。更严重的是,这却一点都不是应聘者的错。因为雇主是stakeholder,是雇主自己的责任得去说清楚需求是什么。结果应聘者实现的不是雇主想要的,雇主想要的应聘者没有实现。
    • 应聘者雇来培训自己的人根本不管事:学生交了学费,就相当于雇老师来培训自己,可培训者根本也不了解(或不关心)他的客户们的需求。这里,学生是需求方,老师则是实现方。弄清需求的职责在后者,可后者也弄不清。
    • 学生自己也弄不清:学生自己既是需求方(需要特定技能),也是实现方。可他们自己也弄不清需求到底是什么。

    以上三点还不是最严重的,最严重的在下面:

    • 明白需求是什么的也不知道怎么实现:怎么去培养现代IT企业真正需要的人才?特别地,实战能力怎么培养?代码素养怎么培养?协作沟通能力怎么培养?学习能力怎么培养?就算这些都知道怎么培养,又怎么给在象牙塔里头,离催命之日还遥遥无期的学生提供足够的动力呢?而学生自己就算知道该学哪些技能,又怎么知道具体怎么着手?什么是最有效率的学习方法?又如何让自己保持学习的热情?

    以上这些问题,就是当下人才培养/招聘的惨淡现状。简而言之,在雇主和学生之间,横梗着一条巨大的鸿沟,两头都很着急,两头都有动力,但就是没有方法,君住长江头妾住长江尾。像微软谷歌这样的,干脆和高校合作,直接插手本科或硕士的教育,从而保证到时有足够强的候选,某种程度上,这的确是根本解决之道,可一来这代价太大了,非一般企业承受得起,二来这影响面也太小了。

    这一切,也许将在未来的5年发生根本的变化。

    《Switch: How to Change Things When Change Is Hard》(中译《瞬变》)里面指出,表面上看来非常困难的改变,也许是因为根本就没有抓住要害。在书中作者通过大量案例分析和心理学研究,雄辩地指出以下几点促成改变的关键之处:

    • 触动内心的大象:要改变的人必须要有情感层面的动力。有一些特定的方法能够比另一些方法更能对人的情感产生触动。
    • 给出清晰、明确的目标:目标一定不能含糊,模棱两口的目标让人无所适从,导致决策瘫痪。例如最近我们组在招实习生,我在微博上发了一条招聘信息,其中提到“扎实”的系统底层知识,有同学就写信来问,怎么叫“扎实”。我傻眼了。比尔·盖茨就以目标清晰明确著称,不仅在战略制定上,“每个人桌面上都有一台PC”,而且居然还体现在招聘上——“如果你读完了TAOCP,那么就给我投简历吧”。多么清晰,明确的目标啊——虽然高了点,也许这就是比尔·盖茨至今还没被应聘邮件淹没的原因:)
    • 给前进的道路扫清障碍:人是懒惰的,只要有借口就会不想往前。如果既有明确的目标,同时道路又直直指向目标,一览无余,只等你开始往前走,那么便没有借口,一往无前。

    那么让我们对照上面看看,可以做什么?

    首先,内心的大象不需要触动,中国有足够多的人足够早就开始焦虑就业的事情,只是不知道往哪使劲,这部分人如果把劲头用到正确的事情上面也许足以满足现在的IT企业人才饥渴了。至于其他人,好吧,也许身边的人开始动起来他们也会被触动。

    然后是清晰、明确的目标。这一点上目前雇主们的做法可谓好坏参半,好的一点是大家都强调要有实践经验,要有团队协作精神,坏的一点就在基础知识和技能的要求方面,可谓再含糊不过了:“精通XX语言”,“扎实的XX功底”,“熟悉XX技术”,甚至看上去最具量化感的描述“X年YY经验”其实都根本说明不了多少东西,在信息量方面还不如我家门口菜市场上一家卖酥油饼的店门口挂的横幅——“三天不硬、至少六层!”。

    很多朋友也许注意到一个现象,现在企业对招聘者简历的要求也在变得越来越灵活变通,例如ThoughtWorks在招聘的时候就希望招聘者能给出自己的博客地址,博客对IT行业的意义也许胜过其他所有行业,一个积累多年的技术博客比任何简历都更能说明问题。台湾的郭安定也说“为什么写技术博客对新人如此重要”。可惜这个做法也有一个弊端:并不是所有技术牛人都写博客,有人就是只干不说型的,而就算写博客,乃至动手写过一阵子的,写一个常年的博客,也远比你想象的更为困难,因为很多时候,写(说)得靠谱比做得靠谱更难。所以这个过滤器很多时候用不上。

    但是这的确表明了一个思考的方向,就是寻找更具鉴别力的过滤器,Stackoverflow Careers 2.0之所以强大,是因为Joel Spolsky和Jeff Atwood这两位常年混社区的资深博主创造性地将一个人在社区的活动历史浓缩成为一系列的量化数值,由于这个历史很长期,所以鉴别力非常高。但它同样也有问题,就是对于应聘者来讲相当花费时间,而且并不是花时间(在Stackoverflow上回答问题)就一定能花到点子上。

    到底什么特征才是既通用,又能够有效地鉴别高低应聘者的特征呢?这个特征必须不像博客那样难以实现,同时又必须有足够的区分度

    有的地方在要求填写简历的时候必须填上平时都访问哪些技术网站。恩,很不错的尝试,可区分度仍然还是不够,因为上网站上查东西毕竟只占现阶段大多数应届生的少数信息来源,特别是当我们看重得更多的是应届应聘者的系统性的知识基础的时候,网上的东西虽然丰富,但属于提高班,也更为琐碎,什么是更系统的知识来源呢?答案其实大家都知道——

    书。

    我一向认为,很多时候,是否好好看完一本好书,对一个人的提升往往能达到质的区别。就算不好好看完一本好书,马马虎虎看完,只要书是真的好书,也肯定会有很大的提高。我在面试的时候就经常询问对方看过哪些技术书籍,经常上哪些网站,订哪些博客。这里头尤其数书籍这一项的区分度最高。此外,好书和坏书的差别,从本质上,就是学习效率和大方向的差别。一本烂书可以浪费你半年的时间,但一本好书却可以为你带来真正扎实的基础和开阔的视野。人们常常用“内功”来形容扎实的基础,认为学好了内功以后学什么都快,其实一点没错,好的“内功”书不仅讲清楚深刻的原理,而且指明技术的本质,刻画领域的地图。好的书抓住不变量,让人能够触类旁通。好的书不仅介绍知识,而且阐释原则,介绍那些万变不离其宗的东西。读烂书浪费时间,但读好书却节省时间

    象牙塔内的学生受到视野的限制,往往择书不慎,事倍功半,烂书不仅浪费时间,还会打击人的积极性,让人对知识心生恐惧,认为很难掌握,殊不知只是作者没有讲好(或者没有翻译好)。因此,为招聘头疼的公司完全可以给出“应聘俺们公司前必读的十本书”,也不一定要每个公司都不一样,在某个技术子领域有影响力的人,或者创始人们,可以来定义具有代表性的书单。

    我们姑且把这个计划叫做“书单计划”,容易看到“书单计划”具备以下几个卓越的优点:

    1. 清晰、明确。完全可度量。
    2. 防伪:读没读过,随便一问便知。而正因为应聘者也知道这事不像实习经验可以忽悠,所以也不敢乱往简历上捅词。
    3. 不在乎是否“泄题”:书单完全公开的,无所谓,本来就是要你去读的。想背题?背书吧。真能背下来说明认真看了。
    4. 管你用心不用心读,只要读了,读完了,就有区别。真正的好书,你想不被吸引都难。据我观察很多人就是不知道该去读什么书。
    5. 不存在“怎么做”的障碍:所有人都知道怎么读书——一页一页读。
    6. 不需要招聘者投入精力:书单在此,就这么简单,您看着办。
    7. 评估的负担很大程度转移到了应聘者的身上:是不是认真看完了,有没有心得体会,您自己掂量。没看完别来找我们。

    “书单计划”能很大程度上起到强鉴别器的作用,看了就是看了,必然能学到东西,没看就是没看。知道和不知道,区别是本质的其实很多企业内部培训,根本上其实还不就是叫员工去看之前没看过的书或者资料嘛。最后,除了鉴别作用之外,它还是一个清晰促进的目标,是完全不花精力的培养

    当然,“书单计划”的背后是另一个悲剧的现实,如果不是因为这个现实,这个计划也完全没有必要,那就是,中国IT大学教育当中要求要学的书,和企业真正需要你去读的书相比,不是完全不够用,就是写的不够好,或者更悲剧的就是根本用不上,所以在这个大背景下出来的牛人都是自己淘书自己学的。微软高级开发测试工程师,《Windows用户态程序高效排错》作者熊力就在微博上说过:“我当年毕业的时候总结了一个公式:第一份工作的月薪=大学四年买过的技术书籍价格的总和。”

    但是光有“书单计划”还不够,因为书籍只能管基础知识这一块,一些更难以量化衡量的实战“能力”又怎么办呢?至少目前为止,除了“练”之外好像还没有特别好的办法。可是在象牙塔里面做的项目,或大作业,真的能起到练的作用吗?前面说了,学生会知道自己最终要交差的不是雇主,而是老师,于是就以老师能够评判的标准来默认要求自己了,老师能够评判编码素养?代码风格?文档?设计?协作?甚至连著名的Joel 12条的第一条“是否用源代码管理系统”都没法通过。所以大多数时候,大作业能起到的作用近乎0。

    但是如果这一切是由雇主来评判的,这个“作业”是由雇主来给出的,就完全不一样了。一想到作业是要作为简历的一部分的,能不紧张嘛。能不好好做嘛。能不学到点东西嘛?

    可是这事儿能实现吗?雇主能给学生出大作业吗?也许一两个关系好的高校可以,可是中国那么多学生呢?

    为什么不能呢?如果像书单那样,列出各个技术领域“推荐在学校期间尝试的项目”,至于动不动手做,那是学生自己的问题。做的,自然能够得到锻炼,面试的时候自然能得到更大的优势。

    可问题是,面试的人又怎么来评估呢?这不又回到了没法有效评估的怪圈了吗?答案很简单,但这个答案,直到最近几年,才真正成为现实——

    GitHub

    GitHub诞生于08年春天,第一年便产生了4万6千个公共项目,大约一年半之后用户就已经达到10万用户之巨。而到今年九月份,GitHub已经迎来了百万级用户。Host超过两百万个项目。

    增长的太快了!就像Twitter一样。这样疯了一般的增长只能说明一个事实——人们等待这个产品太久了

    Social Coding

    真实的项目,真实的流程,真实的人名,一切代码review, check-in, test, build, document, 甚至讨论,计划,brianstorming,流程,一切的一切,都是项目历史的一部分,都可以像棋局那样复盘。有经验的面试者只要稍稍扫两眼一个人的GitHub历史,挑出几个check-in历史看一看,便完全能够迅速判断这个人是否满足他的要求。不再需要费劲心机地去想题目,去观察,去揣测,去花费大量的时间的同时还只能采样到几个极为有限的点。

    不像象牙塔里面大作业,这里有源代码管理系统,自动化build,有check-in,有review,有分工,有合作,最重要的是——这是一个集市,一个超出象牙塔的集市,牛人相互吸引,你可以在互联网上找到和自己拥有共同兴趣的一帮人,真正做起一点事情,而不是交差,不需要受限于几十个人的一个小班级。Here Comes Everybody

    为什么我这么有信心?因为这事儿已经发生了。这个想法也完全不是我原创的

    正如很多事情一样,现在在国内发生的事情,往往是美国那头的历史。今年7月中旬,纽约一家公司的工程师老大发了一篇博客文章:Github is Your New Resume。指出一个惊人但再合理不过的事实:越来越多的IT公司在招聘的时候要求应聘者给出GitHub账号。甚至已经有人为GitHub写了根据GitHub上的历史自动生成简历的工具

    仔细想想,这是必然的趋势,没有比这个再合理的事情了,既然StackOverflow的历史能够作为简历,GitHub的历史不本该就是更好的简历吗:你想要具有实战经验,懂check-in懂review懂test和代码质量的重要性,懂交流和沟通的重要性,你本就应该在一个真实的项目当中去锻炼这些东西,而这些在目前已经完全可以办到。正如邹欣老师所说,你的工作就是最好的面试

    这件事情放在早几年,是完全没法做到的,因为我们那时候还没有GitHub。正如没有Twitter,没有微博之前,很多事情都不会成为可能一样,你有千钧之力,缺乏一个合适的支点,也没法撬动一整个社群。无组织中的组织,具有强大的杠杆效应。

    这个事情里面,我唯一提出的东西就是:在目前国内这个现状下,苦闷的招聘者应该主动行动,给出一些建议项目,正如前面提到的书单计划一样,招聘者需要给出的只是引导和清晰明确的目标,剩下的事情,应聘者自然会去完成,这些项目可以是实验项目,也可以是完全能做出点卖钱的东西的项目(如果好好做的话),唯一的不可或缺的前提是,项目不能太小,单人就能完成的项目不理想,一两个月就能完成的项目不理想,最好足够大到能够锻炼到方方面面,偏大一点倒是无所谓的,因为一个尚未完成的项目完全可以作为简历。当然,可以想见的是,真到了那个时候,学生们肯定又是不会满足于仅去做那些已经有许多人做过的项目了所以这里企业们一开始所建议的项目只是一个《Nudge》,是滚雪球之前需要的一点初始动能。后面的事情,他们自己会完成。

    “GitHub计划”同样有一些明显的、甚至不可替代的优点:

    1. 清晰、明确,完全可度量。
    2. 防伪:同样不担心“泄题”。你伪造不了GitHub历史,伪造不了check-in历史,review comments,文档,交流记录…
    3. 它不但是招聘,也是不花精力的培养。善哉善哉。
    4. 评估的责任很大程度上交给了应聘者自己。

    从你的GitHub旅程开始,你就已经一脚踏进了真正的企业,而企业的面试也已经开始。

    书单+GitHub,就相当于一个两年左右的面试。

    没有什么面试比持续两年的面试更具有信息量。

    书单,加上项目,已经基本上覆盖了所需的全部技能。最妙的是,有太多的人在焦急的等待着他们未来的雇主给出明确的信号,他们想投入精力,去学习和实践,去成为企业需要的人,但是他们就是不知道往什么方向走,所谓有动力没方向。所以,雇主给出了清晰明确的要求,相信对于很多人来说反倒是一个解脱:“终于知道该干什么了”。《编程之美》为什么常居畅销榜?因为它透露了雇主眼中的需求,明确、清晰的需求,可以实现,并且知道怎么去实现的需求。

    你提前两年就开始面试和培养未来的候选者,而且还不需要你花出一分精力,而且人家还很乐意,没有比这更完美的面试了。

    想一想,以后那些没见过世面的公司看见你拿出GitHub账号给他看,该是多么惊讶同时又觉得多么合理。

    而这一切,只是因为两个小小的改变:

    1. 由需求方(雇主)给出了清晰、明确的目标。
    2. GitHub这样的平台。

    那么,学校/老师在这个事情当中的位置呢?说实话我不知道。没有哪个行业像IT行业这样特殊:没有什么东西不能够(应该)在互联网上学到的。自组织的力量完全大过传统的教育方式。而且,既然雇主都当了领路人了,我不知道还有中间开发商什么事儿。(注:这里说的是软件开发,并非计算机科学研究,后者另当别论

    那么,这个改变会发生吗?多久会发生呢?当然,它在国外已经发生了,所以问这个问题多少有点无趣。但我还是预计很快就会在国内发生,毕竟,不是已经有人要求出示博客,和经常浏览的网站了吗?也许5年左右(4年本科和6年硕士的中间值?))就会深刻改变整个人才培养/招聘的格局。当然,我并不是预言家,所以不要把我的时间估计当真,我能肯定的是,这种方式是必然的大势所趋。

    刚才我就收到一位同学邀请我上知乎回答一个问题“找工作的首要原则是什么?”,当然,这个问题的答案是:“弄清雇主的需求到底是什么”。


    列一下我所认为的,你面试微软前必须要读的十本书:

    1. Code: The Hidden Language of Computer Hardware and Software (《编码的奥秘》)
    2. Computer System: A Programmer’s Perspective (《深入理解计算机系统》) / Windows via C/C++ (《Windows核心编程》 / 《程序员的自我修养》
    3. Code Complete 2(《代码大全》)/ The Pragmatic Programmer (《程序员修炼之道》,我也把这本书称为《代码小全》)
    4. Programming Pearls (《编程珠玑》) / Algorithms / Algorithm Design / 《编程之美》
    5. The C Programming Language
    6. The C++ Programming Language / Programming: Principles and Practice Using C++ / Accelerated C++
    7. The Structure and Interpretation of Computer Programs (《计算机程序的构造和解释》)
    8. Clean Code / Implementation Patterns
    9. Design Patterns (《设计模式》) / Agile Software Development, Principles, Patterns, and Practices
    10. Refactoring (《重构》)

    (注:1. 以上同一条目下用“/”隔开的表示任选,当然你也可以都读了,相信我,时间是足够的。2. 读这些书并不意味着逐字逐句从第一页读到最后一页——当然你也可以这么做。怎么是聪明高效的读法,可以参考我之前写的关于如何阅读和查找/鉴别书籍/资料的博文

    注意:以上是我个人认为你面试微软开发职位前必须要读的10本书,它不代表我的雇主的观点。它也只是一个初步的书单,肯定会受到我个人经验和眼界的限制。欢迎大家提意见。

    此外,IT不同子领域的必读书单可能千差万别,所以在发布之前我把这篇文章发给了一些朋友,他们给出了自己的书单(你是不是能看到一些有趣的共同点呢):

    云风(中国游戏编程先行者,前网易游戏部门资深程序员,简悦创始人):

    如果面试,我会挑以下的我自己读过的书,让人选择他也读过的部分,再了解他对这些书的理解。这些书其实本质上就是两类,对所面对的东西(程序语言也好,操作系统也好,底层设施也好)本身的理解程度。以及另一类:对设计思想和原则的理解:

    1. C++编程思想
    2. Effective C++
    3. 深度探索C++对象模型
    4. C++语言的设计和演化
    5. C专家编程
    6. C陷阱与缺陷
    7. C语言接口与实现
    8. Lua程序设计
    9. Linkers and Loaders
    10. COM本质论
    11. Windows核心编程
    12. 深入解析Windows操作系统
    13. 程序员修炼之道
    14. 代码大全
    15. UNIX编程艺术
    16. 设计模式
    17. 代码优化:有效使用内存
    18. 深入理解计算机系统
    19. 深入理解LINUX内核
    20. TCP/IP 详解

    冯大辉(丁香园CTO,贝塔咖啡创始人):

    1. 软件随想录
    2. 黑客与画家
    3. 重来
    4. UNIX编程艺术
    5. 编程人生

    洪强宁(豆瓣技术总监):

    StackOverflow上有一个程序员必读书单帖子,这里仅列出top10,更多参考这里

    1. Code Complete 2
    2. The Mythical Man-Month (《人月神话》)
    3. Code: The Hidden Language of Computer Hardware and Software (《编码的奥秘》)
    4. TAOCP (不解释)
    5. The Pragmatic Programmer (《程序员修炼之道》)
    6. Design Patterns (《设计模式》)
    7. The Structure and Interpretation of Computer Programs (《计算机程序的构造和解释》)
    8. Refactoring (《重构》)
    9. The C Programming Language
    10. Introduction to Algorithms (《算法导论》)

    郑昀(窝窝团研发副总裁):

    1. 工程师入门:
      1. Code Complete 2
      2. 程序员修炼之道
      3. 深入理解计算机系统
    2. 工程师升级:
      1. 设计模式
      2. 重构——改善既有代码的设计
    3. 工程师转型:
      1. 快速软件开发——有效控制与完成进度计划
      2. 人月神话
      3. IT项目管理那些事儿
      4. 软件随想录
      5. 最后期限
      6. 走出软件作坊
      7. 你的灯亮着吗?——发现问题的真正所在

    张峥(微软亚洲研究院副院长):

    1. Algorithms (by Sanjoy Dasgupta, Christos Papadimitriou and Umesh Vazirani)
    2. Data Structure and Algorithms
    3. The C Programming Language
    4. The Design of the UNIX Operating System
    5. Compilers (龙书)
    6. Computer Architecture: A Quantitative Approach
    7. Flow
    8. Outliers (why hard work and luck are both important)

    邹欣(MSRA创新工程中心首席研发经理):

    关于创新的书籍(http://book.douban.com/doulist/1253169/):

    1. The Myths of Innovation
    2. The Innovator’s Dilemma
    3. The Innovator’s Solution
    4. Crossing the Chasm
    5. Inside Intuit
    6. 盛田昭夫
    7. 杰克·韦尔奇自传
    8. 梦断代码
    9. Innovation
    10. 浪潮之巅

    关于“精通”的一篇博客《技能的反面:魔方和模仿》:

    http://www.cnblogs.com/xinz/archive/2011/08/07/2129751.html

    在我教的《现代软件工程》课上,除了教科书,每个学生要看另一本相关的书籍并写读书分析。这个博客有一些同学的读书报告: 
    http://www.cnblogs.com/OMG-Team/archive/2011/10/25/2223247.html


    展开全文
  •  1、 分享第一条经验:“学历代表过去、能力代表现在、学习力代表未来。”其实这是一个来自国外教育领域的一个研究结果。相信工作过几年、十几年的朋友对这个道 理有些体会吧。但我相信这一点也很重要:“重要的...
    下文部分转发自:
     1、 分享第一条经验:“学历代表过去、能力代表现在、学习力代表未来。”其实这是一个来自国外教育领域的一个研究结果。相信工作过几年、十几年的朋友对这个道 理有些体会吧。但我相信这一点也很重要:“重要的道理明白太晚将抱憾终生!”所以放在每一条,让刚刚毕业的朋友们早点看到哈!

      2、 一定要确定自己的发展方向,并为此目的制定可行的计划。不要说什么,“我刚毕业,还不知道将来可能做什么?”,“跟着感觉走,先做做看”。因为,这样的观 点会通过你的潜意识去暗示你的行为无所事事、碌碌无为。一直做技术,将来成为专家级人物?向管理方向走,成为职业经理人?先熟悉行业和领域,将来自立门 户?还是先在行业里面混混,过几年转行做点别的?这很重要,它将决定你近几年、十年内“做什么事情才是在做正确的事情!”。

      3、 软件开发团队中,技术不是万能的,但没有技术是万万不能的!在技术型团队中,技术与人品同等重要,当然长相也比较重要哈,尤其在MM比较多的团队中。在软 件项目团队中,技术水平是受人重视和尊重的重要砝码。无论你是做管理、系统分析、设计、编码,还是产品管理、测试、文档、实施、维护,多少你都要有技术基 础。算我孤陋寡闻,我还真没有亲眼看到过一个外行带领一个软件开发团队成功地完成过软件开发项目,哪怕就一个,也没有看到。倒是曾经看到过一个“高学历的 牛人”(非技术型)带一堆人做完过一个项目,项目交付的第二天,项目组成员扔下一句“再也受不了啦!”四分五裂、各奔东西。那个项目的“成功度”大家可想 而知了。

      4、 详细制定自己软件开发专业知识学习计划,并注意及时修正和调整(软件开发技术变化实在太快)。请牢记:“如果一个软件开发人员在1、2年内都没有更新过自 己的知识,那么,其实他已经不再属于这个行业了。”不要告诉自己没有时间。来自时间管理领域的著名的“三八原则”告诫我们:另外的那8小时如何使用将决定 你的人生成败!本人自毕业以来,平均每天实际学习时间超过2小时。

      5、 书籍是人类进步的阶梯,对软件开发人员尤其如此。书籍是学习知识的最有效途径,不要过多地指望在工作中能遇到“世外高人”,并不厌其烦地教你。对于花钱买 书,我个人经验是:千万别买国内那帮人出的书!我买的那些家伙出的书,!00%全部后悔了,无一本例外。更气愤的是,这些书在二手市场的地摊上都很难卖 掉。“拥有书籍并不表示拥有知识;拥有知识并不表示拥有技能;拥有技能并不表示拥有文化;拥有文化并不表示拥有智慧。”只有将书本变成的自己智慧,才算是 真正拥有了它。

      6、 不要仅局限于对某项技术的表面使用上,哪怕你只是偶尔用一、二次。“对任何事物不究就里”是任何行业的工程师所不应该具备的素质。开发Windows应用 程序,看看Windows程序的设计、加载、执行原理,分析一下PE文件格式,试试用SDK开发从头开发一个Windows应用程序;用VC++、 Delphi、Java、.Net开发应用程序,花时间去研究一下MFC、VCL、J2EE、.Net它们框架设计或者源码;除了会用J2EE、 JBoss、Spring、Hibernate等等优秀的开源产品或者框架,抽空看看大师们是如何抽象、分析、设计和实现那些类似问题的通用解决方案的。 试着这样做做,你以后的工作将会少遇到一些让你不明就里、一头雾水的问题,因为,很多东西你“知其然且知其所以然”!

      7、 在一种语言上编程,但别为其束缚了思想。“代码大全”中说:“深入一门语言编程,不要浮于表面”。深入一门语言开发还远远不足,任何编程语言的存在都有其 自身的理由,所以也没有哪门语言是“包治百病”的“灵丹妙药”。编程语言对开发人员解决具体问题的思路和方式的影响与束缚的例子俯拾皆是。我的经验是:用 面对对象工具开发某些关键模块时,为什么不可以借鉴C、C51、汇编的模块化封装方式?用传统的桌面开发工具(目前主要有VC++、Delphi)进行系 统体统结构设计时,为什么不可以参考来自Java社区的IoC、AOP设计思想,甚至借鉴像Spring、Hibernate、JBoss等等优秀的开源 框架?在进行类似于实时通信、数据采集等功能的设计、实现时,为什么不可以引用来自实时系统、嵌入式系统的优秀的体系框架与模式?为什么一切都必须以个 人、团队在当然开发语言上的传统或者经验来解决问题???“他山之石、可以攻玉”。

      8、 养成总结与反思的习惯,并有意识地提炼日常工作成果,形成自己的个人源码库、解决某类问题的通用系统体系结构、甚至进化为框架。众所周知,对软件开发人员 而言,有、无经验的一个显著区别是:无经验者完成任何任务时都从头开始,而有经验者往往通过重组自己的可复用模块、类库来解决问题(其实这个结论不应该被 局限在软件开发领域、可以延伸到很多方面)。这并不是说,所有可复用的东西都必须自己实现,别人成熟的通过测试的成果也可以收集、整理、集成到自己的知识 库中。但是,最好还是自己实现,这样没有知识产权、版权等问题,关键是自己实现后能真正掌握这个知识点,拥有这个技能。

      9、 理论与实践并重,内外双修。工程师的内涵是:以工程师的眼光观察、分析事物和世界。一个合格的软件工程师,是真正理解了软件产品的本质及软件产品研发的思 想精髓的人(个人观点、欢迎探讨)。掌握软件开发语言、应用语言工具解决工作中的具体问题、完成目标任务是软件工程师的主要工作,但从软件工程师这个角度 来看,这只是外在的东西,并非重要的、本质的工作。学习、掌握软件产品开发理论知识、软件开发方法论,并在实践中理解、应用软件产品的分析、设计、实现思 想来解决具体的软件产品研发问题,才是真正的软件工程师的工作。站在成熟理论与可靠方法论的高度思考、分析、解决问题,并在具体实践中验证和修正这些思想 与方式,最终形成自己的理论体系和实用方法论。

      10、心态有多开放,视野就有多开阔。不要抱着自己的技术和成果,等到它们都已经过时变成垃圾了,才拿出来丢人现眼。请及时发布自己的研究成 果:开发的产品、有创意的设计或代码,公布出来让大家交流或者使用,你的成果才有进化和升华的机会。想想自己2000年间开发的那些Windows系统工 具,5、6年之后的今天,还是那个样子,今天流行的好多Windows系统工具都比自己的晚,但进化得很好,且有那么多用户在使用。并且,不要保守自己的 技术和思想,尽可能地与人交流与分享,或者传授给开发团队的成员。“与人交换苹果之后,每个人还是只有一个苹果;但交换思想之后,每个人都拥有两种思 想”,道理大家都懂,但有多少人真正能做到呢?

      11、尽量参加开源项目的开发、或者与朋友共同研制一些自己的产品,千万不要因为没有钱赚而不做。网络早已不再只是“虚拟世界”,网上有很多的 开源项目、合作开发项目、外包项目,这都是涉猎工作以外的知识的绝好机会,并且能够结识更广的人缘。不要因为工作是做ERP,就不去学习和了解嵌入式、实 时、通信、网络等方面的技术,反过来也是一样。如果当他别人拿着合同找你合作,你却这也不会,那也不熟时,你将后悔莫及。

      12、书到用时方恨少,不要将自己的知识面仅仅局限于技术方面。诺贝尔经济学奖得主西蒙教授的研究结果表明: “对于一个有一定基础的人来说,他只要真正肯下功夫,在6个月内就可以掌握任何一门学问。”教育心理学界为感谢西蒙教授的研究成果,故命名为西蒙学习法。 可见,掌握一门陌生的学问远远没有想想的那么高难、深奥。多方吸取、广泛涉猎。极力夯实自己的影响圈、尽量扩大自己的关注圈。财务、经济、税务、管理等等 知识,有空花时间看看,韬光养晦、未雨绸缪。

      13、本文的总结与反思:

      A:不要去做技术上的高手,除非你的目标如此。虽然本文是关于提高软件开发知识的建议,做技术的高手是我一向都不赞同的。你可以提高自己的专业知识,但能胜任工作即止。

      B:提高软件知识和技术只是问题的表面,本质是要提高自己认识问题、分析问题、解决问题的思想高度。软件专业知识的很多方法和原理,可以很容易地延伸、应用到生活的其它方面。

      C:在能胜任工作的基础上,立即去涉猎其它领域的专业知识,丰富自己的知识体系、提高自己的综合素质,尤其是那些目标不在技术方面的朋友。

        (2) 有关做软件还是做硬件的问题。

          这个问题,我也无法给出准确的答复,要看你的兴趣爱好、专业能力,更要看你能够找到哪方面的工作。你的当务之急不是考虑到底以后要做软件还是硬件,而是先让自己“强大”起来,把本专业的知识学好,争取拿出一份有闪光点的
    展开全文
  • 老Java程序员两天做了个消消乐(天天爱消除)

    万次阅读 多人点赞 2021-06-21 09:33:17
    2.实现Card类,用来代表每一个小图形。 3.创建二维数组9行8列 最后 加入积分、游戏结束、重新开始、音效等等就完成了 看到这里的大佬,动动发财的小手 点赞 + 回复 + 收藏,能【 关注 】一波就更好了。 想要代码的 ...

    老Java程序员花两天做了个消消乐(天天爱消除)

    引言:

    一直就想做一个消消乐,这次正好找到了素材,就自己琢磨写了一个,我觉得这个游戏难点就在消除、以及消除后的下落,其他的地方也就还好,这次做完了写个文章大家唠一波。

    效果图

    在这里插入图片描述

    实现思路

    1.绘制窗口、按钮、边框等。
    2.实现Card类,用来代表每一个小图形。
    3.创建下标集合,因图片下标是0-5,所以用随机函数随机出下标,用来代表不同的图形,并依次添加打集合indexs中。
    4.对此集合进行随机排序处理。
    5.创建二维数组9行8列,根据集合的下标和二维数组对应的下标实例化各个卡片,并对应放在二维数组中。
    6.设定卡片交换—当前卡片的上下左右才能交换。
    7.判断横向、纵向是否超过3个相同的,是则消除。
    8.消除后对应的卡片下落。

    代码实现

    创建窗口

    首先创建一个游戏窗体类GameFrame,继承至JFrame,用来显示在屏幕上(window的对象),每个游戏都有一个窗口,设置好窗口标题、尺寸、布局等就可以。

    /*
     * 游戏窗体类
     */
    public class GameFrame extends JFrame {
    	
    	public GameFrame() {
    		setTitle("消消乐");//设置标题
    		setSize(386, 440);//设定尺寸
    		setLayout(new BorderLayout());
    		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//点击关闭按钮是关闭程序
            setLocationRelativeTo(null);   //设置居中
        	setResizable(false); //不允许修改界面大小
    	}
    }
    

    创建面板容器GamePanel继承至JPanel

    package main;
    
    import java.awt.Graphics;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    /*
     * 画布类
     */
    public class GamePanel extends JPanel{
    	GamePanel gamePanel=this;
    	private JFrame mainFrame=null;
    	//构造里面初始化相关参数
    	public GamePanel(JFrame frame){
    		this.setLayout(null);
    		mainFrame = frame;
    		
    		mainFrame.setVisible(true);
    	}
    	
    	@Override
    	public void paint(Graphics g) {
    		
    	}
    }
    

    再创建一个Main类,来启动这个窗口,用来启动。

    public class Main {
    	//主类
    	public static void main(String[] args) {
    		GameFrame frame = new GameFrame();
    		GamePanel panel = new GamePanel(frame);
    		frame.add(panel);
    		frame.setVisible(true);//设定显示
    	}
    }
    

    右键执行这个Main类,窗口建出来了
    在这里插入图片描述

    创建菜单及菜单选项

    创建菜单

    //初始化按钮
    private void  initMenu(){
    	// 创建菜单及菜单选项
    	jmb = new JMenuBar();
    	JMenu jm1 = new JMenu("游戏");
    	jm1.setFont(new Font("黑体", Font.BOLD, 15));// 设置菜单显示的字体
    	JMenu jm2 = new JMenu("帮助");
    	jm2.setFont(new Font("黑体", Font.BOLD, 15));// 设置菜单显示的字体
    	
    	JMenuItem jmi1 = new JMenuItem("开始新游戏");
    	JMenuItem jmi2 = new JMenuItem("退出");
    	jmi1.setFont(new Font("黑体", Font.BOLD, 15));
    	jmi2.setFont(new Font("黑体", Font.BOLD, 15));
    	
    	JMenuItem jmi3 = new JMenuItem("操作说明");
    	jmi3.setFont(new Font("黑体", Font.BOLD, 15));
    	JMenuItem jmi4 = new JMenuItem("胜利条件");
    	jmi4.setFont(new Font("黑体", Font.BOLD, 15));
    	
    	jm1.add(jmi1);
    	jm1.add(jmi2);
    	
    	jm2.add(jmi3);
    	jm2.add(jmi4);
    	
    	jmb.add(jm1);
    	jmb.add(jm2);
    	mainFrame.setJMenuBar(jmb);// 菜单Bar放到JFrame上
    	
    	jmi1.addActionListener(this);
    	jmi1.setActionCommand("Restart");
    	jmi2.addActionListener(this);
    	jmi2.setActionCommand("Exit");
    	
    	jmi3.addActionListener(this);
    	jmi3.setActionCommand("help");
    	jmi4.addActionListener(this);
    	jmi4.setActionCommand("win");
    }
    

    实现ActionListener并重写方法actionPerformed
    在这里插入图片描述
    actionPerformed方法的实现

    @Override
    public void actionPerformed(ActionEvent e) {
    	String command = e.getActionCommand();
    	UIManager.put("OptionPane.buttonFont", new FontUIResource(new Font("宋体", Font.ITALIC, 18)));
    	UIManager.put("OptionPane.messageFont", new FontUIResource(new Font("宋体", Font.ITALIC, 18)));
    	if ("Exit".equals(command)) {
    		Object[] options = { "确定", "取消" };
    		int response = JOptionPane.showOptionDialog(this, "您确认要退出吗", "",
    				JOptionPane.YES_OPTION, JOptionPane.QUESTION_MESSAGE, null,
    				options, options[0]);
    		if (response == 0) {
    			System.exit(0);
    		} 
    	}else if("Restart".equals(command)){
    		if(!"end".equals(gamePanel.gameFlag)){
    			JOptionPane.showMessageDialog(null, "正在游戏中无法重新开始!",
    					"提示!", JOptionPane.INFORMATION_MESSAGE); 
    		}else {
    			restart();
    		}
    	}else if("help".equals(command)){
    		JOptionPane.showMessageDialog(null, "鼠标点击选中后,与相邻的切换,超过3个成行或者成列则消除!",
    				"提示!", JOptionPane.INFORMATION_MESSAGE);
    	}else if("win".equals(command)){
    		JOptionPane.showMessageDialog(null, "300秒3000分胜利,否则失败!",
    				"提示!", JOptionPane.INFORMATION_MESSAGE);
    	}
    }
    

    在这里插入图片描述

    初始化图片

    将所有要用到的图片初始化,方便待会使用

    public class ImageValue {
    	//小卡片
        public static List<BufferedImage> itemImageList = new ArrayList<BufferedImage>();
        //路径
        public static String ImagePath = "/images/";
        //将图片初始化
        public static void init(){
        	String path = "";
            //图片初始化
            for(int i=0;i<=5;i++){
                try {
                	path = ImagePath +"tile_"+ i+".png";
                	itemImageList.add(ImageIO.read(ImageValue.class.getResource(path)));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            
        }
    }
    

    初始化下标集合

    1.初始化下标值,随机从6张图片中选取,下标[0-5]。
    2.8列9行,当集合的长度满足72则跳出while循环。
    3.使用 Collections.shuffle 对集合进行随机排序(其实不排序也行,本身也是随机来的)。

    //随机排序
    private void sortImage() {
       Collections.shuffle(indexs);
    }
    //初始化下标值
    private void initIndexs() {
    	Random random = new Random();
    	int n ;
    	while(true){//
    		n = random.nextInt(6);//随机从6张图片下标中选取[0-5]
    		indexs.add(n);
    		if(indexs.size()==72){
    			break;
    		}
    	}
    }
    

    绘制卡片

    drawImage介绍

    此例中,因为图片是合在一起的,需要裁剪
    在这里插入图片描述
    所以要用以下方法:

    g.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer)

    其中img是Image图片对象,而d开头的都是destinetiong,s开头的是source。

    也就是说分别定义好来源和目标的两个矩形的左上角和右下角的点,它会自动帮你剪裁和适应。
    在这里插入图片描述

    
    public class Card {
    	private int x = 0;//对应行
    	private int y = 0;//对应列
    	private int dx = 0;//图形显示左上角x位置
    	private int odx = 0;//图形更新后显示左上角x位置
    	private int dy = 0;//图形显示左上角y位置
    	private int ody = 0;//图形更新后显示左上角y位置
    	private int dir = 1;//方向 
    	private int width =32;//宽
    	private int height = 32;//高
    	private int pIndex = 0;//对应素材图片下标
    	private int index = 0;//对应图片下标值
    	private int type = 1;//1:10张的   2:20张的
    	private BufferedImage image = null;//图片对象
    	private GamePanel panel=null;//GamePanel
    	private boolean alive=true;//是否存活
    	private boolean selected = false;//是否选中
    	private int moveFlag=0;//移动标示  0 不移动 1 横向移动 2纵向移动
    	private int speed=15;//移动速度
    	
    	public Card(int x,int y,int pIndex,GamePanel panel){
    		this.x=x;
    		this.y=y;
    		this.dx = 40+y*(32+3)+10;
    		this.dy = 35+x*(32+3)+10;
    		
    		this.panel=panel;
    		this.pIndex=pIndex;
    		
    		this.image = ImageValue.itemImageList.get(pIndex);
      }
      	//绘制
    	public void draw(Graphics g) {
    		int index = this.index;
    		//index 默认是0,就是从图片中截取第一个
    		int sx1 = index*32;
    		int sy1 = 0;
    		//截取的右下角计算
    		int sx2 = (index+1)*32;
    		int sy2 = 32;
    		
    		g.drawImage(this.image,dx, dy,dx+width,dy+height,sx1,sy1,sx2,sy2 ,null );
    	}
    }
    

    创建一个Card实例,并将它设置给二维数组第一个元素

    //初始化卡片
    private void initCards() {
    	Card card = new Card(0, 0, 0, this);
    	cards[0][0]=card;
    }
    

    paint方法绘制一个边框,并把二维数组的card绘制

    	@Override
    	public void paint(Graphics g) {
    		super.paint(g);
    		//绘制边框
    		BasicStroke bs_2=new BasicStroke(3,BasicStroke.CAP_ROUND,BasicStroke.JOIN_MITER);
    		Graphics2D g_2d=(Graphics2D)g;
    		g_2d.setColor(new Color(0,191,255));
    		g_2d.setStroke(bs_2);
    		g_2d.drawRect(38, 32, 305, 334);
    
    		Card card;
    		for (int i = 0; i <ROWS; i++) {
    			for (int j = 0; j < COLS; j++) {
    				card = cards[i][j];
    				if(card!=null){
    					card.draw(g);
    				}
    			}
    		}
    

    在这里插入图片描述
    在Card类中加入线程,更新index,因为index的变更会更新裁剪位置,此方法要在构造函数中调用。

    private void rock() {
    	new Thread(new Runnable() {
    		@Override
    		public void run() {
    			while (alive) {
    				try {
    					Thread.sleep(200);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				
    				index++;
    				if(index==10){
    					index=0;
    				}
    			}
    		}
    	}).start();
    }
    

    在GamePanel中开启主线程,用来repaint,即可看到动画。

    private class RefreshThread implements Runnable {
    	@Override
    	public void run() {
    		while (true) {
    			if ("start".equals(gameFlag)) {
    				repaint();
    			}
    			
    			try {
    				Thread.sleep(200);
    			} catch (InterruptedException e) {
    			}
    		}
    	}
    }
    

    启动线程

    gameFlag="start";
    //主线程启动
    mainThread = new Thread(new RefreshThread());
    mainThread.start();
    

    在这里插入图片描述
    将卡片补齐,修改initCards方法

    //初始化卡片
    private void initCards() {
    	Card card;
    	int index = 0 ;
    	int temp=0;
    	for (int i = 0; i <ROWS; i++) {
    		for (int j = 0; j < COLS; j++) {
    			temp = Integer.valueOf(String.valueOf(indexs.get(index)));
    			card = new Card(i, j, temp, this);
    			
    			cards[i][j]=card;
    			index++;
    		}
    	}
    }
    

    此时效果:
    在这里插入图片描述

    加入点击事件

    Card类中加入isPoint方法用来判断鼠标点击是否在范围内。

    //判断鼠标是否卡片范围内
    boolean isPoint(int x,int y){
    	//大于左上角,小于右下角的坐标则肯定在范围内
    	if(x>this.dx && y >this.dy
    		&& x<this.dx+this.width && y <this.dy+this.height){
    		return  true;
    	}
    	return false;
    }
    

    GamePanel加入方法判断交换的位置,必须在其上下方、或者左右方才允许交换。(当然如果选择交换的本身是一样的,则同样不允许交换)

    //相邻才能交换
    private int checkTran(Card card) {
    	if(card.getpIndex()==curCard.getpIndex()){//相同的不交换
    		return 4;
    	}
    	
    	int x = curCard.getX();
    	int y = curCard.getY();
    	
    	int x1 = card.getX();
    	int y1 = card.getY();
    	
    	if(y==y1){//在上下
    		if(x1+1==x||x1-1==x){
    			return 2;
    		}
    	}
    	if(x==x1){//在左右
    		if(y1+1==y||y1-1==y){
    			return 1;
    		}
    	}
    	
    	return 0;
    }
    

    事件代码,tran的方法先写个空的,等会来写

    //鼠标事件的创建
    private void createMouseListener() {
    	MouseAdapter mouseAdapter = new MouseAdapter() {
    		
    		@Override
    		public void mouseClicked(MouseEvent e) {
    			if(!"start".equals(gameFlag)) return ;
    			
    			int x = e.getX();
    			int y = e.getY();
    			Card card;
    			for (int i = 0; i <ROWS; i++) {
    				for (int j = 0; j < COLS; j++) {
    					card = cards[i][j];
    					if(card==null)continue;
    					
    					if(card.isPoint(x, y)){
    						MusicPlayer.chooseMisic();
    						if(curCard==null){
    							curCard = card ;
    							card.setSelected(true);
    						}else {
    							int dir= checkTran(card);
    							if(dir!=0&&dir!=4){//相邻才能交换
    								tran(card,dir);
    							}else {//不是相邻则当前取消选择
    								curCard.setSelected(false);
    								card.setSelected(true);
    								curCard = card ;
    							}
    						}
    						return ;//直接跳出
    					}
    				}
    			}
    		}
    	};
    	addMouseMotionListener(mouseAdapter);
    	addMouseListener(mouseAdapter);
    }
    

    tran方法实现

    1.横向交换—交换其Y值
    2.纵向交换—交换其X值
    3.交换在2维数组中的对应位置
    4.两个卡片均执行move方法

    protected void tran(Card card,int dir) {
    	Card tempCard=curCard;
    	curCard.setSelected(false);
    	curCard= null;
    	
    	int x = card.getX();
    	int y = card.getY();
    	int x1 = tempCard.getX();
    	int y1 = tempCard.getY();
    	if(dir==1){//横向交换,对应横向移动
    		card.setY(y1);
    		tempCard.setY(y);
    	}else {//纵向交换,对应纵向移动
    		card.setX(x1);
    		tempCard.setX(x);
    	}
    	//交换在2维数组中的对应位置
    	cards[x][y]= tempCard;
    	cards[x1][y1]= card;
    	
    	card.move(dir);
    	tempCard.move(dir);
    }
    

    实现Card类中的move方法

    1.记录最新后的位置odx、ody;
    2.更odx、ody计算图片运动方向。

    public void move(int d) {
    	this.moveFlag=d;
    	int dis= 0;
    	if(this.moveFlag==1){//横向交换,对应横向移动
    		this.odx=40+y*(32+3)+10;
    		dis = this.odx-this.dx;
    	}else {
    		this.ody=35+x*(32+3)+10;
    		dis = this.ody-this.dy;
    	}
    
    	if(dis>0){//向下运动 、向右运动
    		dir = 1;
    	}else {
    		dir = -1;
    	}
    }
    

    修改draw方法

    1.根据移动方向和速度更新dx、dy,用来达到移动的目的。
    2.当dx>=odx或dx<=odx、dy>=ody或dy<=ody 达到最大移动位置。
    3.达到最大移动位置后,要进行消除逻辑处理,写入空方法clear
    4.加入边框,表示卡片被选择状态。

    //绘制
    public void draw(Graphics g) {
    	int index = this.index;
    
    	if(moveFlag!=0){
    		if(this.moveFlag==1){//横向移动
    			dx += dir*speed;//dx修改
    			if(dir>0){
    				if(dx>=odx){//运动到既定位置,停止
    					dx = odx;
    					moveFlag=0;
    					clear();
    				}
    			}else{//运动到既定位置,停止
    				if(dx<=odx){
    					dx = odx;
    					moveFlag=0;
    					clear();
    				}
    			}
    		}else {//纵向移动
    			dy += dir*speed;
    			if(dir>0){
    				if(dy>=ody){//运动到既定位置,停止
    					dy = ody;
    					moveFlag=0;
    					clear();
    				}
    			}else{
    				if(dy<=ody){//运动到既定位置,停止
    					dy = ody;
    					moveFlag=0;
    					clear();
    				}
    			}
    		}
    	}
    	//index 默认是0,就是从图片中截取第一个
    	int sx1 = index*32;
    	int sy1 = 0;
    	//截取的右下角计算
    	int sx2 = (index+1)*32;
    	int sy2 = 32;
    
    	g.drawImage(this.image,dx, dy,dx+width,dy+height,sx1,sy1,sx2,sy2 ,null );	
    	if(selected){
    		//绘制边框
    		Color oColor = g.getColor(); 
    		g.setColor(Color.pink);
    		g.drawRect(dx, dy, 32, 32);
    		g.setColor(oColor);
    	}
    }
    

    在这里插入图片描述

    消除方法

    X方向消除

    在这里插入图片描述
    以当前为中心,向左向右逐个判断,遇到不同的则返回,遇到相同的则计数器加1,当左边+自己+右边 大于三,则横向需要消除。

    //x方向左边计算
    private int computedLeftX() {
    	int res = 0;
    	Card card;
    	//从当前卡片的前一个位置开始往前计算,遇到与当前卡片不是同一类型就直接返回
    	for (int i = this.y-1; i >=0; i--) {
    		card = panel.cards[this.x][i];
    		if(card==null) continue;
    		if(card.pIndex==this.pIndex){
    			res++;
    		}else {
    			break;
    		}
    	}
    	return res;
    }
    //x方向右边计算
    private int computedRightX() {
    	int res = 0;
    	Card card;
    	//从当前卡片的后一个位置开始往后计算,遇到与当前卡片不是同一类型就直接返回
    	for (int i = this.y+1; i < panel.COLS; i++) {
    		card = panel.cards[this.x][i];
    		if(card==null) continue;
    		if(card.pIndex==this.pIndex){
    			res++;
    		}else {
    			break;
    		}
    	}
    	
    	return res;
    }
    

    执行消除

    让消除行的上方每一个,依次往下落一格
    在这里插入图片描述
    上方如果没有了,则新生成一个卡片。

    //当前卡片上方全部下落一格
    private void down(Card c){
    	Card lastCard;
    	//x的循环,表示往上上一个个的取
    	for (int i = c.x; i >=0; i--) {
    		if(i==0){//新创建
    			createCard(0,c.y);
    			continue;
    		}else{
    			lastCard = panel.cards[i-1][c.y];
    		}
    		if(lastCard==null) {//新创建
    			createCard(i-1,c.y);
    		}
    		//向下移动
    		lastCard.setX(i);
    		panel.cards[i][c.y]= lastCard;
    		lastCard.move(2);
    	}
    }
    

    于是X方向消除代码

    //x方向消除
    private int clearX(int left,int right,int type) {
    	MusicPlayer.disappearMisic();
    	//左边消除
    	Card card ;
    	for (int i = this.y-1; i >= this.y-left ; i--) {
    		card = panel.cards[this.x][i];
    		if(card==null) continue;
    		card.alive=false;
    		panel.cards[this.x][i]=null;
    		down(card);
    	}
    	
    	for (int i = this.y+1; i <= this.y+right ; i++) {
    		card = panel.cards[this.x][i];
    		if(card==null) continue;
    		card.alive=false;
    		panel.cards[this.x][i]=null;
    		down(card);
    	}
    	
    	if(type==1){//自己也消除
    		this.alive=false;
    		panel.cards[this.x][this.y]=null;
    		
    		down(this);
    	}
    	
    	return 0;
    }
    

    在这里插入图片描述

    加入Y方向消除代码

    private void clearY(int uCount, int dCount) {
    	MusicPlayer.disappearMisic();
    	int y = this.y;
    	int count = uCount+1+dCount;
    	
    	int maxX = this.x+dCount;
    	int minX = this.x-uCount;
    	Card card;
    	
    	while(count>0){
    		card = panel.cards[maxX][y];
    		card.alive=false;
    		panel.cards[maxX][y]=null;
    		down(card);
    		count--;
    	}
    }
    

    最后

    加入积分、游戏结束、重新开始、音效等就完成了

    在这里插入图片描述

    看到这里的大佬,动动发财的小手 点赞 + 回复 + 收藏,能【 关注 】一波就更好了。

    想要代码的 加微信私聊 我!

    为了帮助更多小白从零进阶 Java 工程师,从CSDN官方那边搞来了一套 《Java 工程师学习成长知识图谱》,尺寸 870mm x 560mm,展开后有一张办公桌大小,也可以折叠成一本书的尺寸,原件129元现价 29 元先到先得,有兴趣的小伙伴可以了解一下

    在这里插入图片描述

    ★ 更多精彩

    ♥ Java贪吃蛇 ♥

    ♥ Java俄罗斯方块 ♥

    ♥ Java连连看 ♥

    ♥ Java植物大战僵尸 ♥

    ♥ Java坦克大战,回忆童年!♥

    ♥ Java扫雷小游戏,以前上学经常玩 ♥

    展开全文
  • 本文主要讲述鸢尾数据集的各种分析,包括可视化分析、线性回归分析、决策树分析等,通常一个数据集是可以用于多种分析的,希望这篇文章对大家有所帮助,同时提供些思考。内容包括: 1.鸢尾数据集可视化分析 2....
  • C/C++获取时间时间格式转换

    万次阅读 2016-11-21 16:23:11
    介绍基础概念,探讨了在C/C++中对日期和时间操作所用到的数据结构和函数,并对计时、时间的获取、时间的计算和显示格式等方面进行了阐述。本文还通过大量的实例展示了time.h头文件中声明的各种函数和数据结构的详细...
  • 其中的数值又代表什么?简单说百度指数是站长们开始做网站优化之前最先用到的工具,可以说如果没有百度指数,站长们就无法确定要优化哪些关键词。既然百度指数对我们做SEO优化如此重要,那我们又应该如何利用好百度...
  • 考虑到这个读者还是非科班,只了半年的时间,所以我觉得还是挺牛逼的。 一面的时候他曾给我发消息,说面试官问他 Java 虚拟机栈方面的知识点,没回答上来,我就立马写了那篇 Java 虚拟机栈的文章甩给他,没想到,...
  • python时间序列分析

    万次阅读 多人点赞 2018-03-05 22:45:49
    本文转载自博客园大神“大熊猫淘沙”的一篇文章——python时间序列分析。 文章写的生动有趣干货满满,特此收藏转载一下。原文地址:https://www.cnblogs.com/foley/p/5582358.html 1. 什么是时间序列 1.1 环境...
  • Aegisub时间码格式详解

    千次阅读 2018-02-20 22:05:10
    注意:以下内容基于帧率为24FPS的视频讲解。 Aegisub时间码 ...其中“开始/结束时间”是0:00:00.00的形式,小数点后有两位,代表的是多少毫秒,比如0:00:06.81就是6秒+810毫秒。 而本文中的另一...
  • Linux时间参数与find命令

    万次阅读 2016-05-18 23:27:03
    那么这三个时间参数又代表着什么样的意义呢?怎么可以看得到它们?下面就来介绍一下。 首先我们可以用一条命令来得到一个文件的某些参数: 我们对当前文件夹下的一个clean文件执行了stat命令,用来查看这个文件的...
  •  上周,和某一线媒体华南区营销策划主管及某国驻华大使秘书吃饭聊天,谈及时间管理,触及到一个绝大多数人都存在的一个错误时间关键--如何安排事情的优先顺序。  柯维在《要事第一》中提出了时
  • 关键字:UTC(世界标准时间),Calendar Time(日历时间),epoch(时间点),clock tick(时钟计时单元) 1.概念 在C/C++中,对字符串的操作有很多值得注意的问题,同样,C/C++对时间的操作也有许多值得大家...
  • 交叉小径的花园

    千次阅读 2012-05-29 15:52:44
    作者在小说中布开了一张时间的网,它的网线相互接近、交叉、隔断,或者几个世纪毫不相关,包括了一切的可能性。我们并不存在于这种时间的大多数里:在某一些里,您存在,而我不存在:在另一些里,我存在,而您却不存在…… ...
  • 时间序列的分析及滚动预测代码

    万次阅读 多人点赞 2018-12-23 21:19:02
    部分代码可能因为版本问题出现bug! 什么是时间序列 ...在这里需要强调一点的是,时间序列分析并不是关于时间的回归,它主要是研究自身的变化规律的(这里不考虑含外生变量的时间序列)。 为什么...
  • Oracle数据库从10g开始,启用以时间模型统计为主,命中率为辅等性能度量指标。基于时间模型统计,主要是基于操作类型测量在数据库中花费的时间的统计信息。最重要的时间模型统计是...本文描述时间模型统计相关知识点。
  • 顺函数API

    万次阅读 2015-12-17 10:01:37
    而具体的显示方案则在“窗口属性”的“时间坐标”项里的“时间格式”一栏里选择。 用于:个股、沪深指数所有的周期。 HIGH 最高 含义:在实时周期时,为当日的最高价。在分钟K线、日K线周期时,分别为当...
  • C语言再学习 -- 时间函数

    千次阅读 2017-01-14 16:46:39
    在软件设计中经常会用到关于时间的处理,用来计算语句、函数的执行时间,这时就需要精确到毫秒甚至是微妙的时间。我们首先来介绍一下,时间单位: 时间单位还有:毫秒(ms)、微秒 (μs)、纳秒(ns)、皮秒(ps)、飞秒...
  • 点击上方“AI有道”,选择“星标”公众号重磅干货,第一时间送达《深度学习》,又名“书”。该书由三位大佬 Ian Goodfellow、Yoshua Bengio 和 A...
  • Linux时间同步(NTP)

    千次阅读 2017-09-05 13:55:09
    设置NTP服务器不难但是NTP本身是一个很复杂的协议. 这里只是简要地介绍一下实践方法,下面的实验都在RHEL5.5 64位上运行 1.时间和时区 ...这里就有产生了一个如何定义时间的问题. 因为在地球环绕太阳旋转的
  • 时间函数的用法(ctime)

    万次阅读 2013-08-21 23:58:42
    /C++对时间的操作也有许多值得大家注意的地方。最近,在技术群中有很多网友也多次问到过C++语言中对时间的操作、获取和显示等等的问题。下面,在这篇文章中,笔者将主要介绍在C/C++中时间和日期的使用方法.  ...
  • 365天生日花语

    千次阅读 2007-11-27 18:34:00
    一月生日二月生日三月生日四月生日五月生日六月生日七月生日八月生日九月生日十月生日十一月生日十二月生日 一月一日 生日:绣球(Laurustinus) 花语:希望(Hope) 原产在地中海...
  • memset对memcpy耗费时间的影响

    千次阅读 2017-12-03 09:18:42
    源于之前几天的一个测试程序,作用是用来测试某个系统的内存访问能力,主体测试策略是分配一个缓冲区,然后使用memcpy在分配的缓冲区之间拷贝若干次,计算拷贝时间,然后在多线程的环境下运行多个拷贝程序,再次分别...
  • Python时间序列分析

    万次阅读 2017-05-08 14:15:04
    什么是时间序列 时间序列简单的说就是各时间点上形成的数值序列,时间序列分析就是通过观察历史数据预测未来的值。在这里需要强调一点的是,时间序列分析并不是关于时间的回归,它主要是研究自身的变化规律的...
  • 时间简史

    万次阅读 2011-11-06 16:52:29
    想找时间简史之简史,没有找到,暂时把这个发表上来吧~ 关于版权问题~在中国好像没有什么问题,哈哈,只是和大家分享一下,希望有兴趣的人能看一看~ 哈哈~ 喜欢蓝色,有颜色的比没有颜色感觉看...
  • C++中的日期和时间time_t与struct_tm

    千次阅读 2016-06-13 16:05:41
    本文从介绍基础概念入手,探讨了在C/C++中对日期和时间操作所用到的数据结构和函数,并对计时、时间的获取、时间的计算和显示格式等方面进行了阐述。本文还通过大量的实例向你展示了time.h头文件中声明的各种函数和...
  • 关于linux下时间延迟函数精度问题

    千次阅读 2016-07-27 10:31:51
    1、xtime一个timeval结构类型变量,是从cmos电路中取得的时间,一般是从某一历史时刻开始到现在的时间,也就是为了取得我们操作系统上显示的日期。这个就是“实时时钟”,它的精确度是微秒。获取方式是通过sys/time....
  • 本文转载自公众号“读芯术”(ID:AI_Discovery)照片:zjkonline你敢相信?数十年来,《花花公子》的裸体照片一直是测试科技的试金石。“莱娜图” 图源:Dwight Ho...
  • 二、时间序列的预处理

    万次阅读 2018-06-11 11:28:29
    只有那些序列值之间具有密切的相关关系,历史数据对未来的发展有一定影响的序列,才值得我们花时间去挖掘历史数据中的有效信息,用来预测序列未来的发展。   如果序列值彼此之间的任何相关性,那就意味着该序列是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 141,202
精华内容 56,480
关键字:

代表时间有关的花