人员管理

请不要将招聘看作一个“收集简历,过滤简历”的过程,你必须将它看作一个“追踪优胜者,设法结识他们”的过程。

我有3个实现这个目的的基本方法:

(1) 走出去:设想一下那些你想雇用的人会出现在什么地方,然后去那里寻找合适的人,不要在大型的求职论坛发布没有针对性的招聘广告。

(2) 实习生:招聘还在还在学校里的学生并开始着手建立下一代优秀程序员之间的联系与花时间培养他们。

(3) 建立自己的社区:创造一个大型的网络社区,让观点相近的优秀软件开发者以某种形式聚集在你的公司周围。然后,每当你有职位空缺的时候,总会有天然的候选者。

寻找优秀程序员有一个所谓标准建议,就是询问你现在的雇员。怎么说呢,它背后的理论是,聪明的程序员一定认识其他聪明的程序员

程序员对公正公平是在乎的,你必须支付有竞争力的报酬,但是让我们这样说,当程序员决 定去哪里工作时,在他们考虑的所有因素中,报酬的位置低得让人吃惊,前提是薪水必须基本合理。

用许多平庸的程序员取代少数优秀的程序员,这种做法的真正问题在于,不管平庸的程序员工作多长时间,他们做出来的东西都无法像优秀程序员做得那样好。

三种管理方法:

1)军事化管理法

软件开发团队中的优秀程序员可以去任何他们想去的地方工作。在这种前提下,如果被人当成士兵一样对待,他们会感到相当扫兴,因此你要是这样做,最后就只能成为“光杆司令”了。

2)经济利益驱动法

“经济利益驱动法”假设每个人的行为动机都是金钱,让人们听命于你的最好方法就是给他们物质奖励或者物质惩罚,以此创造行为动机

3)认同法

让公司对雇员有认同感:一般来说,认同法要求你创造一个有凝聚力的、像脱水一样粘在一起的团队,就好像家庭一样。这样一来,人们就会对他们的同事产生忠诚感和义务感。例如:每天为整个团队提供午饭,大家围在一张大桌子吃饭,让人们觉得公司就将一个大家庭。

设计的作用

如果你问人们喜欢什么样的风格和设计,除非这些人受过专门训练,否则他们一般会选择自己最熟悉的品种。你给用户的选择越多,他们就越难选择,就会感到越不开心。

Dave Winer说过:“创造一个有使用价值的软件,你必须时时刻刻都在奋斗,每一次的修补,每一个功能,每一处小小的改进,你都在奋斗,目的只是为了再多创造一点空间,可以再多吸引一个用户加入。没有捷径可走,你需要一点运气,但是这不取决于你是否幸运。你之所以会有好运气,那是因为你寸土必争。”

软件实现上的小细节会导致在线社区发展、运作、用户体验上的大差异,所以应该只对如阿健做有意义的改进。

软件的设计上不可避免的要列出一个长清单,解释为什么每一个选项都是绝对必须的,不可缺少的。

管理大型项目

80%的用户大多数只使用20%的功能,但不幸的是,那个20%是一个变量。每个人需要的功能都不一样。生产只实现20%功能的产品是一种出色的自力更生战略,你用有限的资源生产出了产品,同时还赢得了用户。但这并不是一个好的长期的战略。因为产品简化意味着别人很容易复制的你的产品。一种故意减少功能的产品是没有钱途的

标准当然是很重要的,但是你不能迷信标准,你必须理解由于人会犯错,所以标准有时候会引发误解、困惑,甚至是争议,因此这样的标准无法达到预期的目标,无法减少“多对多”市场中庞大的测试数量。

当设备有了新版本时,一定要保证它自动向后兼容以前版本的附件,保证老附件能够在新版本的设备中正常使用,将像老附件能与老设备协同工作一样。

