Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

《程序员的职业素养》——Robert C.Martin #19

Open
thzt opened this issue Feb 4, 2017 · 0 comments
Open

《程序员的职业素养》——Robert C.Martin #19

thzt opened this issue Feb 4, 2017 · 0 comments

Comments

@thzt
Copy link
Owner

thzt commented Feb 4, 2017

发布软件时,你应该确保 QA 找不到任何问题。
故意发送明知有缺陷的代码,这种做法是极其不专业的。

什么样的代码是有缺陷的呢?
哪些你没把握的代码都是!

有些家伙会把 QA 当做捉虫机器看待。
他们把自己没有全盘检查过的代码发送过去,想等 QA 找出 bug 再反馈回来。

且不说这么做是否会大幅增加公司成本,严重损害软件,是否会破坏计划并让企业对开发小组的信心打折扣,
也不去评判这么做是否等同于懒惰失职,把自己没把握的代码发送给 QA 这么做本身就是不专业的。

每次 QA 找出问题时,更糟糕的是用户找出问题时,你都该震惊羞愧,并决心以此为戒。


你怎么知道代码能否正常运行呢?
很简单,测试!
一遍一遍的测,翻来覆去,颠来倒去的测,使出浑身解数来测!

你或许会担心这么狂测代码会占用很多时间,毕竟,你还要赶进度,要在截止日期前完工。
如果不停的花时间做测试,你就没时间写别的代码了。
言之有理!所以要实行自动化测试。

写一些随时都能运行的单元测试,然后尽可能多的执行这些测试。
要用这些自动化单元测试去测多少代码呢?还要说吗?全部!全部都要测!

我是在建议进行百分之百测试覆盖吗?不,我不是在建议,我实在要求!
你写的每一行代码都要测试。完毕!

这是不是不切实际?当然不是。
你写代码是因为想执行它,如果你希望代码可以执行,那你就该知道它是否可行。
而要知道它是否可行,就一定要对它进行测试。

但是有些代码不是很难测试吗?是的,但之所以很难测试,是因为设计时就没考虑如何测试。
唯一的解决办法就是要设计易于测试的代码,最好是先写测试,再写要测的代码。


成熟的专业开发人员知道,聪明人不会为了发布新功能而破坏结构。
结构良好的代码更灵活。
以牺牲结构为代价,得不偿失,将来必追悔莫及。

所有软件项目的根本指导原则是,软件要易于修改。
如果违背这条原则搭建僵化的结构,就破坏了构筑整个行业的经济模型。

不幸的是,实在是已有太多的项目因结构糟糕而身陷失败的泥潭。
那些曾经只要几天就能完成的任务现在需要耗费几周甚至几个月的时间。
急于树立威信的管理层于是聘来更多的开发人员来加快项目进度,但这些开发人员指挥进一步破坏结构,乱上添乱。

如果你希望自己的软件灵活可变,那就应该时常修改它。
要想证明软件易于修改,唯一办法就是做些实际的修改。
如果发现这些改动并不像你预想的那样简单,你便应该改进设计,使后续修改变简单。

该在什么时候做这些简单的小修改呢?随时!
关注哪个模块,就对它做点简单的修改来改进结构。
每次通读代码的时候,也可以不时调整一下结构。

这一策略有时也叫“无情重构”,我把它叫做“童子军训练守则”:
对每个模块,每检入一次代码,就要让它比上次检出时变得更为简洁。
每次读代码,都别忘了进行点滴的改善。

这完全与大部分人对软件的理解相反。
他们认为对可工作软件不断的做一系列修改是危险的。
错!让软件保持固定不变才是危险的!
如果一直不重构代码,等到最后不得不重构时,你就会发现代码已经“僵化”了。

为什么大多数开发人员不敢不断修改他的代码呢?
因为他们害怕会改坏代码!
为什么会有这样的担心呢?因为他们没做过测试。

话题又回到测试上来了。如果你有一套覆盖了全部代码的自动化测试,如果那套测试可以随时快速执行,
那么你根本不会害怕修改代码。

怎样才能证明你不怕修改代码呢?那就是,你一直在改。

专业开发人员对自己的代码和测试极有把握,他们会极其疯狂随意的做各种修改。
简单说,他们对待代码,就如同雕塑家对待泥巴那样,要对它进行不断的变形与塑造。


职业发展是你自己的事。雇主没有义务确保你在职场能够立于不败之地,
也没义务培训你,送你参加各种会议或给你买各种书籍充电。这些都是你自己的事。
将自己的职业发展寄希望于雇主的软件开发人员将会很惨。

