写点什么

使用编码招式(Coding Katas)、BDD 和 VS2010 项目模板:第 I 部分

我很优秀,但我能变得更好吗?

  • 2010 年 11 月 17 日
  • 本文字数:0 字

    阅读完需:约 1 分钟

这一系列实践行为驱动开发的编码招式由 3 部分组成,由已故的 Jamie Phillips 撰写,他是波士顿敏捷社区和.NET 社区的知名成员。当我们看到这篇文章的首稿时,我们都迫切想要发布它,但在我们完成编辑工作前,他就去世了。在得到他妻子 Diana 的同意后,我们自豪地交付他最后的工作。

我很优秀,但我能变得更好吗?

使用编码招式、BDD 和 VS2010 项目模板

无论你的技术专长、知识和经验如何,总会有机会增强你自己的技能,成为编码道场(coding dojo)的黑腰带。通过使用编码招式来实践行为驱动开发,并实现一个新的 VS2010 项目模板,这可以磨练我们的技能,让我们变得更好。

这篇文章的三部分涵盖编码招式、行为驱动开发(BDD)以及 VS2010 中项目模板向导的话题,想带领读者进入我最近的一段发现之旅:即便已经编写了 8 年 C#代码,使用编码招式依然提高了我的技能。

第 I 部分:编码招式

对于任何指定的需求,当我们想去实现它、实际编码去实现设计时,即使是经验丰富的软件开发人员,也总有可以改进的地方。事实上是,很多时候,我们想对进入生产环境的代码做一些调整,使用我们最佳的编码实践;这在我们的日常工作中是很自然的事情。但是,如果你把这个想法投射到完全不同的场景中,并从武术的角度去看待它,那么在遇到的防御性场景中,你不会真地想去开始调整你独特的武术风格!你可能会比你自己想象的更糟。相反,你会反复实践和完善你的动作,并磨练你的技能,让他们成为你的第二天性。你将不再需要思考风格或形式,而是着手于眼前的局势。在许多武术中,练习者会反复练习相同的招式,以此把那些招式深深地印在头脑里,这样慢慢地这些招式就会成为练习者的第二天性。

编码招式(Dave Thomas 提出的一个术语,他是《程序员修炼之道》的合著者),在软件开发里是一个类似的理论。开发人员拿到一个简单的问题(比如斐波纳契数列),不断抛开能解决问题的代码,更多地将精力集中在使用什么风格和技术上,而不是问题的实际解决方案上。有人指出,这种自我提高的方法适用于“软件世界中穿着凉鞋的嬉皮士”。也许他们是对的,原先我也持有怀疑态度,但当我开始实践 Katas 的时候,立竿见影的回报让我感到惊讶——尽管作为一名太极练习者,我能理解这个想法。那么,在哪种情况下,BDD 和 VS2010 项目模板向导适合所有这一切?嗯,很简单,可以说这是一段旅程、一段进化的过程。

在 2010 年 TechEd 大会上我看到了相关的演示,那是我第一次接触编码招式的概念以及保龄球招式(Bowling Kata)的实现。David Starr 和 Ben Day 举办了一个非常好的交互式会议,详细研究了保龄球招式,并把这个过程切割成小块,让观众能够理解相关的测试、代码和重构过程。就是那样!作为单元测试的传道,它让人感觉非常完美!有什么更好的方式去逐步形成优秀的工作实践呢,而不要真正去实践那些会产生强壮代码的步骤!我马上开始了尝试(实际上就在会议期间)。我的第一次尝试并不好,因为我仍然专注于问题本身,而不是如何编写代码,那就是我的第一课。为了真正从 Katas 中获益,你要重复相同的 Katas,直到你觉得总体来说测试、编码和重构这一循环过程达到了你预期的效果。一旦你完成这些,你就可以转向另一个招式了。