Jon Postel提出了鲁棒性原则(robustness principle):“对于己方的行为要保守,对于他方的行为要宽容”。他想说的意思是,让一个协议健壮地运行的最好方法就是,每个人都要非常非常小心地让自己的行为符合规范,而且同时在与合作伙伴进行信息交换时,又要采取极端宽容的态度。也就是说,只要你能猜出对方的意思是什么就可以了,不可苛求对方的行为一定要符合规范。

每当你的新功能解决了一件“麻烦事”,你的业务和市场都会有巨大的增长。优秀的推广,优秀的设计,优秀的推销人员,优秀的服务,再加上你为客户解决了许多“麻烦事”,这些因素加在一起会创造出将业务量做得足够大的结果,让你的软件影响到足够多的人,有可能是世界变得更美好。

开办软件公司

开公司的真正目的应该是将资本转化为有用的软件。作者对开软件创业公司的三点建议:

第一点。如果你说不清楚你的软件解决了什么棘手的问题,就不要去开软件公司。你要问自己,它解决了什么问题?谁需要这个软件?为什么它能解决这个问题?为什么客户愿意付钱让这个问题得到解决?

第二点。不要独自一个人创办公司。我知道很多人单枪匹马创业成功,但是失败的例子更多。如果你无法说服任何一个你的朋友,他们都不觉得你的主意是可行的,那么也许它就是不行的。

第三点。一开始不要抱太高期望。当产品上市的第一个月,没有人知道未来会赚多少钱。

总结一下,我所认为的创办软件公司的真正乐趣就是,创造一些东西,自己参与整个过程,悉心培育,不间断地劳作,不断地投入,看着它成长,看着自己一步步得到报偿。这是世界上最带劲的旅程,无论如何,我都不想错过它。

程序员的劳动力成本分摊在你销售出去的所有软件中,对软件来说,如果销售量很大,质量的改进并不会造成单位软件成本的上升,同时软件质量的改进会创造出新价值,而且价值创造的速度要快于成本提升的速度。

最好的工作条件->最好的程序员->最好的软件->利润

如果你开发的软件只是为了在公司内部使用,开发的目录是为了配合公司的运营,而不是销售,那么这种软件够用就可以了,不需要特别优秀。

定价是一门很深奥很难以琢磨的神秘学问,专家告诉你,软件公司犯下的最大错误就是定价太低,那样他们就没有足够的收入,不得不关门歇业。但是,还有更大的错误,那就是定价太高,那样你的公司就没有足够的顾客,不得不关门歇业

建立优质客户服务

客户遇到问题,你帮他解决了,客户实际上变得比没有问题时还要满意。如果你做得好,客人逢人就会唠叨你的服务是多么出色。

避免被别人起诉的方法就是不要让他人对你火冒三丈,要做到这一点,最好的方法就是承认错误,并且把该死的问题都解决掉。

发布软件

几条软件开发周期的基本规则:

(1)确定发布日期,这个日期可以根据客观情况也可以根据主观愿望进行选择。

(2)列出软件要实现的功能,然后按照优先顺序排序。

(3)每当你落后于预定进程时,就把排在最后的功能砍掉。

如果上面的每一步你都做到了,那么你很快就会发现,那些被你砍掉的功能根本不会让你感到后悔。

怎么来挑选发布日期呢?你可以考虑采用三种方法

(1)经常发布稍作改进的版本。

(2)每12到18个月发布一次。

(3)每3年到5年发布一次。

如果你的顾客人数较少,那么你最好经常性地发布小幅修改的新版本。如果你已经有了(或者想要有)大量的付费用户,那么你最好不要太频繁地发布新版本。

如果你已经做了大量的验证和单元测试,而且编写代码很仔细,那么你每天工作结束编译出来的版本可能已经质量很高了,随时都可以对外发布。如果为了应对竞争者的挑战,可能赶紧做出一个新版本以应对。

易用性的原则:一个应用的行为方法与用户期待的方式一致,那么它就是易用的。如果你每个星期都变一变,那么你的网站就缺乏可预测性,所以它的易用性也不会很高。

