10/23日,我在部门内部进行了一次内部学习,使用目前流行的Coding Dojo(道场)方式,进行了TDD开发的演练。演练的题目如下:
 
 
有关Coding道场的介绍,请自行百度一下,我就不再多做介绍了。
 
从效果来看,基本达到了传达TDD是什么样的开发方式的目的。尤其是大家从最初满脑子如何实现这个程序,怎样去设计算法,逐渐转变为了先想如何测试,从最简单的实现开始,最终演化成最终的设计。当然,目前为止,参加人员也只是理解了TDD是一个什么样的开发方式而已,还谈不到真正使用TDD进行开发。这需要一个更加长期的自我训练和使用的过程。使用TDD,最主要的是一种思维方式的变化。
首先:要坚信所有的程序皆可测,如果不能测试,不是产品的特性导致,而是自己的能力不足导致,设计上有问题。因此必须从设计上加以改变,使得程序可测。如一般认为曲线的显示是否正常,是无法使用自动测试的。换个角度:如果显示只是一个数据-坐标的转换的话,测试的重点就变成了数据是否正确,而这一点是完全可测的。
其次:虽然需要全局的考虑,但是要从简单入手,演进式设计。
这一点,在本次道场演练中体现的就很明显,此次道场开始,很多人的想法就是,建立某种算法,将需要的字符显示出来。于是第一个函数就是:void DisplaySegmentDigital(String input),然后再写那些子函数。如何测试这个函数?这是一个输出到屏幕显示的函数,它只能用眼来判断,显然不适合自动测试或者单元测试。所以,TDD不是一个先实现框架,再实现具体功能的做法。输出到屏幕,只是最后的一个过程,也是一个简单的过程,因此可以不必作为重点。重点在于显示的数据是什么?所以,函数就变为了:String DisplaySegmentDigital(String input)。这个时候,这个函数不再是向屏幕输出,而是输出一个字符串,再由另外一个字符串显示函数完成向屏幕的输出。而原来这个函数就变得可测了。于是,第一个测试函数被写出来了:
String strText = "910"; String strTextResult = "._.|_|..|.....|..|._.|.||_|";  
String strOutput = digitalSegment.DisplaySegmentDigital(strText);   
assertEquals(strOutput , strTextResult);
第一个测试顺利通过,因为实现非常简单:
public String DisplaySegmentDigital(String strText) {
    return "._.|_|..|.....|..|._.|.||_|";
}
接下来的困难是:下一个测试什么?测试“3456”的输出?OK,我们先试试看,于是我们想写第二个测试:

String strText = "3456"; String strTextResult = "????????";

问题接着出来了:这串问号该填什么?这样测试真的有意义么?几乎所有的人都直觉得发现这里有问题。简短的讨论后,结论是应该测试每个数字的显示,而非一个字符串。于是,测试变为:

String strText = "9"; String strTextResult = "._.|_|..|";

String strOutput = digitalSegment.DisplaySegmentDigital(strText);

assertEquals(strOutput , strTextResult);

实现变为:

public String DisplaySegmentDigital(String strText) {

if(strText == "9")

return "._.|_|..|";

else

return null;

}

实现后,接着测试:

strText = "1"; strTextResult = ".....|..|";

strOutput = digitalSegment.DisplaySegmentDigital(strText);

assertEquals(strOutput , strTextResult);

实现也变为:

public String DisplaySegmentDigital(String strText) {

String[] strResult=new String[10];

strResult[0]="._.|.||_|";

strResult[1]=".....|..|";

strResult[9]="._.|_|..|";

return strResult[Integer.parseInt(strText)];

}

至此,很显然我们的算法也就自然而然的诞生了。可能与很多人自己开始的算法设计不太一样,但也不应该差到哪里:)。这就是TDD演进式设计。

但有个问题,._.|_|..|是什么东东?我怎么知道最终输出是正确的。因此,我们稍微改变了一下写法:

String strText = "9";   String strTextResult = "._." +
                                                                 "|_|" +
                                                                  "..|";

String strOutput = digitalSegment.DisplaySegmentDigital(strText);

assertEquals(strOutput , strTextResult);

strText = "1";

strTextResult = "..." +

"..|" +

"..|";

strOutput = digitalSegment.DisplaySegmentDigital(strText);

assertEquals(strOutput , strTextResult);

实现变为:

public String DisplaySegmentDigital(String strText) {

String[] strResult=new String[10];

strResult[0]="._." +

"|.|" +

"|_|";

strResult[1]="..." +

"..|" +

"..|";

strResult[9]="._." +

"|_|" +

"..|";

return strResult[Integer.parseInt(strText)];

}

现在直观多了。

为什么一定要变得直观,其目的不单纯是为了程序的易读性,更重要的是:测试不应该抄实现的代码,实现也不要抄测试的代码,否则后果很严重。写测试代码时,必须是含着测试的心态,含着使用者的心态去写测试代码,而非一门心思去想实现。如果这样,TDD就失败了。这也是为什么TDD要求先写测试代码,再写实现代码的原因。因为我们一旦先想到了实现,那么接下来的测试,必然会跟着实现的逻辑走,从而违背“测试独立性”的原则。实现发生错误,测试也无法发现。

接下来需要整理一下代码,显然DisplaySegmentDigital这个函数名不是那么准确,后来议论了一番,得出的名字是:GetDigitalDisplayContent。结束后,我想GetDigitalFont可能更好。

