摘要:在軟件行業(yè)中,,神仙打架的名場面,,那就不得不提的是2014年的那場——測試驅(qū)動開發(fā)(TDD)之爭。 在歷史上有很多精彩絕倫的神仙打架,,比如數(shù)學界的牛頓和萊布尼茨關(guān)于微積分的曠世之爭,;比如量子物理中的愛因斯坦和波爾的紫禁之巔;比如足球里的梅西和C羅的旗鼓相當難分高下,;又比如滴滴和快滴之間觸目驚心的燒錢大戰(zhàn)……而在軟件行業(yè)中,,也同樣有神仙打架的名場面,那就不得不提的是2014年的那場——測試驅(qū)動開發(fā)(TDD)之爭,。 比賽的紅方是David Heinemeier Hansson,,藍方是Kent Beck。David Heinemeier Hansson 由于名字較長簡寫成DHH,,Ruby on Rails 正是出自于DHH之手,。而這場打架還加入了“裁判”員——Martin Fowler,在比賽中Martin Fowler記錄了紅藍雙方的每一次組合拳,、上勾拳,、側(cè)踹、抱摔……總結(jié)如下: 紅方DHH觀點: 許多推動TDD的開發(fā)人員會讓你覺得:如果你不使用TDD的話,,你的代碼就是骯臟的,。 由單元測試開始驅(qū)動你的設(shè)計并不是一個好的主意。 TDD的概念流量交易“測試必須夠快”是目光短淺的,。 對TDD的依賴會導致徹底忘記系統(tǒng)測試,。 關(guān)注并且只關(guān)注單元模塊并不能有助于創(chuàng)建一套完美的系統(tǒng)。 100%的覆蓋率是愚蠢的,。 程序員希望軟件是一門科學,,可是它并不是,。它更像是創(chuàng)造性的寫作活動。 優(yōu)秀的軟件并不像工程學那樣,,它更像寫作。清楚簡潔的寫作要優(yōu)于復雜晦澀的寫作,。 清晰是有好處的,,好到應該將清晰性作為第一目標,而非測試覆蓋度或者測試速度,。 成為一名優(yōu)秀的開發(fā)人員就像成為一名優(yōu)秀的作家一樣困難,。 就像寫作一樣,成為優(yōu)秀的程序員的辦法就是以清晰為目標從而大量編寫軟件,、大量閱讀軟件,。 藍方Kent Beck觀點: DHH已將TDD委托給歷史垃圾堆。我很難過,,不是因為我就把它從歷史的垃圾堆中拯救出來,,而是因為現(xiàn)在我需要雇傭新技術(shù)來幫助我解決編程過程中的許多問題: 過度工程化。我傾向于“投入”我“知道”我“將需要”的功能,。使一個紅色的測試變?yōu)榫G色(以及未來的測試列表)有助于我實現(xiàn)足夠的功能,。我需要找到一個新的方法來保持專注。 API反饋,。我需要找到一種新的方法來獲得關(guān)于我的API決策的快速反饋,。 邏輯錯誤。我需要找到一種新的方法來抓住那些我很容易犯的討厭的測試錯誤,。 文檔,。我需要找到一種新的方式來傳達我對api的期望,并記錄我在開發(fā)過程中的想法,。 感到不知所措,。我真的會懷念如何使用TDD,即使我無法想象一個實現(xiàn),,我?guī)缀蹩偰芟氤鋈绾尉帉憸y試,。我需要找到一個新的方法,以便下一步上山,。 將接口與實現(xiàn)思想分離,。我傾向于用實現(xiàn)推測來污染API設(shè)計決策。我需要找到一種新的方法來分離這兩個層次的思維,,同時在它們之間提供快速的反饋,。 協(xié)議。我需要找到一個新的方法,,精確地與一個編程伙伴關(guān)于我正在解決的問題,。 焦慮,。也許我最懷念的是TDD給我的瞬間“一切都好嗎?”按鈕,。 我相信我會找到其他方法來解決這些問題,。及時。疼痛會減輕的,。再見TDD,,老朋友。 神仙打架不虧是神仙打架,,從那以后業(yè)界關(guān)于測試驅(qū)動開發(fā)的觀念也分成了兩派,。一派主要來源自像國內(nèi)的一些互聯(lián)網(wǎng)等項目中聲音——需求的迭代和更新之快,要求公司或團隊能快速交付有價值的產(chǎn)品,,而TDD對于很多開發(fā)人員來說無疑是帶來了繁重的工作壓力和交付壓力,。甚至有人開玩笑話說:“ Deadline Driven Development 才是第一生產(chǎn)力 ”。 當然也有人力挺TDD,,“TDD并沒有死,。很明顯,既然它有這么這么多的支持者,,它怎么可能會死呢? 這就像在問,,設(shè)計模式死了嗎?或者功能性自動化死了嗎,?不,,它并沒有死。而且它在將來任何時候都不會死亡,。它將來可能會變成其他一些新的事物,、甚至是一些更好的事物,但是它永遠不會死亡,。所以讓我們跳過這一部分吧,。” 關(guān)于測試驅(qū)動開發(fā)說了這么久,,那么測試驅(qū)動開發(fā)到底是個啥呢,? 測試驅(qū)動開發(fā)(TDD)是什么 測試驅(qū)動開發(fā),英文全稱Test-Driven Development,,簡稱TDD,,是一種不同于傳統(tǒng)軟件開發(fā)流程的新型的開發(fā)方法。 它要求在編寫某個功能的代碼之前先編寫測試代碼,,然后只編寫使測試通過的功能代碼,,通過測試來推動整個開發(fā)的進行。 這有助于編寫簡潔可用和高質(zhì)量的代碼,,并加速開發(fā)過程,。 Kent Beck:“測試驅(qū)動開發(fā)不是一種測試技術(shù),。它是一種分析技術(shù)、設(shè)計技術(shù),,更是一種組織所有開發(fā)活動的技術(shù)”,。 分析技術(shù): 體現(xiàn)在對問題域的分析,當問題還沒有被分解成一個個可操作的任務時,,分析技術(shù)就派上用場,,例如需求分析、任務拆分和任務規(guī)劃等,,《實例化需求》這本書可以給予一定的幫助作用。 設(shè)計技術(shù): 測試驅(qū)動代碼的設(shè)計和功能的實現(xiàn),,然后驅(qū)動代碼的再設(shè)計和重構(gòu),,在持續(xù)細微的反饋中改善代碼。 組織所有開發(fā)活動的技術(shù): TDD 很好地組織了測試,、開發(fā)和重構(gòu)活動,,但又不僅限于此,比如實施 TDD 的前置活動包括需求分析,、任務拆分和規(guī)劃活動,,這使得 TDD 具有非常好的擴展性。 測試驅(qū)動開發(fā)(TDD)的目標 Kent Beck 在他的著作《Test-Driven Development》(見參考附錄)一書中提到:“代碼簡潔可用這句言簡意賅的話,,正是 TDD 所追求的目標”,。 對于如何保證“代碼簡潔可用”可以使用分而治之的方法,先達到“可用”目標,,再追求“簡潔”目標,。 可用: 保證代碼通過自動化測試。 代碼簡潔: 在不同階段人們對簡潔的理解程度也不一樣,,不過遵循的原則差不多,,例如 OOD 的 SOLID 原則(詳見參考附錄),Kent Beck 的 Simple Design 原則(詳見參考附錄)等,。 雖然有很多因素妨礙我們得到整潔的代碼,,甚至可用的代碼,無需征求太多意見,,只需要采用 TDD 的開發(fā)方式來驅(qū)動出簡潔可用的代碼,。 測試驅(qū)動開發(fā)(TDD)的規(guī)則 在TDD 的過程中,需要遵循的三項原則: 在編寫好失敗的單元測試之前,,不要寫任何產(chǎn)品代碼,。 只要有一個單元測試失敗了,就不要再寫測試代碼,。無法通過編譯也是一種失敗,。 產(chǎn)品代碼恰好能夠讓當前失敗的單元測試成功通過即可,,不要多寫。 測試驅(qū)動開發(fā)(TDD)的流程 測試驅(qū)動開發(fā)是一個過程,,依賴于不斷重復極短的開發(fā)周期,,這個周期也稱為“紅燈-綠燈-重構(gòu)”,如上圖,。簡單的來說,,基于TDD的三項原則,TDD的這種步驟(周期)如下: 添加一個小的測試 運行測試并查看失敗 對測試進行微小的改動通過測試 運行所有測試并看到其通過 通過重構(gòu)去掉重復部分 需要注意的是,,不同階段有不同的目的,,他們需要不同的解決方案,前二個階段需要很快地完成,,以便知道新添加功能的狀態(tài),。為了達成這個目的,可以通過任何手段,,因為僅在這時才這樣做,,也是為了能快速完成好的設(shè)計。 測試驅(qū)動開發(fā)(TDD)的好處 TDD主要的好處主要包括了,,確定性,、重構(gòu)代碼、單元測試即文檔,。 確定性,。TDD提升了單元測試的覆蓋率,在每輪迭代產(chǎn)品都會新增代碼,,如果有一套覆蓋率很高( 90% 或更高)的單元測試,,那么只需執(zhí)跑一遍測試用例,那么能成功交付的把握就會比較大,。反之,,如果覆蓋率越低,越需要更多的人力去進行手動驗證,。 在 kent Beck的《測試驅(qū)動開發(fā)》舉的例子中,,正因有了TDD才有勇氣和老板說我們可以做!這就是TDD最強大的地方,,它讓你擁有一套值得信賴的測試,,打消你對修改代碼的恐懼。 重構(gòu)代碼,。Martin Flower在他的《重構(gòu)》中也指出,,完善的單元測試是他進行重構(gòu)的基石,從TDD的流程可以看到,,重構(gòu)是TDD的一部分,,運用TDD的同時也推動了代碼的重構(gòu),。 單元測試即文檔。在軟件行業(yè)里,,人員的變動的很頻繁的,,如果要盡快熟悉某個模塊的業(yè)務邏輯??次臋n,?程序員寫的文章一般都不太容易看,而且文檔經(jīng)常會和代碼不同步,,代碼修改了文檔沒跟著改的事情經(jīng)常發(fā)生,。看源碼,?看完也不一定知道為什么,。如果這時候有一套非常完整的單元測試,那可能就是所有接手別人代碼的程序員的福音,。首先,,代碼不會撒謊,,其次,,測試用例明確告訴了你這個函數(shù)是做什么的,什么輸入對應的都有什么預期輸出,。單元測試就是最好的底層文檔,,哪個專業(yè)人士不想提供這樣一份文檔呢? 此外,,TDD還能夠促成良好的代碼設(shè)計,。由于你先寫測試代碼,你會盡可能的讓代碼調(diào)用起來更加簡單方便,,這也就促使你去考慮如何更好的設(shè)計代碼,。以避免會出現(xiàn)一個函數(shù)里實現(xiàn)的功能過多,或者和其他代碼過于耦合而無法測試的情況,。 當然測試驅(qū)動開發(fā)除了好處以外,,還有神仙打架中紅方代表DHH所提出的一些問題??偨Y(jié)來看,,關(guān)于TDD的爭議可以大致從這幾個方面來看,軟件開發(fā)應該由什么來驅(qū)動,,測試的速度和覆蓋程度,,以及設(shè)計思想層面等幾方面。從 辯證統(tǒng)一的角度來看,,事物有兩個方面,, TDD不一定能適用于所有的場景,,同樣TDD的局限性在某些場景下也不見得是對的,如果想要能更好的適用于自身,,不僅要拿捏好度的問題還要以敏捷的思想來應對問題,,比如不應該盲目的制定100%或0%的測試覆蓋率,也不應該固化開發(fā)步驟而不顧實際情況,。 所以,,在最后的神仙打架中,Kent Beck也表達了David的論述可能會讓TDD浴火重生,、鳳凰涅槃的觀點,,希望可以找到更加好的方法。但無論如何,, 在我們實際工作中,,不應該因為某些 觀點成為我們接受或者拒絕它的理由。正所謂大道甚夷,,而民好徑,,作為敏捷開發(fā)中的一項優(yōu)秀實踐來看,TDD只有在真正使用過后才能評價是否已死的問題,。那么你在踐行敏捷開發(fā)的時候,,是否使用過TDD這種實踐呢,又或是踐行過其他一些敏捷開發(fā)的實踐呢,,有沒有評測過你所在的項目中的敏捷開發(fā)的成熟度是如何的呢,? 沒有那就對了! |
|