不要使用网站许可证,也不要想着先判断客户的经济实力,然后再根据对象的不同决定价格。

修订软件

当某个地方出错的时候,你就问为什么,一遍遍地追问,直到你找到根本性的原因为止。然后,你就针对根本性的原因开始着手解决问题,你要从根本上解决这个问题,而不是只解决一些表面的症状。

如果你的工作只是服务于某个特定顾客的需要,那么就有两种可能,一种是你有一个无法无天的销售员,另一种是你正在走向开发“个性化软件”这条道路。作者建议尽一切可能制作面向整个市场销售的上架软件,因为上架软件增加顾客的边际成本为零,所以你就是在把同一件东西一遍又一遍地卖出去,赚到多得多的利润。而且你还可以降低价格,因此把开发成本分摊到大量客户头上去。

如果你想把所有事情都做完,最后只会一事无成。

组织beta测试的十二个最高秘诀

下面是一些关于如何组织一次软件的beta测试的秘诀。需要注意的是,这里所说的“软件”指的是面向大量用户的软件,也就是我所称的“包装盒软件(注:“包装盒软件”指的是在商场中上架销售、有独立包装、外面用热收缩塑料膜密封的软件商品。),而不是公司内部的IT项目。这些秘诀对商业项目和开源项目都适用。不管你开发软件的目的是获得报酬,还是获得眼球效应,或是提高在同行中的知名度,都可以参考这些秘诀。

  1. 开放式的beta测试是没用的。要是你那样做,只可能有两种结果。一种结果是你有太多的测试者,这些人向你反馈了大量的意见,你从中根本不可能得到有用的数据。另一种结果是,现有的测试者根本不向你反馈他们的使用情况,导致你无法得到足够的数据。

  2. 要想找到那些能够向你反馈意见的测试者,最好的方法是诉诸他们“言行一致”的心理。你需要让他们自己承诺会向你发送反馈意见,或者更好的方法是,让他们自己申请参加beta测试。一旦他们采取了某些主动行为,比如填写一张申请表,在“我同意尽快发回反馈意见和软件故障报告”的选项上打勾,许多人就会发送反馈意见,因为他们想要“言行一致”。

  3. 不要妄想一次完整的beta测试的所有步骤能够在少于8-10周的时间内完成。我曾经试过,结果是除非老天帮忙,否则根本不可能做到。

  4. 不要妄想在测试中发布新的软件版本的频率能够快于每两周一次。我曾经试过,结果是除非老天帮忙,否则根本不可能有效。

  5. 一次beta测试中计划发布的软件版本不要少于4个。我从来没试过少于4个版本,因为太明显了,那样不可能达到测试目的。

  6. 如果在测试过程中你为软件添加了一个功能,那么哪怕这个功能非常微小,整个8个星期的测试也要回到起点,从头来过,而且你还需要再发布3个或4个新版本。我犯过的最大错误之一就是,在CityDesk 2.0的beta测试接近尾声的时候,我向软件中加入了一些保留空格的代码,这产生了一些意想不到的副作用,测试的时间不够了,我本应该将测试时间加长、进一步收集数据的。

  7. 即使你有一个申请参加beta测试的步骤,最后也只有五分之一的测试者会向你提交反馈意见。

  8. 我们制定了一条政策,所有向我们提交反馈意见的测试者都将免费获赠一份正版软件。不管你的反馈意见是正面的,还是负面的,只要你提交给我们,就能获得赠品。但是,在测试结束的时候,那些不提交反馈意见的测试者什么也不会得到。

  9. 你需要的严肃测试者(即那些会把反馈意见写成3页纸发送给你的人)的最小数量大约是100人左右。如果你独立开发软件,那么这是你能够处理的反馈意见的最大数量。如果你有一支测试管理团队或专门的beta测试经理,那么设法分别为每个处理反馈意见的人找到100个严肃测试者。

  10. 根据第7条,即使你有一个参加beta测试的申请步骤,最后也只有五分之一的测试者会真地使用你的产品并将反馈意见发送给你。那么,假定你有一个质量控制部门,里面一共有3个测试管理人员,这就意味着你必须批准1500份参加beta测试的申请表,因为这样才能产生300个严肃测试者。批准的数量少于这个数目的话,你就不会得到充分的反馈意见;批准的数量多于这个数目的话,你就会被许许多多重复的反馈意见淹没。

  11. 大多数beta测试的参与者只是在第一次拿到这个程序的时候才会去试用一下,然后就丧失了兴趣。此后每次你推出一个新的版本并发送给他们,他们也不会有兴趣重新测试它。除非他们每天都在用这个程序,但是对于大多数人来说,这是不可能的。因此,你需要错开不同版本的测试对象,将你的所有beta测试参与者分成四组,每次发布一个新版本的时候,就把一个新的组加入测试,这样就能保证每个版本都有第一次使用这个程序的测试者。

  12. 不要混淆技术beta和市场beta。我上面谈的这些都是针对技术beta,它的目标是发现软件中的错误和得到及时的用户反馈意见。市场beta则是软件正式发布前的预览版本,对象主要是新闻媒体、大客户和那些写入门教程的家伙(该教程必须在软件上市的同一天问世)。对于市场beta,你的目的并不是得到反馈意见。

