内容概括
本章是一个结对编程的故事,讲述以测试驱动开发的方式从零开始实现一个保龄球计分的小程序。本章的内容大部分是代码,但是一点也不枯燥,因为其中穿插着两位大神的思考和交流,使得整个过程非常有意思。
心得
-
在未了解事情的真相之前,保持中立
第一遍读本章内容的时候,我是看的晕头转向的,我不能因此判断本章写的不好。在本章的开头作者已经提示本章的末尾有保龄球的比赛规则介绍,我并没有理睬这善意的提示。当我阅读完保龄球的计分规则后,再回过头来阅读本章的内容,整个人豁然开朗了,看大神们写代码是一种享受。
-
在实现一些类似计分程序之前,需了解其背后的规则
保龄球计分程序这类程序是对真实生活场景的模拟,如果我们在不了解背后规则的情况下完全是无从下手的。程序是对真实场景的抽象。
-
明确输入与输出
明确一个程序的输入与输出是非常重要的。输入是:需要被处理的原始数据;输出是:最终想要的结果。测试驱动开发中的所有测试用例(如下面的代码 code-1 所示)都是先给定输入,然后验证实现过程能不能得到想要的结果。
两位大神在保龄球计分程序的实现过程中,并没有按照最初设计的 UML 思路走。他们在写测试用例的时候发现最初的设计是行不通的。
// code-1 public void testAddOneThrow() { Frame f = new Frame(); f.add(5); assertEquals(5, f.getScore()); }
-
根据使用场景来决定是否对一些异常进行处理
在保龄球比赛中,一次投掷击倒的木瓶数是不会超过 10,也不会小于 0 的。这是否着意味着我们需要对录入的数据进行一个范围的判断呢?作者告诉我们是不需要这样做的,因为计分程序只有一个人使用,而不是会被很多人使用。
-
特殊情况留在最后搞定,以免从开始就陷入死胡同
比如:在保龄球计分程序中,补中和全中的计分规则是特殊的,应该留在最后去处理。
-
先将功能实现,再考虑重构
两位大神是在保龄球计分程序的功能基本实现成功后才开始对整个代码进行重构的。如果在功能实现的过程就考虑代码要符合各种原则,这是非常痛苦的。一个可运行的程序是最重要的,其次再是考虑代码是否人性化。
-
排除副作用
// code-2 score += itsThrows[ball++] + itsThrows[ball++];
在 code-2 中 score += 和 两个增量操存在副作用,可能会因为运行环境的不同出现不同的结果。在编写代码的过程中,应该尽量避免类似的代码。
-
测试用例要考虑各种边界情况
在保龄球计分程序的测试代码中,基本包含了所有可能的场景。如果有些场景没有考虑到,那么当一些情况发生后程序是不可用的。
-
结对编程能极大地避免当局者迷
一个人在思考问题的时候难免会陷入当局者迷的状态,当多个人思考同一个问题的时候,这样的情况就会少很多。在我们平常工作中虽然很难完全做到结对编程,但是我们可以做到多和他人进行交流,以避免陷入固定思维。
-
大神是真大神
大神的最终版保龄球计分小程序没有一行多余的代码,代码中不需要任何注释(做到了传说中的代码即注释)。