應(yīng)該有很多人已經(jīng)知道破窗效應(yīng)這個(gè)社會(huì)學(xué)(犯罪學(xué))的詞語,破窗效應(yīng)先由社會(huì)學(xué)家JamesQ.Wilson和GeorgeL.Kelling在一篇名為《BrokenWindows》的文章中提出:

  “一個(gè)房子如果窗戶破了,沒有人去修補(bǔ),隔不久,其它的窗戶也會(huì)莫名其妙地被人打破;一面墻,如果出現(xiàn)一些涂鴉沒有被清洗掉,很快的,墻上布滿了亂七八糟、不堪入目的東西;一個(gè)很干凈的地方,人們不好意思丟垃圾,但是一旦地上有垃圾出現(xiàn)之后,人會(huì)毫不猶疑地拋,絲毫不覺羞愧。”

  我們一直在喊敏捷開發(fā),其實(shí)敏捷開發(fā)的一個(gè)很重要的目的是消除浪費(fèi),防止破窗效應(yīng)的發(fā)生。事情太難,讓它簡單,更簡單。流程太重,讓它輕點(diǎn),更輕點(diǎn)。盡量掃清開發(fā)的障礙,消滅破窗形成的環(huán)境。下面我會(huì)從軟件構(gòu)建的很多方面來描述如何防止“軟件開發(fā)中的破窗”。

  臟代碼

  如果代碼不整潔,后來人很難看懂,人們往往會(huì)對(duì)難以看懂的代碼失去耐心,不愿意進(jìn)一步了解。如果不能進(jìn)一步了解一部分代碼,也難以改進(jìn)它,這樣帶來的一個(gè)后果可能有兩點(diǎn):1、這段代碼被拋棄,然后重新編寫。2、直接復(fù)制這段代碼在別的地方使用。對(duì)于第一點(diǎn),會(huì)帶來軟件開發(fā)中的浪費(fèi),而且再次編寫也不可能能一部到位的編寫正確,可能會(huì)引入新的bug。對(duì)于第二點(diǎn),大家都知道重復(fù)代碼是設(shè)計(jì)走向腐化的根源之一。

  如果我們?cè)诰帉懘a時(shí)能不斷的應(yīng)用一些原則,確保我們的代碼易懂,自描述。在開發(fā)新特性時(shí)還不斷的使用重構(gòu)手段,讓我們的設(shè)計(jì)保持一個(gè)良好的狀態(tài)。我們能防止窗戶被繼續(xù)打破。

  測試

  沒有測試,或者混亂的測試代碼都是破窗滋生的環(huán)境。

  沒有測試

  沒有測試時(shí),當(dāng)我們想對(duì)一塊代碼進(jìn)行重構(gòu),我們像沒有帶保險(xiǎn)繩走鋼絲,步履維艱,生怕一下子失去平衡,掉下懸崖。這樣在我們的心中產(chǎn)生了懼怕重構(gòu)的陰影,久而久之,我們不去重構(gòu)。后帶來的結(jié)果跟上面一段說的一樣,設(shè)計(jì)不斷的腐化,然后失去了控制。

  如果有了單元測試,有了驗(yàn)收測試,當(dāng)我們每做一下重構(gòu)時(shí),我們都可以從測試快速獲得反饋,每當(dāng)紅條亮起時(shí),我們知道我們破壞了一些已有的功能,我們停下來去修復(fù),當(dāng)綠條亮起時(shí),我們知道現(xiàn)在處于安全狀態(tài),可以安心的繼續(xù)重構(gòu)。一切都在我們的掌控之中,我們會(huì)喜歡上重構(gòu)。

  混亂的測試代碼

  有很多人覺得測試代碼不是交付給用戶的產(chǎn)品代碼,可以區(qū)別對(duì)待,我們不需要花那么多時(shí)間琢磨變量命名,方法命名,我們也不需要關(guān)注重復(fù)的代碼。但是……

  混亂的測試代碼跟沒有測試是一樣的,甚至比沒有測試更糟糕。我們以為我們有測試,但測試卻給我們虛假的報(bào)告,當(dāng)我們發(fā)現(xiàn)我們的重構(gòu)破壞如此之深時(shí),已經(jīng)為時(shí)已晚。即使測試能給出真實(shí)的報(bào)告,但如果測試代碼混亂,那么添加新的測試非常困難,我們會(huì)越來越懼怕添加新的測試。而且隨著產(chǎn)品代碼的演進(jìn),測試代碼也需要伴隨著演進(jìn),測試代碼越混亂,我們?cè)诫y以修改測試,讓它反應(yīng)出現(xiàn)在產(chǎn)品代碼的狀態(tài)。終于到了,大家決定拋棄測試,如是我們又回到了沒有測試作保障的日子。

  實(shí)際上,從某種程度上測試代碼的整潔程度比產(chǎn)品代碼的整潔程度更重要,因?yàn)橛辛撕玫臏y試我們可以無憂無慮的重構(gòu)我們的代碼,即使現(xiàn)在我們的產(chǎn)品代碼很糟糕也不怕,因?yàn)橛辛藴y試的保證,我們知道我們可以重構(gòu)過去,如果我們只有混亂的測試代碼,我們那一線重構(gòu)的希望都沒有了。

  難以測試

  可測試性是衡量代碼的一項(xiàng)準(zhǔn)則。既然是準(zhǔn)則一般都很難達(dá)到,如果代碼難以添加測試,在嘗試幾次之后,我們一般都會(huì)放棄編寫測試的想法。當(dāng)我們嘗試對(duì)一段代碼編寫測試時(shí)發(fā)現(xiàn),這塊代碼鐵板一塊,與太多的其他類耦合,需要傳入很多重型對(duì)象的參數(shù),比如與設(shè)備交互的代碼,與數(shù)據(jù)庫交互的代碼相耦合,這些重型對(duì)象很難模擬或插樁。沒有辦法,在進(jìn)度的壓力下我們只有放棄添加測試的想法了,那么如上面一樣,代碼像草原上奔跑的野獸,失去了控制。

  編寫可測試性的代碼是困難的,要將糟糕的代碼改進(jìn)成可測的代碼尤其困難。但有一個(gè)訣竅,我們可以先編寫測試,用測試驅(qū)動(dòng)出我們的產(chǎn)品代碼,這樣一開始我們獲得了一個(gè)個(gè)測試套件,將我們的產(chǎn)品代碼穩(wěn)穩(wěn)的固定在那里,像走鋼絲時(shí)的保險(xiǎn)繩;不僅如此,我們還獲得了可測試性的代碼。