另外,雇主也没义务给你留学习时间。
雇主出了钱,你必须付出时间和精力。
为了说明问题,就用一周工作 40 小时的美国标准来做参照吧。
这 40 小时应该用来解决雇主的问题,而不是你自己的问题。

你应该计划每周工作 60 小时。前 40 小时是给雇主的,后 20 小时是给自己的。
在这剩余的 20 小时里,你应该看书、练习、学习,或者做其他能提升职业能力的事情。

或许你不愿那么勤勉。没问题。
只是那样的话你也不能自视为专业人士了,因为所谓 “术业有专攻” 那也是需要投入时间去追求的。


我们需要招聘的不是“经历丰富”的人,而是“有职业素养的人”。
你遇到的问题可能很容易也可能很难,但我看重的并不是问题的难度,而是解决问题的方式,步骤以及反思的深度。
拿恢复误删数据来说,这可能算非常简单的任务。
我更感兴趣的是怎样分析问题,找了怎样的资料,采取了怎样的步骤,此后做了哪些措施来避免这种错误再次出现。
在我看来,相比问题本身的难度,解决问题的方式和步骤以及反思的深度,都体现出一个人的职业素养。

技术人员经常太容易说“是”,往往在没有明确目标和期限的情况下,就草率给出了确认的答复,而且并不将其视为自己的一种承诺。
屡见不鲜的项目延期,有相当原因就是在这种不负责任的情况下说“是”导致。

