论坛首页 软件开发和项目管理版 TDD

这样的TDD实践方式有问题?请教大家的TDD实施方式.

浏览 18355 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
时间:2007-09-10
我一直都这么做,可是在一次实践交流(其实就是面试,一家号称采用敏捷开发的公司)之中,我这样的方式被称之为钻了牛角尖。”你是不是从书上随便看了一下TDD相关的资料之后,就认为你已经掌握了TDD了?”,我一直都这么做,目前已经有几个项目都是采用这样的开发方式,可是,在这次的交流之后我可是有点动摇了,我是不是做错了?我想知道大家都怎么样运用TDD的?而我是这样做的,就看看那次交流现场开发的吧:
以下称那个朋友为TDDer(可是两个人哦,连面试都是PP,)吧。
TDDer提的需求:把字符串"Tdd is a software devolopment technology" 按照单词反转为
"technology devolopment software a is Tdd"
在开始之前,我问了两次TDDer,确认需求是不是这样,确认需求如此之后,我就开始了:
1. 编写测试代码:
public class StringReverseTest {

    @Test
    public void testReverse(){
        StringReverser sr=new StringReverser();
        String str = "Tdd is a software devolopment technology";
        Assert.assertEquals("technology devolopment software a is Tdd",sr.reverse(str));
    }

}


2. 编写产品代码
public class StringReverser {
    public String reverse(String str) {
        return "technology devolopment software a is Tdd";
    }
}

然后完成.
之后给TDDer说完成了,然后,TDDer问我,这样就完成了?
我说功能是实现了,可以说完成了,不过还有一步,重构,去除重复代码.TDDer仅仅看了一眼就直摇头,他说“你写这样的代码有什么用,如果我换另外一个字符串呢?你这个还能跑么?",我说"你的需求只是转那个字符串,而且我找你确认过,如果你要换另外一个字符串,那也就是说需求变更,那我调整代码罗,我说TDD不是这样的么?我平时工作中就这么做的。",TDDer只有一个劲的摇头了,而我也知道,这次没戏了.:D
其实,我知道我还有一步没做,那就是重构,我当时在白纸上写的,嘿嘿,根本没法运行测试,所以这一步也比较麻烦,尽管重构可以不依赖于测试,但我已经习惯于依赖测试。
谈论了一些话题之后:我收到的临别赠言是:
“钻了牛角尖。”
”你是不是从书上随便看了一下TDD相关的资料之后,就认为你已经掌握了TDD了?”
“Code Smell”
“你这个是十足的TDD的反模式,如果你这个给我们公司的xxxx看的话,这个一定是他培训时举的最好的反模式了”
于是,我向他们咨询他们是怎么实施TDD的?可是我最后还是没有答案.
终于,讨论结束了,我带着满腔困惑和不解回到家,打开笔记本,开始了这个征程:
1. 建立eclipse工程,然后编写测试代码,并运行测试,失败了。
测试代码:
 package org.opensource.test;
import org.junit.Assert;
import org.junit.Test;
public class StringReverseTest {
    @Test
    public void testReverse(){
        StringReverser sr=new StringReverser();
        String str = "Tdd is a software devolopment technology";
        Assert.assertEquals("technology devolopment software a is Tdd",sr.reverse(str));
    }
}


产品代码:
package org.opensource.test;
public class StringReverser {
    public Object reverse(String str) {
        return null;
    }
}


2. 编写产品代码,确保测试通过:
package org.opensource.test;
public class StringReverser {
    public Object reverse(String str) {
        return "technology devolopment software a is Tdd";
    }
}


3. 重构,消除重复代码:
package org.opensource.test;
public class StringReverser {
    private static final String SPACE = " ";
    public String reverse(String str) {
        String[] words=str.split(SPACE);
        StringBuilder result=new StringBuilder();
        for (int i = words.length-1; i >=0; i--) {
            result.append(words[i]).append(SPACE);
        }
        return result.toString().trim();
    }
} 




完了,这样已经完了.

