小步慢走: 如何分解?

小步慢走通过将一大步转化为一系列的小步,一步一个脚印。每次只关注当前这一步,使得每一步变得容易简单,易于控制,降低出错概率; 另一方面即使出错,问题也不大,容易回退。 这样步子小,出错少,返工少,反而效率更高,所谓慢就是快。

小步慢走

小步是一个相对概念,对每一个人理解都不一样,也难于统一,在软件开发过程更是这样子。为了更好的理解什么是小步,那么我们先看看什么是大步? 下面的例子,是否似曾相识

1. 编译长时间没有通过。

2. 单元测试红灯一直亮着。

3. 发现思路错了,想回退,不知道从哪里开始。 如果直接revert 太可惜。

4. 修改代码,测试失败,想不错所以然来。

5.  常常需要IDE里面单步调试来定位错误。这个说明代码已经超出你的大脑容量,问题已经接近失控,需要借助工具来帮助。

6.. 出现regression, 推测不出来是哪里修改导致的, 或者刚改的哪一行代码。

这些都是步子太大的的问题。反之,如果将步子放小,每次改一点,甚至是几行代码,验证,再修改再验证,上面问题基本就可以解决掉。对自己而言这就是小步。大家可以自行感受一下。

如果要步子小,关键是如何将大步分解为小步。 常规软件里面的分解技术,比如水平层分解,垂直流程分解,内核加插件扩展分解,以及按照自治原则分解,如微服务。 这些的确可以将一个大问题,分解为一组模块;但是问题是模块还是太大,对于日常开发在类,接口,方法这个层面来说还是不够小。


下面介绍几种方法,更好的指导在代码级别分解:

1. 接口不变逐步生长

软件开发的很多时候是接口先定下来,然后再逐步完善功能。典型的是算法问题,输入输出很清晰,接口确定下来而且基本不会变。 比如N-皇后问题,输入是一个整数代表矩阵大小,输出是代表有多少种布局。接口很容易定下来而且是不变的。然后随着test case增加,有简单变的复杂,功能也一点点的增强。


随着测试用例增加,软件功能完善

比如8N后问题,可以这样分解:

基于这个分解的一个实现在,这里。如果想看实现过程,可以在这里回放  。 这个是用TDD实现,借助cyber-dojo这个工具可以回放修改代码的从过程。

另外一个例子,可以判断一个字符串是不是一个数字? 比如 1.2e5. 那么也可以分解为: 自然数,整数,浮点数,带有指数的浮点数。一个实现在这里。 

其实这个软件功能完善过程,如同软件有一个内核逐步长大,类似生长过程。也就是我们软件开发中的接口不变的增量开发。但是现实往往不是这么简单,接口在成长的过程也会发生变化。于是就有下面这个方法。

2. 先适应接口再增加新功能。

有些时候,随着test case的增加,会发现已有的接口不是那么合适。 这个时候需要修改接口,才能再增加新功能。 这个和我们经常看到的增量开发演示图有点不一样。

增量开发,我们常常用下图表示。

想象中的增量开发


  但实际情况却是下面这样子的。为增加新功能而需要修改已有代码和接口。

实际增量开发

这条规则是指,添加新功能时如果接口不匹配,那么先修改接口使得接口匹配,然后再加入新功能。将一大步分为两步走,先是修改接口使得适应新功能,然后再增加新功能代码。


先修改接口再增加功能(一大步变两小步)


  3. 测试代码和生产代码不同时修改

TDD标准开发流程中每次迭代是先添加新测试用例,这时代码或编译不通过或者测试不通过;再添新加代码,使得编译通过,测试通过; 然后重构;完成一次迭代反馈,然后进行下一次循环;这里面其实隐藏着一条规则,就是修改测试代码的时候,不修改生产代码;修改生产代码,不修改测试代码。如下图:

测试和代码不同时修改