我尝试的第一个招式是保龄球招式,来自于 Uncle Bob (Robert C. Martin),Dave 和 Ben 在 TechEd 上向我展示过。目标是为 10 瓶保龄球的游戏建立一个计分机制。无需了解太多计分细节(你可以很容易在网络上搜索到),玩家每轮有 2 次机会去击倒所有的木瓶(确切地说是 10 个木瓶——因此叫“10 杆保龄球”)。如果他们一次就把所有的球都击倒,那么这称之为全中(Strike)。如果他们在一轮中两次出球将所有球击倒,那么这叫补中(Spare)。一局比赛有 10 轮,在第 10 轮时,如果玩家打出一次全中或者扔出两次补中,那么他就可以发 3 次球。我设计了下面这个场景“矩阵”,帮我弄清楚如何为游戏计分:





根据这个矩阵,我就可以开始看看用例场景,为编写 10 杆保龄球游戏的计分引擎做好准备:

  • 用例 1:没有击中球时,分数为 0。
  • 用例 2:每轮都击倒一个球时,分数为 20。

    (在最后一轮中没有扔出全中或补中——因此没有奖励球)
  • 用例 3:当扔出的都是全中时,分数为 300。
  • 用例 4:当扔出的都是补中时,分数为 150。
  • 用例 5:在第一轮扔出一次全中,第二轮击倒 8 个球,而其它几轮都没有击倒球时,分数为 26。

对那些熟悉 SCRUM 和 TFS 的人,这通常会作为验收条件列在产品 Backlog 项目上。现在我们有了用例,我们可以开始对每个我们想要创建的场景编写单元测试,并且用真正的 TDD 方式去做,此时我们还未编写引擎本身的代码。Kata 的起点是创建一个单元测试项目,从第一个场景着手,并为其编写测试:

/// <summary>
/// Unit test methods for testing the bowling game engine
/// </summary>
[TestClass]

public class BowlingTests {       /// <summary>      /// Given that we are playing bowling

     /// When I bowl all gutter balls

     /// Then my score should be 0
     /// </summary>      [TestMethod]      public void Bowl_all_gutter_balls()      {          // Arrange          // Given that we are playing bowling          Game game = new Game();            // Act

         // when I bowl all gutter balls
         for (int i = 0; i < 10; i++)          {              game.roll(0);              game.roll(0);          }            // Assert

         // then my score should be 0
         Assert.AreEqual(0, game.score());      } }

为了让这段代码通过编译,需要创建游戏引擎类(Game)以及其方法 roll 和 scroll(因此在代码片段中它们显示为红色)。这些方法不需要做什么事情,也不应该做什么事情——毕竟,在测试驱动开发中,我们会先让它们通不过。

编码提示:

在 VS2010 中,当光标停留在未定义的关键字后(在上面的例子中,就是关键字 Game),我们可以在代码中简单地按下 CTRL + .(稍等片刻),来创建相关类。

用这种方法创建类的好处在于,相对其他强制你专注于新建类的方法而言,这种方法让你可以继续专注于当前的代码。同一键盘快捷键也适用于方法的创建:

因此如果我们采用真正意义上的 TDD 方法,我们的实现类看起来应该是这样的:

public class Game
{
    public void roll(int p)
    {
        throw new NotImplementedException();

    }
  
    public int score()
    {
        throw new NotImplementedException();
    }
}

当然当我们执行单元测试时,会通不过(记得吗?要先通不过):

因此现在我们回过头去,仅仅实现通过测试所需的部分:

public class Game
{
    public void roll(int p)
    {
         // throw new NotImplementedException();

    }       public int score()     {         return 0;     } }

现在,我们执行所有的单元测试,应该都是绿的:

然后我们接着处理下一个场景,先编写测试:

/// <summary>
/// Given that we are playing bowling
/// When I bowl all single pins /// Then my score should be 20
/// </summary> 

[TestMethod] 

public void Bowl_all_single_pins() 
{       

     // Arrange       

// Given that we are playing bowling

    Game game = new Game();       // Act

    // when I bowl all single pins
       for (int i = 0; i < 10; i++)      {             game.roll(1);             game.roll(1);       }        // Assert      

// then my score should be 20
       Assert.AreEqual(20, game.score()); }

