2017年最后一周,我按计划把《The Clean Coder》读完了,大约100页左右。
第6章 练习
这一章的内容是专业人士如何刻意练习。Bob大叔提到40年来他使用的电脑综合性能(内存硬盘容量和速度,显示分辨率的提升;提及能耗价格等的缩减)提升了10的22次方倍,但是实际上计算机程序的本质并没有变化,是可以通过一些基础程序的练习来不断提升自己的技能的。为了让22次方更形象,Bob大叔用了一个乔布斯经常用的技巧,把它转换成人可以理解的其他东西:是从这里到半人马座阿尔法星的距离(以埃为单位),是1美元硬币里的电子数,是地球质量与个人质量的比例。
今天,编译不再需要程序员等待。现在仍然有些程序员必须等待构建,这是悲剧,也是不够仔细的征兆。如今,构建时间应该用秒来衡量,而不是分钟,更不是小时。
构建时间这么细节的问题体现了专业性,比如前段时间大家关注解决的flex编译时间的问题,只是通过申请更好的机器就把整个项目的编译时间从90分钟缩减到20分钟,这应该是最便宜的投资了。不过还没达到Bob大叔说的秒级构建的水平,这里还有进一步提升的空间,但是也需要有专业人士的投入才行,需要学习和尝试下flex的增量编译框架fcsh和flex编译支持maven的工具flexmojos,也许会有帮助。
对于练习方式,作者给出了几种形式,一些练习套路,可以尝试在公司里设计相关的课程。
卡塔
在武术里,卡塔是一套设计好的、用来模拟搏斗一方的招式。与之类似,编程卡塔也是一整套敲击键盘和鼠标的动作,用来模拟编程问题的解决过程。联系着不是在解决真正的问题,因为你已经知道了解决方案。相反,你是在练习解决这个问题所需要的动作和决策。
编程卡塔的最终目标,也是逐步练习以达到纯熟。反复的练习会训练大脑和手指如何动作和反应。在不断练习当众,你或许会发现动作的细微进步,或者解决问题效率的小幅提升。
要学习热键和导航操作,以及测试驱动开发、持续集成之类的方法,找整套的卡塔来练习都是相当有效的。
Bob大叔给出了一些卡塔,参考网站http://codekata.pragprog.com,其中包括在《ASD》中给出的保龄球计分程序。今年后备教练训练营的TDD作业,我做的就是这个BowlingGame的程序。
真正的挑战是把一个卡塔练习到炉火纯青,你可以窥见其中的韵律。要做到这一点可不容易。
瓦萨
瓦萨基本可以说是两个人的卡塔。其中的招式需要精确地记忆,反复演练。一个人负责攻,另一个人负责守。攻守双方互换时,各种动作要一而再、再而三地反复。
程序员可以用一种叫“乒乓”的游戏来进行类似的练习:两个人选择一个卡塔,或者一个简单问题,一个人写单元测试,另一个人写程序通过单元测试,然后交换角色。
自由练习
自由练习就是不限制形式的搏击。模拟搏斗与编程并不是特别贴合。不过,很多编程练习场中都会玩一种叫做“自由练习”的游戏。它很像由两个参与者解决问题的瓦萨,只是自由练习是有很多人参与的,而且规则是可以延续的。在自由练习中,屏幕被投影到墙上,一个人写测试,然后坐下来,另一个人写程序通过测试,再写下一个测试。桌子边的人一个个轮流接下去,或者有兴趣的人可以自己排队参加。无论怎么安排,都是非常有趣的。
上面这三种方式,无一不是以TDD的方式进行,和上一章的内容吻合。另外还有在业余时间参与开源社区,也是推荐的练习方法,总之,专业人士需要不断的练习。
无论如何,专业人士都需要练习。他们这么做,是因为它们关心自己能做到的最好结果。更重要的是,他们用自己的时间练习,因为它们知道保持自己的技能不落伍是自己的责任,而不是雇主的责任。练习的时候你是赚不到钱的,但是练习之后,你会获得回报,而且是丰厚的回报。
第7章 验收测试
Bob大叔举了一个和业务人员一起以不断探索的方式写应用程序的例子,并总结了一些经验。其实是再一次阐述了敏捷的一些原则,强调变化是一定会有的,过早精细化是不必要的,业务方自己很可能并不知道自己要什么。应对方式是推迟精细化,用验收测试驱动开发。验收测试要自动化。几年前测试团队做过相关的尝试,当时觉得在验收自动化测试上投入有点高,没有继续进行下去,2018年是不是可以再尝试一下,改变一下PO和BA的工作方法?
验收测试和单元测试
验收测试是写给业务方看的,单元测试是写个程序员的,它们并不重复。它们的主要功能其实不是测试,测试只是附属功能。它们首先是文档,其次才是测试。
图形界面的测试
这里提到了增加ID和分层测试服务两种方式,都是以前曾经尝试过的,关键是要找到项目真实的落地。
持续集成
这里重点提到的是持续集成的纪律,集成失败必须立即修复,这是优先级最高的事情。实际做起来是需要全员意识上的改变的。
第8章 测试策略
“QA应该找不到任何错误”,这是对专业人士的要求。QA的主要职责不是发现程序员的错误,保证程序没有错误是程序员自己的职责。那QA做什么?
QA在团队中要扮演的是需求规约定义者(specifier)和特性描述者(characterizer)。
需求规约定义者:QA的任务是和业务人员一起创建自动化验收测试,作为系统真正的需求规约文档。
特性描述者:QA的另一项任务是遵循探索式测试的原则,描述系统运行中的真实情况,将之反馈给开发人员和业务人员。在这项任务中,QA并没有解析需求,而是在鉴别系统的真实情况。
自动化测试金字塔
专业开发人员遵循测试驱动开发的要求来创建单元测试。专业开发团队使用验收测试定义系统需求,使用持续集成保证质量稳步提升;同时,这些测试又属于全局测试体系。拥有一套单元测试和验收测试的同时,还需要有更高层次的测试,这样QA才找不出任何错误。
Bob大叔给出了五层的自动化测试金字塔,和我们经常看到的三层的金字塔不太一样,从下到上依次是:单元测试、组件测试、集成测试、系统测试、人工探索式测试。
单元测试是程序员自己编写自己使用,并且要做到接近100%的覆盖率,通常在90%以上,并且是真实的覆盖率,而不是那种虽然能通过但并不关心运行结果的错误的单元测试。
组件测试和集成测试都是针对API进行的测试。组件测试针对单个组件,集成测试针对多个组件。组件测试由QA和业务人员编写,开发人员提供辅助。常用的工具是FitNesse, JBehave, Cucumber。针对GUI的是Selenium或Watir等工具。组件测试要覆盖差不多系统的一半,主要是成功路径。异常路径是要靠单元测试来覆盖的。集成测试主要针对大型系统,是编排性测试,主要不是测试业务规则,而是测试组件装配在一起时是否协调。集成测试一般由系统架构师或主设计师来编写,用于确认系统架构层面的结构是否正确无误。集成测试时间运行比较长,一般不会作为持续集成的一部分。
系统测试大约占测试的10%,由系统架构师和技术负责人编写,一般是在GUI层次。
人工探索性测试不是自动化测试,它需要使用人类的创新能力,对系统进行深入研究和探索。预先编写测试计划反而会削弱这类测试的效果。可以考虑一些全员“抓虫”行动。覆盖率不是探索性测试的目标。
结论
TDD、验收测试这些组合起来,最终目标还是让QA找不到任何错误。
第9章 时间管理
会议
关于会议,有两条真理:
(1)会议是必需的;
(2)会议浪费了大量时间。
通常,两条真理同时适用于同一场会议。有些与会者认为这两条总结得非常好,有些则认为它们是正确的废话。
你需要为自己的时间负责,所以你需要选择哪些会议参加哪些会议不参加。Bob大叔提到Scrum的四会的问题,相关内容应该可以参考Scrum相关书籍。
争论/反对
Kent Beck曾告诉我一个深刻的道理:“凡事不能在5分钟内解决的争论,都不能靠辩论解决。”
如果争论必须解决,就应当要求争论各方在5分钟时间内向大家摆明问题,然后大家投票。这样,整个会议花的时间不会超过15分钟。
注意力点数
现在是个争抢注意力的时代,每个人最稀缺的资源就是注意力,谁抢到更多的注意力就能赚钱。如何保持注意力?
首先需要保证睡眠。Bob大叔每晚需要睡7小时。年初有几个月我曾经每晚睡5小时,想多争取些时间工作和学习,靠每天早晨的咖啡来支撑,后来发现自己有点扛不住,就尽量往7小时睡眠靠了。前阵子听樊登讲《睡眠革命》,一个睡眠周期时间是1.5小时,如果在睡眠周期中间被闹醒,则整天都会受影响,所以睡眠时间最好是1.5小时的整数倍,一周累积睡到35个周期就没问题。正在尝试中,貌似挺有道理。
肌肉注意力。体力活动需要肌肉注意力,编程需要心智注意力,两者的要求不相同。不过定期训练肌肉注意力可以提升心智注意力的上限。Bob大叔的做法是骑自行车1-2小时,大约30-50km,骑车的时候可以听播客或者音乐。我自己挺喜欢慢跑的,周六的早上慢跑听书是一种享受,也是一种放松。不过进入冬天雾霾重了就没怎么跑了。不过在家里做些俯卧撑也挺有好处。
时间拆分和番茄工作法
番茄工作法我用过一段时间,有时经常被打断或者自己内心没法静下来;有时又觉得25分钟时间好像有点短,专注的做一件事情时刚进入状态,番茄就结束了。看到有的文章说番茄时间设置成1小时比较好。不过按照Bob大叔前面的说法,其实进入心流状态并不是很好。也许25分钟的番茄钟就是很科学的。
要避免的行为是优先级错乱,或者不按优先级顺序来处理,这个事情在我身上也经常发生,明明知道有个事情是重要的,但总是拖到最后一刻才做,把自己逼到死角,搞得很忙乱。
番茄时间也需要回顾,感觉番茄工作法就是一个人的Scrum。我对自己的回顾就是对于每项事情的预估时间还是经常偏乐观,也许是因为自己有完美主义的倾向。这个和敏捷的思路并不太匹配,造成自己效率不高,需要调整。
死胡同和泥潭
死胡同:比如选择了走不通的技术道路,越是坚持浪费的时间越多。要记得,任何时候都有选择。
坑法则:如果你掉进了坑里,别挖。
比死胡同更糟糕的是泥潭。泥潭会减慢速度,但不会让你彻底停下来。但如果你使尽全力,你仍然可以取得进展。
之所以说泥潭比死胡同更麻烦,是因为在泥潭中,你仍然可以看到前进的道路,而且看起来总是比回头路要短(虽然实际不是这样)。
这两个道理一看就懂,可以如何分辨哪些是死胡同,哪些是泥潭,哪些是需要坚持挺过去的呢?感觉需要大智慧才行啊。
第10章 预估
预估是软件开发人员面对的最简单、也是最可怕的活动之一了。
承诺和预估
承诺是确定性的,必须要完成,其他人会依据你的承诺制定计划。不能兑现的承诺是一种欺骗。
预估是一种猜测,预估错误无关声誉。
我记得Steve McConnell的《快速软件开发》中有过描述,预估总是会给出两个值,要么是一个区间范围,要么是一个值和概率,而承诺就只有一个值。糟糕的是我们给出的大部分预估都会被管理者当成承诺,因为我们在预估时往往只给出一个值。
特别提一点,按照我们完成任务的时长绘制出直方图,大致上是符合韦伯分布的,而不是正态分布。从我司的度量数据可以看出这一点。如果出现明显不符合韦伯分布的曲线,要么说明任务粒度差异比较大,要么说明这里存在明显的异常,需要关注一下。
常用的预估方法,都是PMBOK中的知识:三点法、DELPHI法等。计划扑克就是一种DEPLHI法。
关于软件估算,McConnell专门写了一本书,可惜没投入时间仔细读过。从经验来看,多人一起拍脑袋做类比估算是比较靠谱的,在PMBOK中叫做专家判断。目前业界的趋势应该是使用功能点方法或快速功能点方法,感觉其本质也是类比估算,不过是基于大数据的类比估算,最核心的东西是其积累的成千上万的项目数据信息。
第11章 压力
即使有压力,专业开发人员也会冷静果断。尽管压力不断增大,他仍然会坚守所受的训练和纪律,他知道这些是他赖以战胜由最后期限和承诺锁带来的压力感的最好方法。
本章前面讲述了Bob大叔自己承担压力以及他的应对方法。确实在他40年的软件生涯中,什么都遇到过了。有兴趣就阅读原书吧。
保持整洁
快速前进确保最后期限的方法,便是保持整洁。专业人士不会为了快点前进而乱来。他们明白“快而脏”是自相矛盾的说法。脏乱只会导致缓慢!
根据经验和我自己的理解,如果工作总是在交接中,可以找到下一位“接盘侠”,那么大家在工作中保持专业性的可能性就会大大降低。以前我维护的程序,我知道出了问题都要自己去解决,没有其他人可以依靠,所以为了让自己维护和理解程序的负担轻一些,所以我会把所有已知的问题都花时间消除掉,这样在遇到问题时我就不会分心去考虑这些已知的问题。已知的问题包括编译器检查出的所有告警,要么通过修改代码消除掉隐患,要么自己要确信理解了编译器告警的原因,并且明确这是无害的。事实证明这个确实有效,我很为我以前维护过的程序的稳定性和代码质量自豪。
是的,那时我还不知道Clean Code和TDD,不然我一定也在自己维护的代码中进行实践。
危机中的纪律
观察自己在危机时刻中的反应,就可以了解自己的信念。如果在危机中依然遵循着你守持的纪律,就说明你确实相信那些纪律。反过来说,如果在危机中改变行为,就说明你并不真正相信常规行为中的原则。
如果在非危机时刻你会遵循测试驱动开发的纪律,但是在危机时刻你放弃了这种做法,就说明你并不真正相信TDD是有帮助的。如果在平常时候你会注意保持代码整洁,但在危机时刻你却会产出混乱的代码,就说明你并不真正相信混乱会导致速度下降。如果在危机时刻你会结对工作,但平时却不结对,就说明你相信结对工作比不结对更有效率。
Bob大叔已经说得很清晰了,我完全赞同。意识不到混乱会导致速度下降,也许是因为还没有合适的度量方式让大家意识到这一点。想起CMMI顾问魏老师曾经给过的一个建议:如果公司不为修复程序故障支付报酬,或者只支付固定比例的报酬,也许对我们的交付质量提升会有比较大的促进作用。
应对压力
1:不要惊慌失措;2:沟通;3:依靠你的纪律原则;4:寻求帮助。
第12章 协作
程序员正是因为不善于和人打交道,喜欢和机器打交道才选择了这个职业。Bob大叔从程序员与雇主,程序员与程序员两个方面讨论了协作的问题,并且又是用自己亲身经历来说法。曾经他做过独行侠,忽略了雇主和公司利益,惨遭解雇的故事。这部分简单易懂,但很有警醒作用,值得读一下。
第13章 团队与项目
有凝聚力的团队
形成团队需要时间。团队成员需要首先建立关系。他们需要学习如何互相协作,需要了解彼此的癖好、强项、弱项,最终,才能凝聚成团队。
有凝聚力的团队确实有些神奇之处。他们能够一起创造奇迹。
有凝聚力的团队通常有大约12名成员。由12个人组成的理想团队,人员配备情况是这样的:7名程序员、2名测试人员、2名分析师和1名项目经理。
这个团队规模不符合5-9人的原则,不过可能平常我们是认为分析师(BA)和项目经理(PM)是团队外的人员,算起来也差不多。这个规模差不多也是我们以前一个科室的规模,确实感觉很不错。记得团队在解散的时候科室同事在公司论坛上留下一个帖子:“钢七连要解散了,实名留念”。我被别人叫做“七连长”(参考《士兵突击》),感觉这是我十几年工作生涯中得到过的最高褒奖。
团队和项目,何者为先?
试图围绕项目来构建团队是一种愚蠢的做法。按照这种做法,团队永远都不可能形成凝聚力。
专业的开发组织会把项目分配给已形成凝聚力的团队,而不会围绕着项目来组建团队。一个有凝聚力的团队能够同时承接多个项目,根据成员各自的意愿、技能和能力来分配工作,会顺利完成项目。
结论
团队比项目更难构建。因此,组建稳健的团队,让团队在一个又一个项目中整体移动共同工作是较好的做法。并且,团队也可以同时承接多个项目。在组建团队时,要给予团队充足的时间,让他们形成凝聚力,一直共同工作,成为不断交付项目的强大引擎。
第14章 辅导、学徒期与技艺
这是全书的最后一章(不算附录,附录说的是工具,和人无关),Bob大叔用自己的成长经历做了个总结,表达了对学校科班教学的失望,认为学校的教育并没能教会学生编程,真正的编程是在工作中学习和锤炼出来的。这个确实是现状,可能在中国和美国都是类似的情况,我自认自己只是个中级水平的程序员,这个能力水平也是在工作之后读了一些书做了一些实践之后获得的,刚毕业的时候确实很渣。
Bob大叔是雪鸟会议的发起者,某种意义上说可以认为是敏捷宣言之父,他同时也是软件工艺运动的推动者,他用这本小书向我们阐述了何为专业人士,以及如何成为专业人士,为他的专业精神所折服,推荐程序员都读一读,然后不再自称“码农”。
很高兴自己在两周内读完了一本书,并且这也是唯一一本我写完了读后感的书,感谢Bob大叔的言简意赅。
对了,其实还有最后的附录工具没有写,里面提到了配置管理工具svn/git,代码编辑器IDE,持续集成工具,问题跟踪工具,自动化测试工具等,提供的都是最优秀的选项,值得学习和参考。
我是有底线的