如果同时修改,那么到底是代码的错还是测试的错呢?每次只修改测试代码或者生产代码,如果出错,那么肯定是刚修改的代码导致的,很容易找打问题。步子小好定位。


        规则2 和规则3经常在一起使用的。 如果已有的代码是A,对应测试集合是TA。 现在要增加新功能使得软件功能变为(B,TB), 也就是软件从一个状态变到另一个状态,即(A, TA) ----> ( B , TB)。 那么应该怎么做?

(A , TA) 初始状态

  (A1, TA) 修改接口A为A1,为添加B功能做准备. 测试集TA没有变化保证新接口以及修改的代码不会对已有功能产生副作用。

(A1, TA1)修改测试代码,使得调用新接口;

                    这个时候代码A1,同时保留接口和新接口

  (B, TA1)删除旧的接口, 这是代码应该已经完全转换到新接口,即接口由A转到B

(B, TB)为新功能B,添加新的测试用例TB

(B1, TB)添加代码,通过新测试。此时状态转换完毕。

4. TDD 黄金法则:

Uncle Bob 提出来TDD的开发原则:

You are not allowed to write any production code unless it is to make a failing unit test pass.

1、除非为了使一个失败的unit test通过,否则不允许编写任何产品代码

You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.

2.在一个单元测试中只允许编写刚好能够导致失败的内容(编译错误也算失败)

You are not allowed to write any more production code than is sufficient to pass the one failing unit test.

3、只允许编写刚好能够使一个失败的unit test通过的产品代码

这个所谓小步慢走的极限目标,也就是增量实现的终极方式。 但是实际中却很难做到,很难做到如此精细分解的粒度,而且也难于衡量(什么是刚好),也没有考虑到重构。 应该根据自己的实际情况,步子尽可能小,理想状态是一切都在掌握之中的感觉,才是恰到好处小步。而不是刻意追求这个过程,为了小步而小步而导致忘记初心。

下面两个工具,可以帮你刻意练习。 

1. cyber dojo。 这是一个TDD在线练习的工具。每次运行代码的时候才保存代码。  当完成时,可以回放自己的代码修改过程。 用交通灯显示每次修改后代码的状态; 用黄色灯代表编译没通过,红色代表测试失败,灰色代表测试运行超时,绿色代表测试通过;记录下来后,就可以用来可视化回放构建过程。 如果一直黄灯,步子太大,编译没通过;一直红色,测试不通过,测试粒度太大; 同样还记录下来每次提交的时间,黄红绿之间的切换,可以看到自己的编码节奏。 这样可以直观发现一些问题? 哪些步子迈的太大,可以再一次分解,哪些做的好的。通过再次审视,回顾,分析,总结;工具简单但是刻意练习的利器。


用cyber-dojo回放构建过程

2.git-timer, 就是一个刻意练习的工具。 工作原理简单,git-timer 监控git repository,在一定的时间间隔检测代码(比如5分钟), 如果编译测试没有通过,强制revert 代码; 如果编译测试通过,强制提交代码;然后重新计时。 如果代码被revert掉 ,说明你的步子太大,将刚才的步骤细化,再来一次。 这样的机制强制你小步慢走,同时按照一定的频率慢走;

git-timer 练习开发的节奏





下一篇预告: 分解的原则 不重不漏;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容

  • 本文结构: 什么是 TDD 为什么要 TDD 怎么 TDD FAQ 学习路径 延伸阅读 什么是 TDD TDD 有...
    李浪溪_WaterLee阅读 74,137评论 16 168
  • 做TDD是为什么? 关于TDD的概念、工具、技巧等,经典的书籍材料可能介绍的更为全面细致。这篇文章想分享的是从一个...
    武可阅读 2,579评论 2 21
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,497评论 18 139
  • 德国啤酒在国内比较流行,人们喜欢直接用颜色区分不同的品种,比如红、黄、白、黑。其中白啤,指的就是小麦啤酒。 正宗的...
    渔人精酿阅读 1,025评论 0 0
  • 装饰器 decorator类装饰器 带参数的装饰器 举例(装饰器函数;装饰器类;有参与无参) https://fo...
    idri阅读 336评论 0 0