敏捷的反馈
敏捷反馈
守护天使
Coding feedback.
为了应对代码的变化,你需要持续获得代码健康状态的反馈:他是在做你期望的事情吗?最近一次修改有没有无意中破坏了什么功能?为了确保所有功能都能正常工作,就需要自动化单元测试。
一些开发者会对“测试”这个词有意见,应把它看作是一个代码技术。用代码来检查变量的具体值,而不是手工检查那些感兴趣的变量。
只要有了单元测试,就让到他们自动运行,也就是每次编译或者构建代码的时候,就运行一次测试。把单元测试的结果看作是和编译器一样——如果测试没有通过,那就像变异没有通过一样糟糕。
接下来就是在后台假设一个构建机器,不断获取最新版本的源代码,然后编译代码,并运行单元测试,如果有任何错误它会让你及时知道,这是最容易修复也是成本最低的时候。
具体技巧
- 单元测试是优质股,值得投资。但一些简单的属性访问方法或者价值不大的方法,是不值得花费时间进行测试的。
- 人们不编写单元测试的很多借口都是因为代码中的设计缺陷。通常,抗议越强烈,就说明设计越糟糕。
- 单元测试只有在达到一定测试覆盖率的时候,才能真正地发挥作用。你可以使用一些测试覆盖率工具,大致了解自己的单元测试的覆盖情况。
- 不是测试越多质量就会越高,测试必须要有效。如果测试无法发现任何问题,也许它们就是没有测试对路。
先用它再实现它
我们的业务是要创造出能调用的API和可以使用的接口。这就是说,你在说服其他人使用它之前,先得让自己切实地使用这些接口。事实上,在你刚做完设计但还没有完成后面的实现的时候,应该使用它。这个可行吗?
Write test before writing code.
使用被称为TDD(Test Driven Development,测试驱动开发)的技术,你总是在有一个失败的单元测试后才开始编码。测试总是先编写。通常,测试失败要么是因为测试的方法不存在,要么是因为方法的逻辑还不足以让测试通过。
先写测试,你就会站在代码用户的角度来思考,而不仅仅是一个单纯的实现者,这样做是有很大区别的,你会发现,因为你自己要使用它们,所以能设计一个更有用、更一致的接口,除此之外,先写测试有助于消除过度复杂的设计,让你可以专注于真正需要完成的工作。
消除那些还没有编写的类,这会很容易地简化代码。相反,一旦你已经编写了代码,也许会强迫自己保留这些代码,并继续使用它,即使代码已经过期作废很久了。
Good design doesn’t mean more classes.
当你开发设计面向对象系统的时候,可能会迫使自己使用对象,有一种倾向认为,面对对象的系统应该由对象组成,我们迫使自己创建越来越多的对象类,不管他们是否真的需要。添加无用代码总是不好的想法。
具体技巧
- 不要把测试优先和提交代码之前的测试等同起来。测试先行可以帮助你改进设计,但你还是需要在提交代码之前做测试。
- 任何一个设计都可以被改进
- 你在验证一个想法或者设计一个原型的时候,单元测试也许并不适合。但是,玩意这些代码不行仓促演变成了一个真正的系统,就必须要为它们添加测试(但是最好能重新开始设计系统)。
- 单纯的单元测试无法保证好的设计,但它们会对设计有帮助,会让设计更加简单。
不同环境,就有不同问题
也许,你会要求测试团队在所有支持的平台上进行测试。如果它们是手工进行测试,可能并不是最可靠的测试办法。我们需要更加面向开发者的测试办法。
你已经编写了单元测试,测试你的代码。每次在修改或者重构代码的时候,在提交代码之前,你会运行测试用例。那么现在所要做的,就是在各种支持的平台和环境中运行这些测试用例。
Automate to save time.
但是,也许你已经有时间压力了,因此,你怎么可能有时间在多个平台上运行测试呢?这就要靠持续集成来拯救了。我们在前面的保持可以发布中学过,用一个持续集成工具,周期性地从源代码控制系统中取得代码,并运行代码。如果有任何测试失败了,他会通知相关的开发者。通知方式可能是电子邮件、页面I、RSS Feed或者其他一些新颖的方式。要在多个平台上测试,你只要为每个平台设置持续集成系统就行了。当你或者同事提交了代码,测试会在每个平台上自动运行。
具体技巧
- 硬件比开发人员的时间便宜。但如果你有很多配置,要支持大量的平台,可以选择哪些平台需要内部测试。
- 软件在很多平台上出现Bug很可能只是因为栈布局的差异、机器字大小端的不同所致。因此,即使用Solaris的用户比用Linux的少很多,你也仍然要在两个系统上都进行测试。
- 你不希望因为一个错误而收到5次通知轰炸(这就像是双重征税,会导致电子邮件疲劳症)。可以设置一个主构建平台或者配置,降低其他构建服务器的运行频率,这样在它失败的时候,你就有足够的时间来修复主构建平台。或者汇总所有错误报告信息到一个地方,进行统一处理。
自动验收测试
关键业务逻辑必须要独立进行严格的测试,并且最后需要通过用户的审批。但你也不可能拉着用户,逐一检查每个单元测试的运行结果。实际上,你需要能自动比较用户期望和实际完成的工作。
有一个办法可以使验收测试不同于单元测试。你应该让用户在不必学习编码的情况下,根据自己的需要进行添加、更新和修改数据。你有很多方法来实现它。
FIT,即集成测试框架,它很实用,可以更容易地使用HTML表格定义测试用例,并比较测试结果数据。使用FIT,客户可以定义带有新功能的使用样本。客户、测试人员和开发人员(根据样本)都可以创建表格,为代码描述kennel的输入和输出值。开发人员会参照带有正在开发的代码结果的FIT表格中的样本编写测试代码。测试结果成功或者失败,都会显示在HTML页面中,用户可以很方便地查阅。
如果领域专家提供了业务的算法、运算或者方程式,为他们实现一套可以独立运行的测试。要让这些测试都成为测试套件的一部分,你会在项目生命周期中确保持续为它们提供正确的答案。
具体技巧
- 不是所有客户都能给你提供正确的数据。如果它们已经有了正确的数据,就根本不需要新系统了。
- 你也许会在旧系统中发现以前根本不知道的bug,或者以前不存在的真正问题。
- 使用客户的业务逻辑,但是不要陷入无边无际的文档写作之中。
度量真实的进度
时间的消逝可以证明:判断工作进度最好是看实际花费的时间而不是估计的时间。
我们不应该去计算工作量完成的百分比,而应该测定还剩下多少工作量没有完成。
在你最后真正完成一项任务时,要清楚知道完成这个任务真正花费的时间。奇怪的时,它花费的时间很可能要比最初估计时间长。没有关系,我们希望这能作为下一次的参考。在为下一个任务估计工作量时,可以根据这次经验调整评估。你的评估会波动一段时间,但随着时间但推移,你但评估会与事实接近,你也会对任务所花费但时间有梗清楚的认识。
如果能一直让下一步工作时可见的,会有助于进度度量。最好多做法就是使用待办事项backlog。当添加新任务的时候,先排列它们的优先级,然后加入到待办事项中。你也可以有个人的待办事项、当前迭代的待办事项(工作项)或者整个项目的待办事项(项目进行阶段)。
具体技巧
- 6分钟作为一个时间单位,它的粒度太细了,这不是敏捷的做法。
- 一周或者一个月的时间单元,它的粒度太粗了,这也不是敏捷的做法。
- 关注功能,而不是日程表。
- 如果你在一个项目中花费了很多时间来了解你所花费的时间,而没有足够的时间进行工作,那么你在了解你所花费的时间上花费的时间就太多了。听懂了吗?
- 一周工作40个小时,不是说你就有40个小时的编码时间。你需要减去会议、电话、电子邮件以及其他相关活动的时间。
倾听用户的声音
It is a bug.
当出了错误,你要尽可能地提供详细信息。黑屏和含义不明的退出按钮说很不友好的行为。更糟糕的是,在得到用户反馈的时候,还嘲笑用户愚蠢,而不去真正地解决问题。
不管它是否是产品的bug,还是文档的bug,或者是对用户社区理解的bug,它都是团队的问题,而不是用户的问题。
我们花费了很大的精力从单元测试之类的代码中获得反馈,但却最容易忽略最终用户的反馈。你不仅需要和真实用户(不是他们的产品经理,也不是业务分析师之类的代理人)进行交谈,还需要耐心地倾听。
即使他们说的内容很傻!
具体技巧
- 没有愚蠢的用户
- 只有愚蠢自大的开发人员
- “它就是这样的。”这不是一个好的答案。
- 如果代码问题解决不了,也许可以考虑通过修改文档或者培训来弥补。
- 你的用户有可能会阅读所有的文档,记住其中的所有内容,但也可能不会。