TDD中的一小步 2-->1+1

小步

小步進(jìn)行(Baby steps)是TDD開發(fā)中非常重要的理念。

  • 小步增加測(cè)試暖夭,確保了不會(huì)一次引入過多變更箩祥。以免一不小心扯了蛋。:D
  • 小步通過測(cè)試驯鳖,確保了最快最直接的從紅燈轉(zhuǎn)為綠燈闲询。避免前期過度設(shè)計(jì),以及隨之而來的無測(cè)試的實(shí)現(xiàn)代碼浅辙。
  • 小步重構(gòu)扭弧, 確保了安全平滑的改善代碼結(jié)構(gòu)。

在整個(gè)TDD“紅燈->綠燈->重構(gòu)”的循環(huán)中记舆,小步提供了快速反饋?zhàn)屛覀冸S時(shí)檢驗(yàn)代碼行為鸽捻,并在出錯(cuò)的第一時(shí)間進(jìn)行修正。另一方面也促使我們“一次只做一件事”,將一個(gè)較為復(fù)雜的問題分解開來逐步解決御蒲。

僵局

看起來很簡(jiǎn)單是吧衣赶,但是現(xiàn)實(shí)往往是骨感的。在學(xué)習(xí)TDD的過程中厚满,我們經(jīng)常會(huì)發(fā)現(xiàn)小步成為了一大難點(diǎn)府瞄。一開始的紅燈然后hardcode綠燈還算簡(jiǎn)單。之后碘箍,要么反復(fù)的小步踏步摘能,要么對(duì)這種小步探索喪失信心,重新回到了 長(zhǎng)時(shí)間預(yù)先設(shè)計(jì) -> 大改動(dòng) -> 調(diào)試 的節(jié)奏中敲街。
對(duì)這個(gè)問題团搞,Unclue Bob提出了一個(gè)指導(dǎo)意見, Transformation Priority Premise (代碼變換優(yōu)先次序)簡(jiǎn)稱 TPP多艇。由于整個(gè)的優(yōu)先列表比較復(fù)雜逻恐,而且還有些可商榷的地方,今天在這里并不打算詳細(xì)介紹峻黍。有興趣的同學(xué)可以看看文末鏈接复隆。這里只對(duì)比最近一次coding dojo的例子,分享一下這個(gè)原則對(duì)小步練習(xí)的啟發(fā)姆涩。

蠢代碼 聰明代碼

在第一個(gè)“紅燈->綠燈”循環(huán)后挽拂,有一個(gè)問題就擺在了程序員面前:既然要求最快的通過測(cè)試,那么為什么不一直hardcode來通過測(cè)試呢骨饿?
以我們所做的“羅馬數(shù)字轉(zhuǎn)換為整數(shù)”的Kata為例亏栈,在一開始hardcode

if(roman.equals("X")) {
return 10;
}
if(roman.equals("V")) {
return 5;
}
if(roman.equals("I")) {
return 1;
}

...
if(roman.equals("II")) {
return 2;
}

之后宏赘,為什么不寫3千句if來解決這個(gè)題目呢绒北?
其實(shí)我們心里都明白,一句永遠(yuǎn)返回一個(gè)值的代碼太蠢了察署。它并不真正“理解”并解決問題闷游,我們的目標(biāo)是要寫一段“聰明”的代碼來真的解決它。難點(diǎn)在于贴汪,我們習(xí)慣于一開始就尋找“聰明”的方案脐往,從問題的“本質(zhì)”去解決。一旦刻意縮小步伐扳埂,先寫下一句蠢代碼业簿,卻發(fā)現(xiàn)找不到一條路把它逐步變的聰明起來。

constant -> constant+

這里就引入了TPP中的一步聂喇,constant -> constant+
當(dāng)我們開始寫II轉(zhuǎn)換為2的邏輯時(shí)辖源,首先增加了一個(gè)硬編碼的分支來通過測(cè)試
這時(shí)蔚携,可能我們心里會(huì)覺得有一些不對(duì),感覺并沒有真正在解決這個(gè)問題克饶。那么酝蜒,如何開始讓代碼向”真正“的代碼演進(jìn)呢?
下面就是采用了constant -> constant +規(guī)則來重構(gòu)后的代碼

if(roman.equals("I"+"I")) {
return 1+1;
}

哇哦……
好吧矾湃,其實(shí)好像沒什么大不了的嘛亡脑。從編譯運(yùn)行來說,"I"+"I"和1+1很可能會(huì)被編譯器直接優(yōu)化成為常量"II" 和2邀跃,也就是說這么改寫對(duì)機(jī)器來說霉咨,根本就是一樣的嘛。
但是代碼是給人看的拍屑。
這個(gè)變換的最大意義途戒,在于減少了代碼中的知識(shí)。

知識(shí)

知識(shí)僵驰,在日常生活中是個(gè)很好的詞喷斋。“知識(shí)就是力量”蒜茴,“知識(shí)改變生活”星爪,見多識(shí)廣是美德。
然而粉私,軟件中的知識(shí)卻并非如此顽腾。對(duì)于代碼而言,知識(shí)意味著無法用邏輯解釋的事情诺核。比如為什么羅馬人用I表示1抄肖,而不是用Y。這是代碼無法回答的問題猪瞬。一個(gè)知識(shí)對(duì)于代碼而言就是一個(gè)依賴或者假設(shè)憎瘸。怎么處理這些依賴和假設(shè)是軟件設(shè)計(jì)的關(guān)鍵問題。


在代碼世界中“你知道的太多了”可能是更合適的格言