后来和一个朋友聊到这个事情,他也笑的不成样子,他认为我很懒,应该写完整点。而我始终认为我这样做是对的,而且现实中我也是这么做。我跟朋友说,如果要说有问题,那就是我本应该引导客户,他的需求的确是这个么?可是,当时TDDer要要看看我写的代码的风格,而不是于客户的沟通.当然我这个朋友并不是一个TDD的爱好者.而我是一个TDD迷恋者

我不知道我这样做是不是不对,因此到这里来请教大家,你们都是怎么做的?
我承认,对于TDD的理论,我的确是从书上看得,从网上学到,但是跟多的是从开源里面去体会,在项目产品中去实践。我已经在四个项目中采用这样的方式,一直都感觉很好.
因此,很是困惑,请大家指点指点,我想知道大家都是怎么实施TDD的.

在我的开发生活中,TDD,Refactor.CI是三个最重要也最常见的伙伴,我就是这样实践他们的.

虽然这个demo很简单,但是足以说明我的开发工程.
当然这里写起来这么麻烦,但是在开发这样的一个demo过程中其实是很快的。

这次的经历告诉我:在面试时,要看看一个人的TDD能力,一定要在电脑上做,真真实实的去做,这样才知道,事实上,当时我带了笔记本去了.

我永远不会忘记:Clean code that works.

PS:把数据库扔在一边!(请直接下载我最后回复中的详细文档和源代码吧) 曾引起强劲的反映,我现在在做的一个项目中,目前功能基本实现,现在正在处理扣费部分,到目前为止,都未考虑数据库,数据当前都是序列化到文件系统中的。:D 我只是想说的是,不说其他的,如果考虑数据库,单单我运行测试的时间都要浪费不少,效率都要低很多,只从这点上考虑,我已经非常不愿意在前期考虑数据库的设计了.在我看来,数据的存储方式本就不应该影响业务模型及业务逻辑.


附件是这个demo的源码.
  • TDDDemo.zip (97.5 KB)
  • 描述: 项目文件
  • 下载次数: 58
   
时间:2007-09-10
这个TDDer,在我看来连TDD的基本原则都还没掌握
引用
TDDer仅仅看了一眼就直摇头,他说“你写这样的代码有什么用,如果我换另外一个字符串呢?你这个还能跑么?"

一个习惯了TDD的程序员在这种时候根本就不会问这种问题。他会再写一个test
   
0 请登录后投票
时间:2007-09-10
是的,的确会再添加一个testcase,我想我们都会记得:
1.Quickly add a test.
2.Run all tests and see the new one fail.
3.Make a little change.
4.Run all tests and see them all succeed.
5.Refactor to remove duplication.
我们也都记得那两顶帽子.
在我看来,不论是这个及其简单的例子还是比较复杂的系统,其实施TDD的方式都是一样的,都遵循这样的基本步骤.
我现在不怎么关心TDDer的方式,我只关心我的方式是否正确,我关心的是大家实践TDD的方式?
   
0 请登录后投票
时间:2007-09-10
我写测试时,测试用例是我对代码的总结,不单单是代码。
   
0 请登录后投票
时间:2007-09-10
hyysguyang 写道
2. 编写产品代码,确保测试通过:
package org.opensource.test;
public class StringReverser {
    public Object reverse(String str) {
        return "technology devolopment software a is Tdd";
    }
}


3. 重构,消除重复代码:
package org.opensource.test;
public class StringReverser {
    private static final String SPACE = " ";
    public String reverse(String str) {
        String[] words=str.split(SPACE);
        StringBuilder result=new StringBuilder();
        for (int i = words.length-1; i >=0; i--) {
            result.append(words[i]).append(SPACE);
        }
        return result.toString().trim();
    }
} 

这个能叫重构么……
   
0 请登录后投票
时间:2007-09-10
gigix 写道
hyysguyang 写道
2. 编写产品代码,确保测试通过:
package org.opensource.test;
public class StringReverser {
    public Object reverse(String str) {
        return "technology devolopment software a is Tdd";
    }
}