当我们阅读面前的源码时,无非有以下几种目的:纯粹学习、添加新功能、重构旧代码、修复他人的Bug

为了学习去读源码,这是最愉快的最放松的,而重构旧代码、在代码功能上添加新功能、修复他人的bug等任务,大程度上我们心理感觉到比兴奋更大的是不爽,尽管如此,该是你干的活还是得继续干….

阅读旧代码的关键点

既然无法避免阅读旧代码,那么如果能注意以下几点,就有可能把历史的代码代码转换成为你成长的垫脚石

  • 产品需求与业务流程文档

产品需求与业务流程文档,这些是你先要找到的,你接手的代码,必然和某个产品需求相对应,必然实现了某个业务流程,先了解产品需求和业务流程,才能更好的读代码。

假如你的团队就是没文档,Ok,也可以要求离职或转移战线的这位程序员把需求描述出来,把业务流程画出来。

  • 测试环境

了解了产品需求和业务流程,最好能体验一下软件,从用户的角度来理解软件的使用。这个时候你要么需要生产环境,要么需要测试环境。哪个环境不重要,重要的是,你需要一个能Run,能体验的软件。

  • 业务流程在代码层面的体现

负责交接代码给你的那位同事,要么在办离职,要么已经介入了其他产品,眼下很可能已无心恋战,但你心里要清楚,只有他才能提供代码层面的东西,比如:类图、模块划分说明、数据流图、时序图、状态图。

所以,你需要他整理一些文档和图表出来。你可以告诉领导你需要上面的东西,让领导和他沟通,让他在离开之前准备好这些文档给你,并留一些时间以便你熟悉。

  • 读代码,不死不休

有了产品需求,有了业务流程,有了代码设计相关的文档和图表,接下来你就该死磕代码了:

while(不懂){ 读 }

  • 开发环境与调试

有的产品需要比较复杂的开发环境配置,一定要提前做好,让即将离开的同事辅导你搭建好开发环境,这样你就可以利用“调试”这个强大的武器来快速理解代码了。

  • 调试

调试是接手别人代码时的利器,如果你看不明白一个业务在代码层面是怎么体现的,也看不懂代码之间的调用关系,那最好的办法就是调试。从一个业务的起点所对应的代码开始调试,一步一步跟进去,就能快速理清函数调用链。

  • 树立可实现可衡量的目标

程序员的工作交接,尤其是代码交接,怎样才算顺利完成呢?这简直就是一个谜!没人说得清楚。所以,你最好给自己梳理一些可衡量的、可实现的目标。比如读懂A、B、C三个业务流程……