以非常常見的兩個(gè)設(shè)計(jì)原則為例:

  1. 消除重復(fù) (DRY):這條規(guī)則往往被理解為消除重復(fù)的代碼陈瘦。著眼點(diǎn)在于避免重復(fù)勞動(dòng)。比如上面例子中“II”改寫為"I" + "I"后潮售,可能很快就會(huì)有人意識(shí)到"I"可以提取替換來消除字面量的重復(fù)痊项。然而比這個(gè)更重要的是,消除知識(shí)的重復(fù)酥诽。也就是說對(duì)于每個(gè)知識(shí)鞍泉,應(yīng)該有且只有一個(gè)地方對(duì)其進(jìn)行表述。
  2. 單一職責(zé):這里的職責(zé)肮帐,往往也被局限在代碼功能方面咖驮。對(duì)于不怎么需要編碼的事情边器,往往就忘記它也可能和職責(zé)相關(guān)了。比如當(dāng)前時(shí)間托修,比如pi=3.14忘巧。事實(shí)上,職責(zé)最重要的一點(diǎn)就是知識(shí)的所有權(quán)睦刃。對(duì)于每項(xiàng)知識(shí)砚嘴,應(yīng)該有一個(gè)所有者對(duì)它“說了算”,系統(tǒng)的其它部分都聽它的涩拙,這樣才能保證所有相關(guān)于這個(gè)知識(shí)的改變都局部化在這個(gè)單元之中际长。

我們?cè)倩仡^以知識(shí)的視角來看2->1+1的這一次變換。前面的I->1,V->5,X->10……是羅馬數(shù)字本身所固有的知識(shí)兴泥。軟件中必須要寫下處理這些知識(shí)的代碼工育,當(dāng)然,可以寫的比一堆if優(yōu)雅很多搓彻,不過這是另一個(gè)話題了如绸。
然而 II->2 卻不同。它是 I->1以及數(shù)字組合邏輯的派生結(jié)果好唯。簡(jiǎn)單的增加一句if是向系統(tǒng)中增加了一個(gè)知識(shí)竭沫,而這個(gè)知識(shí)本身是可以消除掉的。
通過把本來看似一整塊的常量寫成常量的組合骑篙,讓本來隱含的知識(shí)重復(fù)變成了明顯的代碼重復(fù)蜕提。為后續(xù)的提取常量/變量等后續(xù)重構(gòu)開辟了道路。

參考資料

TPP: https://blog.8thlight.com/uncle-bob/2013/05/27/TheTransformationPriorityPremise.html
漫畫版: http://blog.8thlight.com/uncle-bob/2013/05/27/TransformationPriorityAndSorting.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末靶端,一起剝皮案震驚了整個(gè)濱河市谎势,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌杨名,老刑警劉巖脏榆,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異台谍,居然都是意外死亡须喂,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門趁蕊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來坞生,“玉大人,你說我怎么就攤上這事掷伙∈羌海” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵任柜,是天一觀的道長(zhǎng)卒废。 經(jīng)常有香客問我沛厨,道長(zhǎng),這世上最難降的妖魔是什么摔认? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任逆皮,我火速辦了婚禮,結(jié)果婚禮上级野,老公的妹妹穿的比我還像新娘页屠。我一直安慰自己,他們只是感情好蓖柔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布辰企。 她就那樣靜靜地躺著,像睡著了一般况鸣。 火紅的嫁衣襯著肌膚如雪牢贸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天镐捧,我揣著相機(jī)與錄音潜索,去河邊找鬼。 笑死懂酱,一個(gè)胖子當(dāng)著我的面吹牛竹习,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播列牺,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼整陌,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了瞎领?” 一聲冷哼從身側(cè)響起泌辫,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎九默,沒想到半個(gè)月后震放,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡驼修,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年殿遂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乙各。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡勉躺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出觅丰,到底是詐尸還是另有隱情,我是刑警寧澤妨退,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布妇萄,位于F島的核電站蜕企,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏冠句。R本人自食惡果不足惜轻掩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望懦底。 院中可真熱鬧唇牧,春花似錦、人聲如沸聚唐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽杆查。三九已至扮惦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間亲桦,已是汗流浹背崖蜜。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留客峭,地道東北人豫领。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像舔琅,于是被迫代替她去往敵國和親等恐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗(yàn)搏明。 張土汪:刷leetcod...
    土汪閱讀 12,745評(píng)論 0 33
  • 做TDD是為什么鼠锈? 關(guān)于TDD的概念、工具星著、技巧等购笆,經(jīng)典的書籍材料可能介紹的更為全面細(xì)致。這篇文章想分享的是從一個(gè)...
    武可閱讀 2,601評(píng)論 2 21
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理虚循,服務(wù)發(fā)現(xiàn)同欠,斷路器,智...
    卡卡羅2017閱讀 134,657評(píng)論 18 139
  • 前些天,我的國學(xué)老師去曲阜參加了一個(gè)學(xué)術(shù)討論研究會(huì)茎刚,深受啟發(fā)襟锐,回來就和我們講她在這次會(huì)議上的所見所聞。 我的老師和...
    鹿知之閱讀 483評(píng)論 2 4
  • 如果膛锭,累了倦了粮坞, 如果蚊荣,碰巧想起了我。 如果莫杈,你愿意互例。 來我的長(zhǎng)街,做我的歸人筝闹。 世界那么大媳叨,我們每天會(huì)遇見熟...
    Ai那個(gè)他閱讀 362評(píng)論 1 0