一次TDD(Test Driven Development)尝试感受

TDD系列

Posted by Bruce Wong on February 24, 2022

TDD作为被证实的最有效的软件研发工程实践之一,也是很多团队心里认可但是很难落地执行的一项实践。到底有哪些因素是落地的阻力需要我们考虑。同时有哪些可以尝试的可行方案呢?最近作为技术敏捷教练,我在一个团队中尝试做了一次TDD的尝试。结合自己的感受在这里和大家分享一下。
本次的功能是实现一个Excel的生成功能,根据业务需求支持各种单元格合并逻辑。数据列和数据内容会根据业务需求变化。效果如下图:
demo report

我把练习的代码放到了我的代码库中,兴趣的小伙伴可以访问我的github:
https://github.com/BruceWong001/GenerateExcelReport

最直接的感受

  • 代码足够精简,只为了开发的功能够用。但是并不代表没有设计,因为当一段代码可测的时候他必定会涉及一些设计。
  • 引导思考逻辑设计,同时避免过度设计。就拿这次举例,一开始动手前想过很复杂的对象来实现。TDD之后先实现了简单的导出表格和合并单元格。之后才是考虑如何通过组合这两个基本方法来实现复杂逻辑。
  • 一些参数的使用会因为为了方便测试而调整。例如文件路径作为参数,改为外围传递流对象,并由外围控制生命周期。这种设计最开始的初衷竟然是因为这样才方便测试,我可以传入内存流而不是实际的文件流。
  • 当不知道如何写代码的时候,将功能拆分成若干个基础简单的测试,然后想办法通过每一个测试,最后你会发现你的功能就做出来了。

带来的额外好处

  • 代码覆盖率在不知不觉中变高,因为你的逻辑都是在测试中增加的。而不是后补充。
  • 每次修改都有信心保证不破坏已有逻辑。一个真实的例子:当这次改动的部分在Sonar扫描后需要重构降低代码复杂度的时候,QA第一反应是是否需要全部重新测试,而此时开发已经能从容地说不需要。只需要重构后他们保证所有的单元测试pass就可以了。
  • 代码审查在平时的结对工作中自然进行,无需单独安排时间。
  • 不同开发彼此学习不同的思考和编程思维方式,会有更多的成长。

落地时需要注意的地方

  • 遇到实际业务复杂的情况,无从下手的时候,首先先考虑抽象成若干简单逻辑,之后写成单元测试。
  • 选择相对和业务逻辑关系不大的部分进行尝试,基于现有架构小步尝试。
  • 员工因为不熟练单元测试的写法无从下手;另外测试先行的方式不如直接写代码来的舒服,在一定时间内做完功能代码的编写,会更有安全感,即使可能根本不知道写的code是否覆盖了所有业务逻辑。所以工作完成时间的宽松程度是能否在团队内推行TDD的一个主要因素。
  • 结对编程其实是在做同行评审,如果心态无法摆正,压力会很大。会遭遇抵制,因为不希望别人对自己的指指点点,特别是现场编写的时候。

小贴士

  • Unit Test永远验证最简单的业务逻辑,如果不能就尝试拆分成多个Unit Test。
  • 一定要调整心态,始终抱着学习的心态。这样在结对过程中才能够接受不同的思考方式,从中学到对自己有用的。而不是一味地挑毛病和抱怨。
  • 用匠心精神来要求自己。保持精益求精的精神才能持续的优化修改,在写测试->红灯->调整->绿灯的循环中优雅的前行。
  • 不要求大,每次调整都是从小步开始。有整体的设计思考但是落笔仍然是从小的尝试开始。这有助于持续积累信心,并能够更快的发现设计与实际情况的不同点,也更容易调整。
  • 单元测试需要通过实际编程练习来让大家感受和体验。最好采用单独的“代码道场”等实操工作坊。如果是直接在Team迭代中尝试,教练最好和Team结对进行。
  • 如果教练不熟悉当前team的实际业务,最好是选择和业务关系较弱的Common功能作为着手点。否则教练在结对过程中只能是Reviwer的角色,实操是团队成员。这种效果会减弱,同时耗时会比较长,容易增加团队成员的任务压力和抵触。