最好,找一个Bug或者一个新增的功能,带着目的去读代码、修改代码,有目的,有目标,有时间盒,就容易投入,容易读进去,容易掌握与Bug或新增功能相关的代码的逻辑与流程。

  • 输出、分享与重构

你在读代码时,如果能撇开给你交接工作的程序员提供的文档,按自己的理解,自己绘制类图、数据流图、时序图、关键业务流程对应的函数调用关系链等,就能更快的掌握别人的代码。

如果你还能将你理解到的东西,讲给其他人听,并且讲明白,那Ok,你真的理解了别人交接给你的代码。

再进一步,如果你在理解现有代码的基础上,可以识别出哪些部分实现得逻辑不清晰或有待改善,然后可以结合业务与自己的理解将其重构,那就真的是完全接手了别人的代码,别人的代码与你的代码就没有差别了,它们终将成为你的代码。

一些的心得体会

  • 理清某一业务如何映射在代码执行流程上的,这点很关键。

  • 理清不同模块间的业务关系,代码调用关系,很关键

  • 调试是弄明白代码调用流程的最快方式,之一

  • 找出关键代码(代表实际对象的类、衔接不同模块的类、代表业务关键节点的类)

  • 分析日志可以帮助分析代码执行流程和业务流程

  • 先用已有的可运行软件,体验业务,琢磨你点这里一下点那里一下代码可能是怎么做出反应的

  • 阅读应该围绕目的,把实现目标放在第一位,比如修改Bug,如果有期限,在最后日期前搞定是第一要务,然后有时间就继续读源码或改进Bug修复方案,力求没有副作用和后遗症,再有时间就修修别人留下的破窗户(你也可以顺带鄙视下前任维护者)

  • 千万次的问,还记得前面说要弄明白谁维护过你要读的代码吧,别不好意思,问吧,问吧,问吧

  • 对着设计文档、接口文档或测试用例看代码

  • 心理调试,勿畏难,别放弃。我有时看代码,看两天也不知道看了个甚,一头雾水两眼发花是常有的事儿,有时真是觉得搞不定了,然而,这要么是你基础知识没准备好,要么是你找错了入口,要知道,任何一份代码,都有一条隐形的线串着,耐心点,总会找到。这样不行就那样,多换换角度,多换换方法,读不行,就调试,调试不行,就运行,运行不行,就研究日志,都不行,我靠,while(!i.isDead())i.analyzeCode(),跟Y死磕!总之,你不放弃自己,就没人能放弃你!

  • 给自己设置小奖励,弄明白某个逻辑或某个模块的代码后奖励自己休息一下,5~10分钟,走出办公室转转,或者干脆在网上瞎逛一下,浏览自己喜欢的网站

  • 读不懂才要读,想不明白才要想,这是进步和成长的开始。那些阻挡你的蹂躏你的而又杀不死你的,终将帮助你成长让你变得更强大。

参考资料

  1. 接手别人的代码,死的心有吗?

我们在一些著名开源项目的版本库中,通常可以看到trunk, branches, tags等三个目录。由于SVN固有的特点,目录在SVN中并没有特别的意义,但是这三个目录却在大多数开源项目中存在,这是因为这三个目录反映了软件开发的通常模式

Trunk主干和Branches分支和Tags标签

  • Trunk主干

trunk主干,是主要的开发目录,还可以用于处理一些容易且能迅速解决的BUG,或者添加一些无关逻辑的文件(比如媒体文件:图像,视频,CSS等等)。

  • Branches分支

在版本控制的系统中,Branches分支是用来做添加新的功能以及产品发布后的bug修复等,这样可以不影响主要的产品开发线以及避免编译错误等。当我们添加的新功能完成后可以将其合并到主干中。