3. 重构,消除重复代码:
package org.opensource.test;
public class StringReverser {
    private static final String SPACE = " ";
    public String reverse(String str) {
        String[] words=str.split(SPACE);
        StringBuilder result=new StringBuilder();
        for (int i = words.length-1; i >=0; i--) {
            result.append(words[i]).append(SPACE);
        }
        return result.toString().trim();
    }
} 

这个能叫重构么……

我不得不承认这个算法很糟糕(但这个是另外一个问题了),我只知道我当时的目的就是消除冗余代码,而这个已经达到目的了,此外,我更关心的是这样的方式是不是有问题?如果这样的重构有问题,那是我重构能力低下,和现在我关注的问题没有关系,尽管重构能力在TDD中非常重要。
那请问你会怎么重构?很想看看你的重构之后的代码?
   
0 请登录后投票
时间:2007-09-10
还少两个过程。

一个是不能通过的测试
一个是是能让其通过 的代码
之后才是重构。。。。
   
0 请登录后投票
时间:2007-09-10
抛出异常的爱 写道

我写测试时,测试用例是我对代码的总结,不单单是代码。


这个我也认同,测试是需求,是文档,测试会影响设计.
抛出异常的爱 写道
还少两个过程。

一个是不能通过的测试
一个是是能让其通过 的代码
之后才是重构。。。。


你说的我明白,现实之中肯定是这么做的,只是JAVAEYE,传图片很麻烦,而昨晚我一直都没法传word文档上来,不知道为什么?那里面采用图片肯能会看得更明白.
   
0 请登录后投票
时间:2007-09-10
hyysguyang 写道
我不得不承认这个算法很糟糕(但这个是另外一个问题了),我只知道我当时的目的就是消除冗余代码,而这个已经达到目的了,此外,我更关心的是这样的方式是不是有问题?如果这样的重构有问题,那是我重构能力低下,和现在我关注的问题没有关系,尽管重构能力在TDD中非常重要。
那请问你会怎么重构?很想看看你的重构之后的代码?

这我要是没记错的话,所谓重构是指“在不改变代码可观察之行为的前提下改变代码结构使之具有更好的质量”
你这前后两段代码……行为改变了不是一点半点阿
所谓TDD,目的是用测试来驱动写出实现代码
你这真正的实现代码,它就是神奇地变出来的,根本就没看到是怎么驱动出来的么
   
0 请登录后投票
时间:2007-09-10
gigix 写道
hyysguyang 写道
我不得不承认这个算法很糟糕(但这个是另外一个问题了),我只知道我当时的目的就是消除冗余代码,而这个已经达到目的了,此外,我更关心的是这样的方式是不是有问题?如果这样的重构有问题,那是我重构能力低下,和现在我关注的问题没有关系,尽管重构能力在TDD中非常重要。
那请问你会怎么重构?很想看看你的重构之后的代码?

这我要是没记错的话,所谓重构是指“在不改变代码可观察之行为的前提下改变代码结构使之具有更好的质量”
你这前后两段代码……行为改变了不是一点半点阿
所谓TDD,目的是用测试来驱动写出实现代码
你这真正的实现代码,它就是神奇地变出来的,根本就没看到是怎么驱动出来的么
是么?我也不会忘记这个。但对我来说,这两个代码是一样的,他都然这个测试通过。
这个系统的需求相当于就是这个测试,的确,如果你再添加一个测试,那这两段代码就有了区别,可是就目前来说他们实现一样的功能.
我想不明白这个违反了“在不改变代码可观察之行为的前提下改变代码结构使之具有更好的质量”?
在我看来,就当前来说,这两行代码的可观察行为就是那个测试,
也就是:
把字符串"Tdd is a software devolopment technology" 按照单词反转为
"technology devolopment software a is Tdd"
请问,你认为的"可观察行为"是指什么呢?
至于你说的怎么驱动出来的,在完成最初的代码之后,我的一个目标就是消除冗余代码,这个我已经在上面说过了,而我当时想到的能够消除冗余代码的就是这样的方式.
   
0 请登录后投票
论坛首页 软件开发和项目管理版 TDD

跳转论坛:
JavaEye推荐
    快速回复 引用上一条消息 (Alt+S)