好了,有关第一次道场就写到这里,留一个小小的问题:到目前为止我们还没有设计显示的算法。为了便于输出,目前的设计如何改进?

Coding道场:第一次的更多相关文章

  1. Python全栈开发:冒泡排序

    #!/usr/bin/env python # -*- coding;utf-8 -*- """ 第一次对比:找到最大值,放到最后 对比是两两对比,对比的两个数组合共有l ...

  2. 软件工程 Coding.net代码托管平台 Git初学者的使用总结 五步完成 程序,文件,文件夹的Git

    一.前言 第一次用git相关的命令行,我使用的是Coding.net代码托管平台.Coding.net 自主打造的基于 Git 的代码托管平台,提供高性能的远端仓库,还有保护分支,历史版本分屏对比. ...

  3. Coding 及 git 的工程使用方法

        在过去的两周,同学们除了在学习 C 语言之外,还在学习如何利用 git 将自己的代码上传到 coding 中.也有大量的同学,成功的上传了代码.但是,实际上大部分同学的用法都不合理.这里,以一 ...

  4. C 语言学习 第一次作业总结

    第一次的作业是冯老师布置的练习题,需要在pta平台上完成.我这边看不到结果,但是透过冯老师给出的截图,同学们都还是认真的去做的.同时,我这边也布置了一个持续 3 周的作业:熟悉 git 的使用.因为后 ...

  5. Coding编译连接过程中遇到的问题及解决方法(iOS)

    Coding 上下载地址:https://coding.net/u/coding/p/Coding-iOS/git Github源码下载地址:https://github.com/Coding/Cod ...

  6. Coding源码学习第三部分(EaseStartView.m)

    首先接上篇的要做一个NSEnumerator 类的延展阅读. 枚举(NSEnumerator) (1)依附于集合类(NSArray,NSSet,NSDictionary),没有用来创建实例的接口. ( ...

  7. Coding源码学习第一部分(AppDelegate.m)

    前言:在此首先感谢开源,感谢大神们的无私分享. Coding 的主页:https://coding.net/app#app-feature Coding 自己家的仓库:https://coding.n ...

  8. 使用VS2010在Coding.net上进行代码托管

    网上有VS2010和Github结合使用办法,但是Github在国内使用太慢,本文使用相同的配置方法稍作改动让VS2010代码托管在coding.net平台上.由于只是稍做记录让自己不会遗忘,所以叙述 ...

  9. Coding Kata - 挑战你的“底线”

    Coding Kata简介 如何进行Kata练习 亲身感受 Coding Kata简介 前段时间听到一个比较有意思的概念叫做Coding Kata,今天试了一下来说说一些想法和思考.Kata是一个日语 ...

随机推荐

  1. 如何利用sendmail发送外部邮件?

    在写监控脚本时,为了更好的监控服务器性能,如磁盘空间.系统负载等,有必要在系统出现瓶颈时,及时向管理员进行报告.在这里通常采用邮件报警,同时,邮件设置为收到邮件,即向指定手机号码发送短信.这样可以实现 ...

  2. 【记录】GitHub/TortoiseGit 修改邮箱/提交者

    我使用 Git 客户端工具是 TortoiseGit,在提交更新的时候,不知何时起会出现下面这种情况: 正常提交作者信息显示应该是: 本来也没怎么注意,但是在提交历史中,记录就不显示出来了,也就是在首 ...

  3. 怎样录制屏幕并将结果保存为Gif

    怎样录制屏幕 并将结果保存为GIF 大前天写文章,需要把PPT的翻转页面截成动态图.我一开始就想到保存文件肯定是GIF.但是如何生成呢?素材又从哪里来?以前自己感兴趣做过把一组连拍的图片做成动态图,再 ...

  4. 让自己也能使用Canvas

    <canvas> 是 HTML5 新增的元素,可使用JavaScript脚本来绘制图形.例如:画图,合成照片,创建动画甚至实时视频处理与渲染. 兼容性方面,除了一些骨灰级浏览器IE6.IE ...

  5. PHP类的原理

    一.类的实现 类的内部存储结构: struct _zend_class_entry { char type; // 类型:ZEND_INTERNAL_CLASS / ZEND_USER_CLASS c ...

  6. Coreseek Windows下安装调试

    由于项目需要全文检索,后面就去网上查了下资料,找到了Sphinx[中文是狮身人面像]这个全文检索引擎,听说挺好用的,不过没有中文分词.后面又去找了一下,找到了Coreseek,一款中文全文检索/搜索软 ...

  7. Maven工程引入jar包

    Maven项目引入jar包的方法 法一.手动导入:项目右键—>Build Path—>Configure Build Path—>选中Libraries—>点击Add Exte ...

  8. ASP.NET实现微信功能(2)(服务号高级群发)

    前面写了一篇文章,关于微信的:http://www.cnblogs.com/kmsfan/p/4047097.html 今天打算来写本系列的第二批文章,服务号后台群发. 在写本篇文章之前,我们先来看看 ...

  9. [Java IO]06_JSON操作

    6.1 JSON 知识背景 6.1.1 JSON 简介 JSON: JavaScript Object Notation(JavaScript 对象表示法) JSON 是存储和交换文本信息的语法.类似 ...

  10. SQL Server基础之存储过程

      简单来说,存储过程就是一条或者多条sql语句的集合,可视为批处理文件,但是其作用不仅限于批处理.本篇主要介绍变量的使用,存储过程和存储函数的创建,调用,查看,修改以及删除操作. 一:存储过程概述 ...