以自身的角度考虑问题

北大青鸟大学城校区logo 北大青鸟大学城校区
招生简章校园环境师资力量就业明星招生问答软件工程师北京大学学历学员项目联系我们 报名通道

免费在线咨询通道>>

免费在线报名通道>>

北大青鸟报名电话
当前位置:北大青鸟 > IT培训 > 电脑培训 >

以自身的角度考虑问题

标签:   分类:电脑培训

“前进,先完成所有的库代码。后面会有大量时间看用户是如何思考的。现在只要把代码扔过墙去就可以了,我保证它没有问题。”

很多成功的公司都是靠着“吃自己的狗食”活着。也就是说,如果要让你的产品尽可能地好,自己先要积极地使用它。

幸运的是,我们不是在做狗食业务。但是,我们的业务是要创造出能调用的APl和可以使用的接口。这就是说,你在说服其他人使用它之前,先得让自己切实地使用这些接口。事实上.在你刚做完设计但还没有完成后面的实现的时候,应该使用它。这个可行吗?

使用被称为1DD(Test Driven Development,测试驱动开发)的技术,你总是在有一个失败的单元测试后才开始编码。测试总是先编写。通常.测试失败要么是因为测试的方法不存在.要么是因为方法的逻辑还不足以让测试通过。

先写测试.你就会站在代码用户的角度来思考,而不仅仅是一个单纯的实现者。这样做是有很大区别的,你会发现因为你自己要使用它们,所以能设计个更有用、更一致的接口。

除此之外,先写测试有助于消除过度复杂的设计,让你可以专注于真正需要完成的工作。看看下面编程的例子,这是一个可以两人玩的“井字棋游戏”。

开始,你会思考如何为这个游戏做代码设计。你也许会考虑需要这些类,例如:TicTacToeBoard、Cell、Row、Column、plaoyer、ules、Peg、Score和rules.咱们从TicTacToeBoard类开始,它就代表了井字棋本身(从游戏的核心逻辑而不是UI角度说)。

这可能是TicTactoeBoard类的第一个测试,是c#在Nunil测试框架下编写的。

它创造了一个游戏面板,用断言来检查游戏没有结束。

TestFixture]

public class TicTacToeTest

{

private TrcTactoeBoard board;

【SetUP】

public void CreateBoard{}

{

board =new TicTacToeBoard();

[Test]

public void testcreateboard()

{

Assert .Isnotnull (board);

Assert.Isfalse {board.Gameover}

}

}

测试失败.因为类TicTacT0eBoard不存在,你会得到一个编译错误。如果它通过了,你一定很惊讶,不是吗?这也可能会发生,只是概率根小·但确实可能会发生。在测试通过之前,先要确保测试是失败的。目的是希望暴露出测试中潜在的bug。下面我们来实现这个类。

public class tictactoeboard{

public bool gameover {

get{

return false

}

}

}

在属性GaIneover中,我们现在只返回旦false。一般情况下,你会用必要的最少代码让测试通过。从某种角度上说,这就是在欺骗测试——你知道代码还没有完成。但是没有关系,后面的测试会迫使你再返回来,继续添加功能。

下一步是什么呢?首先,你必须决定谁先开始走第一步棋,我们就要设第个比赛者。先为第一个比赛者写一个测试。

[test]

pubic viod testsetfirstplayer()

//what should go here?

}

这时,测试会迫使你做一个决定。在完成它之前,你必须决定如何在代码中表示比赛者,如何把它们分配到面板上。这里有一个主意。

board setfirstplayer(Mark),“x”

这会告诉面板,游戏玩家Mark使用X。这样做当然可以,你真的需要Player这个类,或者第一个玩家的名字吗?也许,稍后你需要知道谁是赢家。但现在它还不是问题。YANGI。(你可能永远都不需要它)原则说过,如果不是真正需要它的时候,你就不应该实现这个功能。基于这点,现在还没有足够的理由表示你需要Player这个类。

别忘了,我们还没有实现TicTacToeBoard类中自SetFirtplayer()方法,并且还没有写Player这个类。我们仍然是先写一测试。我们假设下面的代码是用来设置第一个玩家的。

board setFirstplayer("x")

它表示设X为第一个玩家,比第一个版本要更简单。但是,这个版本隐藏着风险:你可以传任何字母给SetFirstplayer()方法.这就意味着你必须添加代码来检查参数是O是X并且需要知道如果它不是这两个值的时候该如何处理。因此要更进一步简单化。我们有一个简单的标志来标明第一个玩家是O还是X。知道了这个,我们现在就可以写单元测试了。

f‰t】

public void testsetfirstplayer()

board.firstplayerpegisx=true;

Assert.IsTrue(board.firstplayerpegIsx);

我们可以将First:PlayerPegIsX设为布尔类型的属性,并把它设为期望的值。这看起来挺简单的,也容易使用,比复杂的Player类容易很多。测试写好了,你就可以通过在TicTacToeBoard类中实现FirgtplayezPegl8x属性,让测试通过。

你看,我们是以playez类开始,最后却只使用了简单的布尔类型属性。这是如何做到的呢?这种简化就是在编写代码之前让测试优先实现的。

但记住.我们不是要扔掉好的设计。就只用大量的布尔类型来编码所有的东西。这里的重点是:什么是成功地实现特定功能的最低成本。总之,程序员根容易走向另一个极端——些不必要的过于复杂的事情——测试优先会帮助我们,防止我们走偏。

消除那些还设有编写的类,这会很容易地简化代码。相反,一旦你已经编写了代码.也许会强迫自己保留这些代码.并继续使用它(即使代码已经过期作废很久了)。

当你开发设计面向对象系统的时候,可能会迫使自己使用对象。有一种倾向认为,面向对象的系统应该由对象组成,我们迫使自己创建越来越多的对象类.不管它们是否真的需要。添加无用代码总是不好的想法。

TDD有机会让你编写代码之前(或者至少在深入到实现之前),可以深思熟虑将如何用它。这会迫使你去思考它的可用性和便利性.并让你的设计更加注重实效。

当然.设计不是在开始编码的时候就结束了。你需要在它的生命周期中持续地添加测试,添加代码,并重新设计代码先用它再实现它。将TDD作为设计工具,它会为你带来更简单曼有实效的设计。

切身感受

这种感觉就是,只在有具体理由的时候才开始编码。你可以专注于设计接口,而不会被很多实现的细节干扰。

平衡的艺术

不要把测试优先和提交代码之前的测试等同起来。测试先行可以帮助你改进设计,但是你还是需要在提交代码之前做测试。

任何一个设计都可以被改进。

你在验证一个想法或者设计一个原型的时候,单元测试也许并不适合。但是,

万一这些代码不幸仓促演变成了一个真正的系统,就必须要为它们添加测试(但是最好能重新开始设计系统)。

单纯的单元测试无法保证好的设计,但它们会对设计有帮助,会让设计更加简单。

若有疑问请拨打北大青鸟咨询热线:010-80146691或点击免费在线咨询!
  • xml地图 网站地图 招生简章 合作企业 学员项目 联系我们
  • 关闭窗口