当我们执行该测试时,显而易见它会失败:

我们回到刚才的实现代码中,做所需的更改,确保我们不会影响先前的测试:

public class Game
{     
     private int[] _rolls = new int[21];     
     private int _currentFrame = 0;


     public void roll(int pinsKnockedDown)     
     {         
             _rolls[_currentFrame++] = pinsKnockedDown;
     }

     public int score()

     {       int retVal = 0;

             for (int index = 0; index < _rolls.GetUpperBound(0); index++)
             {             
                  retVal += _rolls[index];

             }         
             return retVal;     
      }
}

运行所有的测试,检查我们所做的更改:

这个过程在 Kata 中不断进行,直到完成所有场景的编码,并且所有的测试都通过:

在这个阶段,如果你尽可能多地进行了重构、删除重复代码,同时保留完整的功能(即你的测试在每次重构后保持通过),那么你就可以认为你的 Kata 完成了。

要真正从 Kata 中受益,就要反复练习同样的 Kata,直到确信你已尽可能多地重构优化了你的代码。你必须总是从头开始(或至少从你最基本的环境开始),原因是我们正在练习 Katas,借此增强编码能力。为此,你必须仔细琢磨所有进展,以获取你最终的产品——可运行的方案——因此在你的方法中跳步会适得其反,因为你没有从练习中充分受益。你会看到,就像我稍后在这一系列中解释的那样,当你改变 Katas 时,会有一些共性,那些共性确实会通过通用的宏或者更好的方法——项目模板,融入到你的方法中。

查看英文原文: Using Coding Katas, BDD and VS2010 Project Templates: Part 1


感谢陈宇对本文的审校。

给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。

2010 年 11 月 17 日 00:002300
用户头像

发布了 38 篇内容, 共 74756 次阅读, 收获喜欢 1 次。

关注

评论

发布
暂无评论
发现更多内容

架构师训练营1期 第七周总结

谭明华

第三章总结

孤星

架构师训练营—第七周作业

Geek_shu1988

第七周作业

Geek_ce484f

极客大学架构师训练营

Week3- 面向对象的设计模式(作业二)

shuyaxx

架构师训练营第 1 期第七周作业

Leo乐

极客大学架构师训练营

Week3总结

lggl

作业

架构师训练营第七周学习总结

Gosling

极客大学架构师训练营

架构师训练营—第七周学习总结

Geek_shu1988

极客大学架构师训练营

作业-第3周总结

arcyao

架构师训练营1期 第七周作业

谭明华

极客大学架构师训练营

第三周作业

孤星

Navicat无法连接MySQL怎么办?

MySQL从删库到跑路

MySQL navicat 3306端口

第三章学习笔记

博博

Week3作业一

幸福小子

单例模式

性能测试中并发量与响应时间和吞吐量的关系

天天向上

极客大学架构师训练营

架构师训练营 - 第七周作业

一个节点

极客大学架构师训练营

架构师训练营 - 第七周总结

一个节点

极客大学架构师训练营

性能优化一第七周作业「架构师训练营第 1 期」

天天向善

架构一期第七周作业

Airs

第三章课后作业

博博

架构师训练营第 1 期 -第七周作业

睁眼看世界

极客大学架构师训练营

第七周作业总结

Geek_ce484f

极客大学架构师训练营

架构师训练营第 1 期第七周总结

Leo乐

极客大学架构师训练营

第七周作业

icydolphin

极客大学架构师训练营

把打胜仗的决心作为信仰

吴晨曦

创业

week07作业

追风

架构师一期

第七周

Geek_fabd84

架构师训练营第三周作业

Sandman

Week3小结

幸福小子

设计模式

架构师训练营第七周课程笔记及心得

Airs

使用编码招式(Coding Katas)、BDD和VS2010项目模板:第I部分_敏捷_Jamie Phillips_InfoQ精选文章