有时候,获取正确决策的唯一途径,便是勇敢无畏的说出“不”字。
我们要明白,委屈专业原则以求全,并非问题的解决之道。
舍弃这些原则,只会制造出更多的麻烦。
(注:放弃原则,本身就是一种不专业的做法。

一看到已经满足的需求,关于到底想要什么,他们就会冒出更好的想法,通常并不是他们当时看到的样子。
真正的解决办法,是约定共同认可的验收测试标准,并在开发过程中保持沟通。


非专业人士不需要为自己所做的工作负责,他们大可把责任推给雇主。
如果非专业人士把事情搞砸了,收拾摊子的往往是雇主,而专业人士如果犯了错,只好自己收拾残局。
实际上,专业主义的精髓就在于将公司利益视同个人利益。
看到了吧,“专业性”就意味着担当责任。

开发的软件有bug会损害软件的功能。因此,要做得专业,就不能留下bug。
“等等!”你肯定会说,“可是那是不可能的呀。软件开发太复杂了,怎么可能会没bug呢!”
当然,你说的没错。软件开发太复杂了,不可能没什么bug。
但很不幸,这并不能为你开脱。
人体太复杂了,不可能尽知其全部,但医生仍誓言不伤害病人。

代码中难免会出现bug,但这并不意味着你不用对它们负责。
没人能写出完美的软件,但这并不表示你不用对不完美负责。
所谓专业人士,就是能对自己犯下的错误负责的人,哪怕那些错误实际上在所难免。
职业经验多了之后,你的失误率应该快速减少,甚至渐近于零。
失误率永远不可能等于零,但你有责任让它无限接近零。

(1)让QA找不出任何问题
在发布软件时,你应该确保QA找不出任何问题。
故意发送明知有缺陷的代码,这种做法是极其不专业的。
什么样的代码是有缺陷的呢?那些你没把握的代码都是!
把自己没把握的代码发送给QA这么做本身就是不专业的。

QA会发现bug吗?可能会吧,所以准备好道歉吧,然后反思那些bug是怎么逃过你的注意的,想办法防止它再次出现。
每次QA找出问题时,更糟糕的是用户找出问题时,你都该震惊羞愧,并决心以此为戒。

(2)要确信代码正常运行
你怎么知道代码能否正常运行呢?很简单,测试!
一遍遍的测,翻来覆去,颠来倒去的测,使出浑身解数来测!

写一些随时都能运行的单元测试,然后尽可能多的执行这些测试。
你写的每一行代码都要测试。
你写代码是因为想执行它,如果你希望代码可以执行,那你就应该知道它是否可行。
而要知道它是否可行,就一定要对它进行测试。

有些代码不是很难测试吗?
是的,但之所以很难测试,是以为设计时就没考虑如何测试。
唯一的解决办法就是要设计易于测试的代码,最好是先写测试,再写要测的代码。

(3)自动化QA
作为开发人员,你需要有个相对迅捷可靠的机制,以此判断所写的代码可否正常工作,并且不会干扰系统的其他部分。


成熟的专业开发人员知道,聪明人不会为了发布新功能而破坏结构。
结构良好的代码更灵活,以牺牲结构为代价,得不偿失,将来必追悔莫及。
所有软件项目的根本指导原则是,软件要易于修改。
如果违背这条原则搭建僵化的结构,就破坏了构筑整个行业的经济模型。

不幸的是,实在是已有太多的项目因结构糟糕而深陷失败的泥潭。
那些曾经要几天就能完成的任务现在需要耗费几周甚至几个月的时间。
急于重新树立威望的管理层,于是聘来更多的开发人员来加快项目进度,
但这些开发人员只会进一步破坏结构,乱上添乱。

描述如何创建灵活可维护的结构的软件设计原则和模式已经有很多了。
专业的软件开发人员会牢记这些原则和模式,并在开发软件时认真遵循。
但是其中有一条实在是没几个开发人员会认真照做,那就是:
如果你希望自己的软件灵活可变,那就应该时常修改它!

要想证明软件易于修改,唯一办法就是做些实际的修改。
如果发现这些改动并不像你预想的那样简单,你便应该改进设计,使后续修改变简单。

对每个模块,每检入一次代码,就要让它比上次检出时变得更为简洁。
每次读代码,都别忘了进行点滴的改善。
这完全与大多数人对软件的理解相反,他们认为对可工作的软件不断的做一系列修改是危险的。错!
让软件保持固定不变才是危险的!
如果一直不重构代码,等到最后不得不重构时,你就会发现代码已经“僵化了”。

为什么大多数开发人员不敢不断的修改他们的代码呢?
因为他们害怕会改坏代码!
为什么会有这样的担心呢?
因为他们没做过测试。

话题又回到测试上来了,如果你有一套覆盖了全部代码的自动化测试,如果你那套测试可以随时快速执行。
那么你根本不会害怕修改代码。
怎样才能证明你不怕修改代码呢?那就是,你一直在改。
专业开发人员对自己的代码和测试极有把握,他们会极其疯狂的做各种修改。
简单的说,他们对待代码,就如同雕塑家对待泥巴那样,要对它进行不断的变形和塑造。


职业发展是你自己的事,雇主没有义务确保你在职场能够立于不败之地,
也没有义务培训你,送你参加各种会议或给你买各种书籍充电,这些都是你自己的事。
将自己的职业发展寄希望于雇主的软件开发人员将会很惨。

雇主出了钱,你必须付出时间和精力。
为了说明问题,就用一周工作40小时的美国标准来做参照吧。
这40小时应该用来解决雇主的问题,而不是你自己的问题。
你应该计划每周工作60小时,前40小时是给雇主的,后20小时是给自己的。
在这剩余的20小时里,你应该看书,练习,学习,或者做其他能提升职业能力的事情。

或许你不愿那么勤勉,没问题,只是那样的话你也不能自视为专业人士了,
因为所谓“术业有专攻”那也是需要投入时间去追求的。


近50年来,各种观点,实践,技术,工具与术语在我们这一领域层出不穷。
你对这些了解多少呢?如果想成为一名专业开发者,那你就得对其中的相当一大部分有所了解,而且要不断扩展这一知识面。
下面列出了每个专业软件开发人员必须精通的事项。
(1)设计模式:必须能描述GOF书中的全部24种模式,同时还要有POSA书中多数模式的实战经验。
(2)设计原则:必须了解SOLID原则,而且要深刻理解组件设计原则。
(3)方法:必须理解XP,Scrum,精益,看板,瀑布,结构化分析及结构化设计等。
(4)实践:必须掌握测试驱动开发,面向对象设计,结构化编程,持续集成和结对编程。
(5)工件:必须了解如何使用UML图,DFD图,结构图,Petri网络图,状态迁移图,流程图和决策表。


你会找那些已经不看医学期刊的医生看病吗?
你会聘请那些不了解最新税法和判例的税务律师吗?
雇主们干嘛要聘用那些不能与时俱进的开发人员呢?

业精于勤,真正的专业人士往往勤学苦干,以求得自身技能的纯熟精炼。
只完成日常工作是不足以称为练习的,那只能算是种执行性质的操作,而不是练习。
练习,指的是在日常工作之余专门练习技能,以期自我提升。

对软件开发人员来说,有什么可以用以操练的呢?
乍一听,这概念显得荒唐,但是再仔细想一会儿,想想音乐家是如何掌握演练技能的。
他们靠的不是表演而是练习。
他们又是如何练习的呢?首先,表演之前,都需要经历过特别的训练,音阶,练习曲,不断演奏等。
他们一遍又一遍的训练自己的手指和意识,保持技巧纯熟。

俗话说,教学相长,想迅速牢固的掌握某些事实和观念,最好的方法就是与由你负责的人交流这些内容。
这样,传道授业的同时,导师也会从中受益。
同样,让新人融入团队的最好办法是和他们坐到一起,向他们传授工作要诀。
专业人士会视辅导新人为己任,他们不会放任未经辅导的新手乱打乱撞。


每位专业软件开发人员,都有义务了解自己开发的解决方案所对应的业务领域。
你未必需要成为该领域的专家,但你仍需勤勉,付出相当的努力来认识业务领域。

开始一个新领域的项目时,应当读一两本该领域相关的书,要就该领域的基础架构与基本知识作客户和用户访谈。
还应当花时间和业内专家交流,了解他们的原则和价值观念。
最糟糕,最不专业的做法是,简单按照规格说明来编写代码,但却对为什么那些业务需要那样的规格定义不求甚解。
相反,你应该对这一领域有所了解,能辨别,质疑规格说明书中的错误。


能就是能,不能就是不能。不要说“试试看”。——尤达

每位经理都承担着工作职责,绝大多数经理也知道该如何尽职尽责。
其中一部分的工作职责,便是要竭尽所能追求和捍卫他们设定的目标。
同样,程序员也自有其工作职责所在,绝大多数程序员也知道该如何出色的尽职尽责。
如果他们是专业程序员的话,他们也会竭尽所能的去追求和捍卫自身的目标。

你的经理要求你在明天之前完成登录页面,这就是他在追求和捍卫一个目标,那是尽他的工作职责。
如果你明知第二天之前不可能完成登录页面,嘴上却说“好的,我会试试的”,那便是你的失职了。
这时候,唯一的尽职方式便是说“不,这不可能”。

可是难道你不该照经理说的话去做吗?
当然不该,你的经理指望的是,你能像他那样竭尽所能的捍卫自己的目标。
这样你们俩才能得到可能的最好结果。
可能的最好结果,是你和你的经理共同追求的目标。
最关键的是要找到那个共同目标,而这往往有赖于协商。

或许你觉得Paula应该解释下为什么“登录页面”还要花那么长时间才能完成。
我的经验是,“为什么”远不如“事实”重要。
事实是,“登录页面”还需要两个星期才能完成。而为什么需要两个星期,则只是个细节。
有时候,提供太多细节,只会招致更多的微观管理。

最要说“不”的是那些高风险的关键时刻,越是关键时刻,“不”字就越具价值。
这一点应该不证自明,当公司存亡成败皆系于此时,你必须尽己所能,把最好的信息传递给你的经理。
这往往意味着要说“不”。

许诺“尝试”,就意味着你承认自己之前未尽全力,承认自己还有余力可施。
许诺“尝试”,意味着只要你再加把劲还是可以达成目标的,而且这也是一种表示你再接再厉去实现目标的承诺。
因此,只要你许诺自己会去“尝试”,你其实是在承诺你会确保成功。
这样,压力就要由你自己来扛了,如果你的“尝试”没有达成预期的结果,那就表示你失败了。

如果你此前并未有所保留,如果你没有新方案,如果你不会改变你的行为,如果你对自己原先的估计又充分的自信,那么从本质上讲,
承诺“尝试”就是一种不诚实的表现,你在说谎。
你这么做的原因,可能是为了护住面子和避免冲突。

尽管客户一再声明交付日期很重要,尽管他们对此表现得似乎非常迫切,但他们永远不会像你那样在乎应用程序的按时交付。
一切尘埃落定之后再想想,客户从始至终倒是说对了一件事:这个程序是“应急”的。

急于完成,却迟难面市:
(1)告诉开发人员这个应用很简单,这能误导整个开发团队进入一种错误的思维框架,还能让开发人员们更快开工。
(2)挑剔职责开发团队没能发现他们的需要,并借机添加各种功能。
(3)一而再的推后项目截止日期,在你已加班20小时把一切差不多都弄好时,他们又多给你几天时间,然后再加一周时间,好提出新的需求。

接受错误的决定,才是失败的真正根结,成功的唯一途径就是坚持专业行为。
委屈专业原则以求全,并非问题的解决之道。舍弃这些原则,只会制造更多的麻烦。


做出承诺,包含三个步骤:
(1)口头上说自己将会去做
(2)心里认真对待做出的承诺
(3)真正付诸行动

很少有人会认真对待自己说的话,并且说到做到。
有些人在说话时是认真的,但从来都不会说到做到。
而更多的人在做出承诺后,几乎从不会认真履行诺言。

更糟的是,我们常常会因为直觉摔跟头,有时我们轻信他人会说话算话说到做到,但事实上,他并没有像承诺的那么去做。
我们可能会相信某位开发人员所说的,他们能在一星期内完成原本两星期才能完成的任务,但其实他们是迫不得已才这么说的。
我们不能轻易相信此类承诺。

在承诺做某事时,应当留意自己的用词,因为这些用词透露了我们对待承诺的认真程度。
例如:需要/应当,希望/但愿,让我们,等等。
你会发现,我们有极力逃避承担责任的倾向。

识别真正的承诺的诀窍在于,要去搜寻与下列相似的语句:
我将在……之前……(如:我将在星期二之前完成这个任务。)
这句话的关键在哪里呢?你对自己将会做某件事做了清晰的事实陈述,而且还明确说明了完成期限。
那不是指别人,而是说的自己。
你谈的是自己会去做的一项行动,而且,你不是可能去做,或是可能做到,而是会做到。

如果最终目标依赖他人,那么你就应该采取些具体行动,接近最终目标。
即使目标无法完成,你仍能全力前进,离目标更近些。而弄清楚目标能否达到这件事,便是你可能采取的努力行动之一。
有些时候真的无能为力,有些事情先前你可能没预料到,但如果你希望自己能够不负众望,那就赶紧去调整别人对你的预期,越快越好。
如果你无法兑现承诺,那么最重要的就是尽早向你的承诺对象发出预警,越快越好,越早越好。
你越早向各利益相关方发送预警信号,整个团队就越有可能抓住机会,中止并重新评估当前的活动,并决定是否采取某些措施或做出些改变。(比如调整优先级等)
这么一来,你仍有可能达成之前的承诺,或者用另一个承诺代替先前的承诺。
如果你不尽早告诉他人可能的问题,就错失了让他们帮助你达成目标,兑现承诺的机会。

如果是专业开发人员,就不会放弃底线,多年的经验告诉我们,打破这些纪律和原则,必然会拖慢进度。
专业人士对自己的能力极限了如指掌,他们十分清楚自己还能保持效率加班多长时间,也非常明白要付出的代价。
如果自己加班的话,一定可以完成代码修改和文档编写的任务,但是在这之后的几天需要休整,才有精力回来继续工作。


能够感知到错误确实非常重要,不只对“录入”是这样,对于一切事情莫不如此。
具备“出错感知能力”,说明你已经能够非常迅速的获得反馈,能够更为快速的从错误中学习。

当你无法全神贯注的编码时,所写代码就可能出错。
代码中可能会存在不少错误,也可能会存在错误的结构,模糊晦涩,令人费解,无法解决客户的实际问题。
总之,最终你可能必须返工修改代码甚至重写,在心烦意乱的状态下工作,只会造成严重的浪费。
如果感到疲劳或者心烦意乱,千万不要编码。
强而为之,最终只能再回头返工。相反,要找到一种方法消除干扰,让心绪平静下来。

疲劳的时候,千万不要写代码,奉献精神和职业素养,更多意义上指要遵守纪律原则而非成为长时间工作的工作狂。
要确保自己已经将睡眠,健康和生活方式调整到最佳状况,这样才能做到在每天的8个小时工作时间内全力以赴。
焦虑的时候,根本就不应该编码,这时产生的代码都会是垃圾,这时应该先想办法解除焦虑情绪。

流态区,指的是程序员在编写代码时会进入的一种意识高度专注,但思维视野却会收拢到狭窄的状态。
在流态区,人们会感到效率极高,但其实没有顾忌全局,很可能会做出一些后来不得不推到重来的决策。

中断无法避免,总有干扰会打断你,消耗你的时间。
发生这种情况时要记住一点,也许下次也会轮到你去打断别人请求帮助。
因此,礼貌的表现出乐于助人的态度才是专业的态度。

结对是用以应对中断的一种好方法,当你接电话或回答其他同事的问题时,结对搭档能够维护住中断处的上下文。
另一种很有帮助的方法便是采用TDD,如果有一个失败的测试,它就能帮你维护住编码进度的上下文。

很久之前我已经明白这一点:“创造性输出”依赖于“创造性输入”。
我平时广泛阅读,不放过各种各样的资料。
包括软件,政治,生物,航天,物理,化学,数学,还有其他许多方面的资料。

出于某些原因,软件开发人员会认为调试时间并非编码时间,他们认为存在调试时间是天经地义的,调试不等于编码。
但是对于公司来讲,调试时间和编码时间是一样昂贵的。
因此,如果我们能够做些事情避免甚或消除调试活动,那是最为理想不过的。

不管是否采用TDD或其他一些同等效果的实践,衡量你是否是一名专业人士的一个重要方面,
便是看你是否能将调试时间尽量降到最低。

软件开发是一场马拉松,而不是短跑冲刺。
你无法全程一直以最快的速度冲刺来赢得比赛,只有通过保存体力和维持稳定节奏来取胜。
无论是赛前还是赛中,马拉松选手都会仔细调整好自己的身体状态。
专业程序员也会同样仔细的保存好自己的精力和创造力。

当碰到困难而受阻时,当你感到疲倦时,就离开一会,让富有创造力的潜意识接管问题。
精力分配得当,你将能在更短的时间内以更少的精力完成更多的事情。
让自己保持好节奏,让团队保持好节奏。
了解你的创造力和智力运行的模式,充分发挥它们的优势而非与之背道而驰。

管理延迟的诀窍,便是早期检测和保持透明。
最糟糕的情况是,你一直都在告诉每个人你会按时完成工作,到最后期限来临前你还在这样说,但最终你只能让他们大失所望。
不要这么做,相反,要根据目标定期衡量进度。

坚决坚持你的估算,你最初的估算比你在老板在面前时做出的任何调整估算都要准确的多。
告诉老板你已经考虑过所有情况,唯一能够加快进度的方法便是缩减范围。
不要经受不住诱惑盲目冲刺。
如果可怜的开发人员在压力之下最终屈服,同意尽力赶上截止日期,结局会十分悲惨。
那些开发人员会开始抄近路,会额外加班加点工作,抱着创造奇迹的渺茫希望。
这是制造灾难的最佳秘诀,因为这种做法给自己,给团队以及利益相关方带来了一个错误的期望。
这样每个人都可以避免面对真正的问题,把做出必要的艰难决定的时机不断后延。

其实,快速冲刺时做不到的。
你无法更快的写完代码。你无法更快的解决问题。
如果试图这么做,最终只会让自己变得更慢,同时也只能制造出一堆混乱,让其他人也慢下来。

加班确实有用,而且有时候也有必要。
有时候,通过一天工作10小时再加上周末加班一两天,你确实能够达成原本不可能的进度。
但这么做的风险也很高,在额外加班20%的工作时间内,其实你并无法完成20%的额外工作。
而且,如果连续两三个星期都要加班工作,则加班的措施必败无疑。

因此,不应该采用额外加班加单工作的方案,除非以下三个条件都能满足:
(1)你个人能挤出这些时间
(2)短期加班,最多加班两周
(3)你的老板要有后备预案,以防万一加班措施失败了
最后一条至为关键,如果老板无法向你清楚说明加班方案失败的后备预案,那么你就不应该同意接受加班方案。

在程序员所能表现的各种不专业行为中,最糟糕的是明知道还没有完成任务却宣称已经完成。
我们自欺欺人的认为任务已经完成得足够好,然后转入下一项任务。
我们自己给自己找借口说,其他还没来得及完成的工作可以等有更充裕时间的时候再来处理。
这种做法具有传染性,如果一名程序员这么做,其他程序员看见了一会效仿。

可以通过创建一个确切定义的“完成”标准来避免交付失误。
最好的方法是让业务分析师和测试人员创建一个自动化的验收测试,只有完全通过这些验收测试,开发任务才能算已经完成。


任何事情,要想做得快,都离不开练习。
尽可能快的重复编码/测试过程,要求你能迅速做出决定。
这需要识别各种各样的环境和问题,并懂得应付。

如果有两个习武者在搏斗,每个人都必须能够迅速识别出对方的意图,并且在百分之一秒内正确应付。
在搏斗时,你不可能有充足的时间来研究架势,思考如何应付。
这时候,你只能依靠身体的反应。
实际上,真正做出反应的是你的身体,大脑是在更高级的层面上思考。

无论如何,专业人士都需要练习。


我们把验收测试定义为业务方与开发方合作编写的测试,其目的在于确定需求已经完成。
验收测试都应当自动进行。
在软件开发周期中,确实有时候需要手动测试,但是验收测试不应当手工进行,原因很简单:要考虑成本。

验收测试是业务方写给业务方的(虽然可能最后是身为开发者的你来写),它们是正式的需求文档,描述了业务方认为系统应该如何运行。
关心验收测试结果的是业务方和程序员。
单元测试是写给程序员的,它是正式的设计文档,描述了底层结构及代码的行为。
关心单元测试结果的是程序员而不是业务人员。

这两种测试并不是重复劳动,它们的主要功能其实不是测试,测试只是它们的附属职能。
单元测试和验收测试首先是文档,然后才是测试。
他们的主要目的是如实描述系统的设计,结构,行为。

编写GUI的验收测试很麻烦,但如果把GUI当成API那样处理,而不是看成按钮,滚动条,格子,菜单,那验收测试就简单多了。
布局,格式,工作流,都会因为效率和美观的原因而变化,但是GUI背后的功能却不会因此变化。
测试系统功能时,应当调用真实的API,而不是GUI,测试程序应当直接调用GUI使用的API。
几十年来,设计专家一直教导我们,要把GUI和业务逻辑分开。
(注:GUI只是API的一层包装。

请务必确保在持续集成系统中,单元测试和验收测试每天都能运行好几次。
整套持续集成系统应该由源代码管理系统来触发。
持续集成不应该失败,如果失败了,团队里的所有人都应该停下手里的活,看看如何让测试通过。

交流细节信息是件麻烦事,尤其是开发方和业务方交流关于程序的细节时,更是如此。
通常,各方握手言欢,以为其他人都明白自己的意思。
双方以为取得了共识,然后带着截然不同的想法离开,这种事太平常不过了。

要解决开发方和业务方沟通问题,我所知道的唯一有效的办法就是编写自动化的验收测试。
它们就是无可挑剔的需求文档。


预估不是一个定数,预估的结果是一种概率分布。
专业开发人员能够清楚区分预估和承诺,只有再确切知道可以完成的前提下,它们才会给出承诺。
此外,它们也会小心避免给出暗示性的承诺,他们会尽可能清楚的说明预估的概率分布,这样主管就可以做出合适的计划。

你可以根据3个数字预估某项任务,这就是三元分析法。
(1)O,乐观估计:这是非常乐观的数字。如果一切都异常顺利,你可以在这个时间内完成,概率小于1%。
(2)N,标称估计:这是概率最大的数字。
(3)P,悲观估计:这是最糟糕的数字。
有了以上三个预估,我们可以像下面这样描述概率分布:
(1)任务的期望完成时间为:μ=(O+4N+P)/6
(2)任务的概率分布的标准差:σ=(P-O)/6,用来衡量不确定性,如果这个数字越大,就表示非常不确定。

例子:
任务 乐观估计 标称估计 悲观估计 μ σ
alpha 1 3 12 4.2 1.8
beta 1 1.5 14 3.5 2.2
gamma 3 6.25 11 6.5 1.3
则,总的μ=4.2+3.5+6.5=14.2,总的σ=(1.8^2+2.2^2+1.3^2)^(1/2)=~3.13。
所以,任务大概需要14天完成,也可能需要17天(1σ),甚至是20天(2σ)。
3项任务最乐观的估计是5填,即便是按照标称估计,也需要10天,那么为什么需要14天或者17天甚至20天呢?
答案是,因为这个数字是把各个任务的不确定性叠加起来,让计划更加现实。
如果你是有几年经验的程序员,可能看过过于乐观的项目预估,它们最终花的时间是预估的3到5倍。

预估是非常容易出错的,所以才叫预估。
控制错误的方法之一是使用大数定律,该定律的意思是,把大任务分成许多小任务,分开预估再加总,结果会比单独评估大任务要准确的多。
这样做之所以能提高准确度,是因为小任务的预估错误几乎可以忽略,不会对总的结果产生明显影响。

专业开发人员一旦做了承诺,就会提供确定的数字,按时兑现。
但是大多数情况下,他们都不会做这种承诺,而是提供概率预估,来描述期望的完成时间及可能的变数。
对需要妥善对待的预估结果,专业开发人员与团队的其他人协商,以取得共识。


即使有压力,专业开发人员也会冷静果断,尽管压力不断增大,他仍然会坚持所受的训练和纪律,
他知道这些是他赖以战胜由最后期限和承诺所带来的压力感的最好方法。

在压力下保持冷静的最好方式,便是规避会导致压力的处境。
应当避免对没有把握能够达成的最后期限做出承诺,这一点很重要。
业务方总是期望能够拿到这些承诺,因为他们想消除风险。
我们要做的就是使风险定量化并将它们陈述给业务方,这样他们就能做好相应准备。
做不切实际的承诺会阻碍目标的实现,对公司和个人都没好处。

有时有人会代我们做出承诺,发生这种事情,由于责任感我们必须主动帮助业务方找到方法来兑现这些承诺,但是一定不能接受这些承诺。
专业人士总会千方百计的帮助业务方找到达成目标的方法,但并不一定要接受业务方代为做出的承诺。
最终,如果我们无法兑现业务方所做出的承诺,那么该由当时做出承诺的人来承担责任。

快速前进确保最后期限的方法,便是保持整洁。
专业人士不会为了快点前进而乱来,他们明白“快速但脏乱”是自相矛盾的说法,脏乱只会导致缓慢。
让系统,代码和设计尽可能整洁,就可以避免压力。
这并非是说我们要花无穷无尽的时间去清理代码,而只是说不要容忍混乱。
混乱会降低速度,导致工期延误,承诺失信,因此,要尽力保持输出成果整洁干净。

观察自己在危机时刻中的反应,就可以了解自己的信念。
如果在危机中依然遵循着你守持的几率,就说明你确实相信那些纪律。
反过来说,如果在危机中改变行为,就说明你并不真正相信常规行为中的原则。
如果你在非危机时刻你会遵循测试驱动开发的纪律,但是在危机时刻你放弃了这种做法,这说明你并不真正相信TDD是有帮助的。
如果在平常时候你会注意保持代码整洁,但在危机时刻你却会产出混乱的代码,这说明你并不真正相信混乱会导致速度下降。
如果在危机时刻你会结对编程,但平时却不结对,就说明你相信结对工作比不结对更有效率。

选择那些你在危机时刻依然会遵循的几率原则,并且在所有工作中都遵守这些纪律。
遵守这些纪律原则是避免陷入危机的最好途径。
当困境降临时,也不要改变行为。


专业程序员的首要职责是满足雇主的需求,这意味着要和你的经理们,业务分析师们,测试工程师们和其他团队成员更好的写作,深刻理解业务目标。
专业程序员最糟糕的表现是两耳不闻窗外事,只顾一头将自己埋在技术堆里,甚至连公司业务火烧眉毛行将崩溃了也不闻不问。
你的工作职责就是要让业务免于陷入困顿,让公司可以长久发展下去。
因此,专业程序员会花时间去理解业务,他们会和用户讨论他们正在使用的软件,会和销售人员与市场人员讨论所遭遇的问题,会和经理们沟通,明确团队的短期目标和长期目标。
简而言之,他们会将注意力放在如何与业务同舟共济上。

不正常的团队最糟糕的症状是,每个程序员在自己的代码周边筑起一道高墙,拒绝让其他程序员接触到这些代码。
我曾在许多地方看到过,不少程序员甚至不愿让其他程序员看见他们的代码,这是招致灾难的“最佳秘诀”。

许多程序员都不喜欢“结对编程”这一理念。但很奇怪,在紧急情况下,大多数程序员又愿意结对编程。为什么呢?
很显然,因为这是解决问题最有效的方法。

如果我们真想终生能以编程度日,那么一定要学会交流,和人们交流。


形成团队是需要时间的,团队成员需要首先建立关系。
他们需要学习如何互相协作,需要了解彼此的癖好,强项,弱项,最终,才能凝聚成团队。
有凝聚力的团队通常由大约12名成员,最多的可以有20人,最少可以只有3个人,但是12个人是最好的。
这个团队应该配有程序员,测试人员和分析师,同时还要有一名项目经理。
由12个人组成的理想团队,人员配备情况是这样的,7名程序员,2名测试人员,2名分析师,1名项目经理。

分析师开发需求,为需求编写自动化验收测试。
测试人员也会编写自动化验收测试,但是他们两者的视角是不同的。
分析师关注业务价值,而测试人员关注正确性。
项目经理跟踪项目团队的进度,确保团队成员理解项目时间表和优先级。
其中一名团队成员可能会拿出时间充任团队教练或Master的角色,负责确保项目进展,监督成员遵守纪律。

银行和保险公司试图围绕项目来构建团队,这是一种愚蠢的做法。
按照这种做法,团队永远都不可能形成凝聚力,每个人都只在项目中短期停留,只有一部分时间是在为项目工作,因此他们永远都学不会如何默契配合。
专业的开发组织会把项目分配给已形成凝聚力的团队,而不会围绕项目来组建团队。

团队比项目更难构建,因此,组建稳健的团队,让团队在一个又一个项目中整体移动共同工作是较好的做法。


计算机科班毕业生的质量一直令我颇感失望。究其原因,并不是这些毕业生不够聪明或缺乏天份。
而是由于大学并没有教授真正的编程之道。

我注意到,那些符合要求的毕业生有个共同点,他们几乎都在进入大学之前就已经自学编程,并且在大学里依然保持自学的习惯。

学校能够传授的是计算机编程的理论,但是学校并不会也无法传授作为一名编程匠者所需掌握的原则,实践和技能。
这些东西只有经由师徒个体间多年的细心督导和辅导才能获得。
软件行业中像我们这样的一批人必须要面对这一事实,即指引下一代软件开发人员成熟起来的重任无法寄希望于大学教育,
现在这个重任已经落到了我们肩上。
建立一种包含学徒期,实习期和长期指引的机制已是迫在眉睫。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant