色尼玛亚洲综合影院,亚洲3atv精品一区二区三区,麻豆freexxxx性91精品,欧美在线91

TDD并不是看上去的那么美

  春節(jié)前的一篇那些炒作過(guò)度的技術(shù)和概念中對(duì)敏捷和中國(guó)ThoughtWorks的微辭引發(fā)了很多爭(zhēng)議,也驚動(dòng)了中國(guó)ThoughtWorks公司給我發(fā)來(lái)了郵件想來(lái)找我當(dāng)面聊聊。對(duì)于Agile的Fans們,意料之中地也對(duì)我進(jìn)行了很多質(zhì)疑和批評(píng)。我也回復(fù)了許多評(píng)論。不過(guò),我的那些回復(fù)都是關(guān)于中國(guó)ThoughtWorks咨詢師以及其咨詢的方法的。我對(duì)Agile方法論中的具體內(nèi)容評(píng)價(jià)的不是很多,所以,我想不妨討論一下Agile方法論中的具體的實(shí)踐(以前本站也討論過(guò)結(jié)對(duì)編程的利與弊)。

  那么,這次就說(shuō)說(shuō)TDD吧,這是ThoughtWorks中國(guó)和Agile的Fans們最喜歡的東西了。我在原來(lái)的那篇文章中,我把TDD從過(guò)度炒作的技術(shù)剔除了出去,因?yàn)槲疫€是覺(jué)得TDD有些道理的,不過(guò),回顧我的經(jīng)驗(yàn),我也并不是很喜歡TDD。我這篇文章是想告訴大家,TDD并沒(méi)有看上去的那么美,而且非常難以掌控,并且,這個(gè)方法是有悖論之處的。

  TDD簡(jiǎn)介

  TDD全稱Test Driven Development,是一種軟件開(kāi)發(fā)的流程,其由敏捷的“極限編程”引入。其開(kāi)發(fā)過(guò)程是從功能需求的test case開(kāi)始,先添加一個(gè)test case,然后運(yùn)行所有的test case看看有沒(méi)有問(wèn)題,再實(shí)現(xiàn)test case所要測(cè)試的功能,然后再運(yùn)行test case,查看是否有case失敗,然后重構(gòu)代碼,再重復(fù)以上步驟。其理念主要是確保兩件事:

  • 確保所有的需求都能被照顧到。
  • 在代碼不斷增加和重構(gòu)的過(guò)程中,可以檢查所有的功能是否正確。

  我不否認(rèn)TDD的一些有用的地方,如果我們以Test Case 開(kāi)始,那么,我們就可以立刻知道我們的代碼運(yùn)行的情況是什么樣的,這樣可以讓我們更早地得到我們實(shí)現(xiàn)思路的反饋,于是我們更會(huì)有信心去重構(gòu),去重新設(shè)計(jì),從而可以讓我們的代碼更為正確。

  不過(guò),我想提醒的是,TDD和Unit Test是兩碼子事兒。有很多人可能混淆了自動(dòng)化的Unit Test(如:XUnit系例)和TDD的軟件開(kāi)發(fā)過(guò)程。另外,可能還會(huì)有人向鼓吹“TDD讓你進(jìn)行自頂向下的設(shè)計(jì)方式”,對(duì)此,請(qǐng)參閱本站的《Richard Feynman, 挑戰(zhàn)者號(hào), 軟件工程》——NASA的挑戰(zhàn)者號(hào)告訴你自頂向下設(shè)計(jì)的危險(xiǎn)性。

  TDD的困難之處

  下面是幾個(gè)我認(rèn)為T(mén)DD不容易掌控的地方,甚至就有些不可能(如果有某某TDD的Fans或是ThoughtWorks的咨詢師和你鼓吹TDD,你可以問(wèn)問(wèn)他們下面這些問(wèn)題)

  • 測(cè)試范圍的確定。TDD開(kāi)發(fā)流程,一般是先寫(xiě)Test Case。Test Case有很多種,有Functional的,有Unit的,有Integration的……,最難的是Test Case要寫(xiě)成什么樣的程度呢。
    • 如果寫(xiě)的太過(guò)High Level,那么,當(dāng)你的Test Case 失敗的時(shí)候,你不知道哪里出問(wèn)題了,你得要花很多精力去debug代碼。而我們希望的是其能夠告訴我是哪個(gè)模塊出的問(wèn)題。只有High Level的Test Case,豈不就是Waterfall中的Test環(huán)節(jié)?
    • 如果寫(xiě)的太過(guò)Low Level,那么,帶來(lái)的問(wèn)題是,你需要花兩倍的時(shí)間來(lái)維護(hù)你的代碼,一份給test case,一份給實(shí)現(xiàn)的功能代碼。
    • 另外,如果寫(xiě)得太Low Level,根據(jù)Agile的迭代開(kāi)發(fā)來(lái)說(shuō),你的需求是易變的,很多時(shí)候,我們的需求都是開(kāi)發(fā)人員自己做的Assumption。所以,你把Test Case 寫(xiě)得越細(xì),將來(lái),一旦需求或Assumption發(fā)生變化,你的維護(hù)成本也是成級(jí)數(shù)增加的。
    • 當(dāng)然,如果我把一個(gè)功能或模塊實(shí)現(xiàn)好了,我當(dāng)然知道Test 的Scope在哪里,我也知道我的Test Case需要寫(xiě)成什么樣的程度。但是,TDD的悖論就在于,你在實(shí)現(xiàn)之前先把Test Case就寫(xiě)出來(lái),所以,你怎么能保證你一開(kāi)始的Test Case是適合于你后面的代碼的?不要忘了,程序員也是在開(kāi)發(fā)的過(guò)程中逐漸了解需求和系統(tǒng)的。如果邊實(shí)現(xiàn)邊調(diào)整Test Case,為什么不在實(shí)現(xiàn)完后再寫(xiě)Test Case呢?如果是這樣的話,那就不是TDD了。
  • 關(guān)注測(cè)試而不是設(shè)計(jì)。這可能是TDD的一個(gè)弊端,就像《十條不錯(cuò)的編程觀點(diǎn)》中所說(shuō)的一樣——“Unit Test won’t help you write the good code”,在實(shí)際的操作過(guò)程中,我看到很多程序員為了趕工或是應(yīng)付工作,導(dǎo)致其寫(xiě)的代碼是為了滿足測(cè)試的,而忽略了代碼質(zhì)量和實(shí)際需求。有時(shí)候,當(dāng)我們重構(gòu)代碼或是fix bug的時(shí)候,甚至導(dǎo)致程序員認(rèn)為只要所有的Test Case都通過(guò)了,代碼就是正確的。當(dāng)然,TDD的粉絲們一定會(huì)有下面的辯解:
    • 可以通過(guò)結(jié)對(duì)編程來(lái)保證代碼質(zhì)量。
    • 代碼一開(kāi)始就是需要滿足功能正確,后面才是重構(gòu)和調(diào)優(yōu),而TDD正好讓你的重構(gòu)和優(yōu)化不會(huì)以犧牲功能為代價(jià)。

  說(shuō)的沒(méi)錯(cuò),但僅在理論上。操作起來(lái)可能會(huì)并不會(huì)得到期望的結(jié)果。1)“結(jié)對(duì)編程”其并不能保證結(jié)對(duì)的兩個(gè)人都不會(huì)以滿足測(cè)試為目的,因?yàn)橹貥?gòu)或是優(yōu)化的過(guò)程中,一旦程序員看到N多的test cases 都failed了,人是會(huì)緊張的,你會(huì)不自然地去fix你的代碼以讓所有的test case都通過(guò)。2)另外,我不知道大家怎么編程,我一般的做法是從大局思考一下各種可行的實(shí)現(xiàn)方案,對(duì)于一些難點(diǎn)需要實(shí)際地去編程試試,最后權(quán)衡比較,挑選一個(gè)最好的方案去實(shí)現(xiàn)。而往往著急著去實(shí)現(xiàn)某一功能,通常在會(huì)導(dǎo)致的是返工,而后面的重構(gòu)基本上因?yàn)榍捌诳紤]不足和成為了重寫(xiě)。所以,在實(shí)際操作過(guò)程中,你會(huì)發(fā)現(xiàn),很多時(shí)候的重構(gòu)通常意味著重寫(xiě),因?yàn)槟切?rdquo;非功能性”的需求,你不得不re-design。而re-design往往意味著,你要重寫(xiě)很多Low-Level的Test Cases,搞得你只敢寫(xiě)High Level的Test Case。

  • TDD導(dǎo)致大量的Mock和Stub。相信我,Test Case并不一定是那么容易的。比如,和其它團(tuán)隊(duì)或是系統(tǒng)的接口的對(duì)接,或是對(duì)實(shí)現(xiàn)還不是很清楚的模塊,等等。于是你需要在你的代碼中做很多的Mock和Stub,甚至fake一些函數(shù)來(lái)做模擬,很明顯,你需要作大量的 assumption。于是,你發(fā)現(xiàn)管理和維護(hù)這些Mock和Stub也成了一種負(fù)擔(dān),最要命的是,那不是真正的集成測(cè)試,你的Test Case中的Mock很可能是錯(cuò)的,你需要重寫(xiě)他們。

  也許,你會(huì)說(shuō),就算是不用TDD,在正常的開(kāi)發(fā)過(guò)程中,我們的確需要使用Mock和Stub。沒(méi)錯(cuò)!的確是這樣的,不過(guò),記住,我們是在實(shí)現(xiàn)代碼后來(lái)決定什么地方放一個(gè)Mock或Stub,而不是在代碼實(shí)現(xiàn)前干這個(gè)事的。

  • Test Case并沒(méi)有想像中的那么簡(jiǎn)單。和Waterfall一樣,Waterfall的每一個(gè)環(huán)節(jié)都依賴于前面那個(gè)環(huán)節(jié)的正確性,如果我們沒(méi)有正確的理解需求,那么對(duì)于TDD,Test Case和我們的Code都會(huì)的錯(cuò)的。所以,TDD中,Test Case是開(kāi)發(fā)中最重要的環(huán)節(jié),Test Case的質(zhì)量的問(wèn)題會(huì)直接導(dǎo)致軟件開(kāi)發(fā)的正確和效率。而TW的咨詢師和Agile的Fans們似乎天生就認(rèn)為,TDD比Waterfall更能準(zhǔn)確地了解需求。如果真是這樣,用TDD進(jìn)行需求分析,后面直接Waterfall就OK了。

  另外,某些Test Case并不一定那么好寫(xiě),你可能80%的編程時(shí)間需要花在某個(gè)Test Case的設(shè)計(jì)和實(shí)現(xiàn)上(比如:測(cè)試并發(fā)),然后,需求一變,你又得重寫(xiě)Test Case。有時(shí)候,你會(huì)發(fā)現(xiàn)寫(xiě)Test Case其實(shí)和做實(shí)際設(shè)計(jì)沒(méi)有差別,你同樣要考慮你Test Case的正確性,擴(kuò)展性,易讀性,易維護(hù)性,甚至重用性。如果說(shuō)我們開(kāi)發(fā)的Test Case是用來(lái)保證我們代碼實(shí)現(xiàn)的正確性,那么,誰(shuí)又來(lái)保證我們的Test Case的正確性呢?編寫(xiě)Test Case也需要結(jié)對(duì)或是Code review嗎?軟件開(kāi)發(fā)有點(diǎn)像長(zhǎng)跑,如果把能量花在了前半程,后半程在發(fā)力就能難了。

  也許,TDD真是過(guò)度炒作的,不過(guò),我還真是見(jiàn)過(guò)使用TDD開(kāi)發(fā)的不錯(cuò)的項(xiàng)目,只不過(guò)那個(gè)項(xiàng)目比較簡(jiǎn)單了。更多的情況下,我看到的是教條式的生硬的TDD,所以,不奇怪地聽(tīng)到了程序員們的抱怨——“自從用了TDD,工作量更大了”。當(dāng)然,這也不能怪他們,TDD本來(lái)就是很難把控的方法。這里送給軟件開(kāi)發(fā)管理者們一句話——“當(dāng)你的軟件開(kāi)發(fā)出現(xiàn)問(wèn)題的時(shí)候,就像bug-fix一樣,首要的事是找到root cause,然后再case by case的解決,千萬(wàn)不要因?yàn)橛袉?wèn)題就要馬上換一種新的開(kāi)發(fā)方法”。相信我,大多數(shù)的問(wèn)題是人和管理者的問(wèn)題,不是方法的問(wèn)題。

it知識(shí)庫(kù)TDD并不是看上去的那么美,轉(zhuǎn)載需保留來(lái)源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 玉龙| 天祝| 隆尧县| 凌云县| 洛川县| 凌源市| 集贤县| 皋兰县| 榆社县| 荥阳市| 沅陵县| 徐闻县| 临泽县| 大宁县| 靖安县| 宜兰县| 武强县| 台湾省| 芒康县| 田阳县| 正定县| 禄劝| 景德镇市| 睢宁县| 蒲江县| 靖安县| 紫金县| 车致| 凌海市| 兴山县| 昭平县| 千阳县| 如东县| 仪征市| 福清市| 宁德市| 开封市| 建湖县| 黄浦区| 抚远县| 武义县|