注意:

  1. 当一个branch完成了,并且认为它足够稳定的时候,它必须合并回它原来的拷贝的地方,也就是说:如果原来是从trunk中拷贝的,就应该回到trunk去,或者合并回它原来拷贝的父级branch。

  2. 除非是因为必须从一个branch中创建一个新的子branch,否则新的branch必须从trunk创建

  3. 建立的分支目的就是修改那些在主干中不会被修改的文件,以便修改完成后合并到主干中。

  • Tags标签

Tags目录一般是只读的,可以使用SVN中的authz文件控制该目录的访问权限为只读,Tags的创建主要用于在项目开发中的里程碑时或当trunk稳定后可以向外发布时,比如开发到一定阶段可以单独一个版本作为发布等,通常用于发布给客户使用。

还有一点值得注意的是,SVN不推荐在创建的Tag基础上Revision,这种情况应用Branches,因为Tag一般保持不变不作任何修改。

trunk、branches、tags的用法详解

当一个版本(trunk_release_2_0)开发告一段落(开发、测试、文档、制作安装程序、打包等)结束后,代码处于冻结状态(人为规定,可以通过hook来进行管理)。此时应该基于当前冻结的代码库,打tag,如:tag_release_2_0,这个版本是可以交付给用户的。当下一个版本/阶段的开发任务(trunk_release_2_1)开始,继续在trunk进行开发。此时,如果发现了上一个已发行版本(trunk_release_2_0)有一些bug,或者一些很急迫的功能要求,而正在开发的版本无法满足时间要求,这时候就需要在上一个版本上进行修改了。应该基于发行版对应的tag,做相应的分支(branch_bugfix_2_0)进行开发,等到bugfix结束,做一个tag,tag_release_2_0_1,然后,如果是修复bug的分支则需要把branch_bugfix_2_0并入trunk,如果是个性化功能则根据需要决定是否并入trunk。

为了便于创建分支和标签,我们习惯于将Repository版本库的结构布置为:/branches,/tags,/trunk。分别代表分支,标签以及主干。


project
  |
  +– trunk
        |
        +—– main.cpp  (2.0版本的最新文件)
        +—– common.h

  +– branches
  +     |
  +     +– r1.0
  +     +     |
  +     +     +—- main.cpp (1.x版本的最新文件)
  +     +     +—- common.h
  +     +
  +     +– r2.0
  +           |
  +           +—- main.cpp (2.x版本的最新文件)
  +           +—- common.h
  +
  +– tags   (此目录只读)
        |
        +– r1.0
        +     |
        +     +—- main.cpp (1.0版本的发布文件)
        +     +—- common.h
        +
        +– r1.1
        +     |
        +     +—- main.cpp (1.1版本的发布文件)
        +     +—- common.h
        +
        +– r1.2
        +     |
        +     +—- main.cpp (1.2版本的发布文件)
        +     +—- common.h
        +– r2.0
        +     |
        +     +—- main.cpp (2.0版本的发布文件)
        +     +—- common.h
        +
        +– r2.0.1
              |
              +—- main.cpp (2.0.1版本的发布文件)
              +—- common.h

工作流样例

假设你必须添加了一个特性至一个项目,且这个项目是受版本控制的,你差不多需要完成如下几个步骤:

  1. 使用SVNcheckout或者SVNswitch从这个项目的trunk主干获得一个branch分支

  2. 使用SVN切换本地代码为创建好的branch分支状态并完成新特性的开发(当然,要做足够的测试,包括在开始编码前)

  3. 一旦这个特性完成并且稳定(已提交),并经过你的同事们确认,切换本地代码为trunk状态

  4. 本地通过svn合并开发好的branch分支代码,重新检查合并后的代码并且解决一系列的冲突

  5. commit本地代码至项目的trunk上

  6. 如果某些部署需要特殊的环境(生成环境等等),请更新相关的tag至你刚刚提交到trunk的修订版本,使用SVNupdate部署至相关环境

参考资料

  1. http://www.cnmiss.cn/?p=296