那一晚,我梦见自己的代码有个 Bug

我与 TDD/BDD 不得不说的故事,第一篇。

单元测试的觉醒

那一年我还年轻,刚入行没几年也没有白头发。

在一个夜黑风高的凌晨,写了一天代码的我若梦若醒,兴奋的大脑还在检查和推敲自己的代码是否有问题。

突然我想到一个场景,在某个特定的输入下,我的代码的输出并不是如我所愿。我瞬间清醒,两眼一睁又掐指一算,果然,是个 Bug。

早上我迫不及待地来到公司,打开电脑,看着屏幕上映着的那双布满血丝的眼睛,有点生气:这特么还让不让人睡觉了?

我转念一想:“验证我的代码对不对”这件事,明明可以用电脑来完成,我却要牺牲睡觉时间用我的大脑来完成,这就是明明工资比我高的原因?

于是我心生一计,干嘛不把凌晨才想到的场景,以及之前想到的其它场景,用网上看到的所谓“单元测试”写下来,每天下班前把这些单元测试一跑,不就可以安心睡大觉了吗?

这是一个改变我码农生涯的伟大的一天。从此,我变成了一个有思想的码农。

注解
两点体现了该码农的思想:

  1. 对单元测试有内在渴望;而不是依赖公司的要求写单元测试。
  2. 不断补充单元测试用例,以及每天下班前跑单元测试,这不就是持续集成吗?

有思想的前提是有素质。该码农基本素质有:

  1. 自己写的代码自己负责,绝不交给 QA 负责。
  2. 自己没测完,代码就算没写完。

测试先行

开始写单元测试之后,最大的收获是自信了:单元测试告诉我,我写的代码是可工作的。

也更淡定了:如果有 Bug,一定是某个场景被遗漏了,补一个单元测试就好了。慌毛?

但是我不满足,我想:为什么我要写完代码再去想那些场景呢?

仓央嘉措告诉我:理解需求之后,我写或不写代码,那些场景就在那,不舍不弃,不增不减。

那么我在写代码之前,就把那些场景分别用例子列下来,不是让我写代码时更下笔如有神吗?

这是让我的码农生涯 Great Again 的一天。从此一位叫做 Kent Beck 的大牛,开始走进了我的生活。

注解
至此,该码农悟到了写代码的几个精髓:

  1. 需求 = 测试。把需求分解成几个场景,然后实例化这些场景,它们就成为了测试用例。(那时 Spec by Example 这个词还没出现。)
  2. 既然“需求= 测试”,那么完全可以测试先行,走在代码前面。

测试驱动开发

一开始,我的方法是这样的:

  1. 把主要的用例写在纸上。
  2. 写代码。
  3. 把纸上的用例写成单元测试。

慢慢的,对于复杂的逻辑代码,这种方式开始遇到问题:写完代码后,单元测试写起来很费劲,因为场景太多,都覆盖的话单元测试之间不少重复代码。不覆盖的话,我是那没素质的人吗?

于是,我稍作调整:代码未全部完成时,就先写几个单元测试,看如何重构代码让单元测试写起来更轻松。

这就是勉勉强强懵懵懂懂恍恍惚惚的 TDD 了。实践了一段时间后,在某一年春节回家的火车上,我带上了一本宗师 Kent Beck 的《测试驱动开发》,看看这位元芳是怎么看的。

这本薄薄的小书,歪歪斜斜的每页上都写着“测试驱动开发”这六个字。我在火车上横竖睡不着,仔细看了半夜,才从字缝里看出字来,满本都写着两个字是“智慧”。

大师写一个 TDD 循环的步伐非常小,小到让人不服:有必要吗?就这么点逻辑,我欻一下全写出来了,你非得一点一点挪?就这还大师?

但我毕竟是一个有思想了好几个月的码农了,我放下身段,反复揣摩,终于领悟到了大师的智慧:小(步伐),是一种能力。

大算个屁,谁没大过,可你小过吗?

注解
我读到的 Kent Beck 的智慧:

  1. 小步伐是一种刻意练习。随着水平上涨,步伐可以越来越大,但你得有小的能力。
  2. 拆解 Task 到几分钟的粒度,是程序员的核心能力,甚至没有之一。
  3. 重构不是吃饭,饿了才吃;重构是呼吸。

它们是那么质朴,平淡无奇,可是鲜有人做到。如果程序员有幼儿园,我认为这些都是幼儿园要教的五讲四美。

待续

TDD 打开了一扇门。接下来碰到的问题是:代码是要维护的,测试代码也是代码,随着测试代码越来越多,如何避免我的维护成本也越来越大?

或者抽象点说:

  1. 如何让代码可测?
  2. 如何让测试可读?

下回分解。

你可能感兴趣的:(那一晚,我梦见自己的代码有个 Bug)