五招幫你正確處理前任程序員留下的代碼
作為軟件工程師不可避免會(huì)遇到的一個(gè)場(chǎng)景是:我們?cè)诟淖兓蛱砑右粋€(gè)功能到不是我們創(chuàng)建的、我們不熟悉的、與我們負(fù)責(zé)的系統(tǒng)部分無關(guān)的代碼中時(shí),會(huì)遇到麻煩。雖然這可能會(huì)是一個(gè)繁瑣而艱巨的任務(wù),但是由于使用其他開發(fā)人員編寫的代碼有很大的靈活性,所以我們可以從中得到大大的好處,包括增加我們的影響范圍,修復(fù)軟件腐爛以及學(xué)習(xí)我們以前不了解的系統(tǒng)部分(更何況,還可以學(xué)習(xí)其他程序員的技術(shù)和技巧)。
考慮到使用其他開發(fā)人員編寫的代碼既有其厭煩之處,又有其優(yōu)勢(shì)所在,所以我們必須小心不要犯一些嚴(yán)重的錯(cuò)誤:
- 我們的自我意識(shí):我們可能會(huì)覺得自己知道得最多,但通常事實(shí)并非如此。我們要更改的是我們知之甚少的代碼——我們不知道原作者的意圖、導(dǎo)致此代碼的決策以及原作者在寫代碼時(shí)可用的工具和框架,等等。謙遜的品質(zhì)價(jià)值千金,你值得擁有。
 - 原作者的自我意識(shí):我們即將接觸的代碼是由另一個(gè)開發(fā)人員所編寫的,另一種風(fēng)格、約束、期限和個(gè)人生活(消耗他或她工作之外的時(shí)間)。只有當(dāng)我們開始質(zhì)疑他或她做出的決定或質(zhì)疑代碼為什么這么不干凈的時(shí)候,那人才會(huì)自我反省,不至于夜郎自大。我們應(yīng)該盡一切努力讓原作者幫助我們工作,而不是妨礙我們。
 - 對(duì)未知的恐懼:很多時(shí)候,我們將要接觸的代碼是我們知之甚少或完全一無所知的。令人害怕的是:我們將對(duì)我們所做的任何改變負(fù)責(zé),但是我們基本上就像是在沒有光線的黑暗屋子里走動(dòng)一樣。其實(shí)我們不需要擔(dān)心,而是應(yīng)該構(gòu)建一種使我們能夠在大小不一的改變中感到舒適的結(jié)構(gòu),并允許我們確保沒有破壞現(xiàn)有的功能。
 
由于開發(fā)人員,包括我們自己,是人,所以在處理其他開發(fā)人員編寫的代碼時(shí),處理好很多人的天性問題是很有用的。在這篇文章中,我們將通過我們可以使用的五種技術(shù)來確保將對(duì)人性的理解成為我們的優(yōu)勢(shì),從現(xiàn)有代碼和原作者汲取盡可能多的幫助,并使得其他開發(fā)人員編寫的代碼最后變得比原來更優(yōu)秀。雖然這里列出的5個(gè)方法并不全面,但是使用下面的技術(shù)將確保在結(jié)束改動(dòng)其他開發(fā)人員編寫的代碼時(shí),我們有信心保持現(xiàn)有功能的工作狀態(tài),同時(shí)確保我們的新功能與現(xiàn)有的代碼庫協(xié)調(diào)一致。
1.確保測(cè)試的存在
要想確保在其他開發(fā)人員編寫的代碼中所存在的現(xiàn)有功能實(shí)際能夠按照預(yù)期的方式工作,并且我們對(duì)其進(jìn)行的任何更改都不會(huì)影響到功能的實(shí)現(xiàn),唯一真正令人信心十足的方式是用測(cè)試來支持代碼。當(dāng)我們遇到另一位開發(fā)人員編寫的代碼時(shí),代碼有兩種所處的狀態(tài):(1)沒有足夠的測(cè)試水平,或(2)有足夠的測(cè)試水平。遇到前一種情況,我們得負(fù)責(zé)創(chuàng)建測(cè)試,而在后一種情況下,我們可以使用現(xiàn)有的測(cè)試來確保我們做出的任何更改都不會(huì)破壞代碼,并盡可能多地從測(cè)試去了解代碼的意圖。
創(chuàng)建新測(cè)試
這是一個(gè)悲傷的例子:我們?cè)诟淖兤渌_發(fā)人員的代碼時(shí),要對(duì)更改結(jié)果負(fù)責(zé),但是我們沒有辦法保證我們?cè)谶M(jìn)行更改時(shí)不破壞任何東西。抱怨是沒有用的。無論我們發(fā)現(xiàn)代碼處在什么樣的條件下,我們總歸是要接觸代碼,因此如果代碼壞掉了,就是我們的責(zé)任。所以我們?cè)诟淖兇a時(shí),一定要掌控自己的行為。確定不會(huì)破壞代碼的唯一方法是自己寫測(cè)試。
雖然這是乏味的,但它允許我們通過編寫測(cè)試來學(xué)習(xí),這是它的主要優(yōu)點(diǎn)。假設(shè)代碼現(xiàn)在可以正常工作,而我們需要編寫測(cè)試,以便預(yù)期的輸入會(huì)導(dǎo)致預(yù)期的輸出。在我們完成這個(gè)測(cè)試的過程中,我們逐漸了解到代碼的意圖和功能。例如,給出以下代碼
- public class SuccessfulFilterTest {
 - private static final double THRESHOLD_NET_SALARY = 68330.0;
 - @Test
 - public void under30AndNettingThresholdEnsureSuccessful() {
 - Person person = new Person(29, THRESHOLD_NET_SALARY);
 - Assert.assertTrue(new SuccessfulFilter().test(person));
 - }
 - @Test
 - public void exactly30AndNettingThresholdEnsureUnsuccessful() {
 - Person person = new Person(30, THRESHOLD_NET_SALARY);
 - Assert.assertFalse(new SuccessfulFilter().test(person));
 - }
 - @Test
 - public void under30AndNettingLessThanThresholdEnsureSuccessful() {
 - Person person = new Person(29, THRESHOLD_NET_SALARY - 1);
 - Assert.assertFalse(new SuccessfulFilter().test(person));
 - }
 - }
 
我們對(duì)代碼的意圖以及為什么在代碼中使用Magic number知道得并不多,但是我們可以創(chuàng)建一組測(cè)試,已知輸入產(chǎn)生已知輸出。例如,通過做一些簡(jiǎn)單的數(shù)學(xué)和解決構(gòu)成成功的閾值薪水問題,我們發(fā)現(xiàn)如果一個(gè)人的年齡在30歲以下,且每年大概賺68,330美元,那么他被認(rèn)為是成功的(按照本規(guī)范的標(biāo)準(zhǔn))。雖然我們不知道那些magic number是什么,但是我們知道它們確實(shí)減少了初始的薪水值。因此,68,330美元的閾值是扣除前的基本工資。通過使用這些信息,我們可以創(chuàng)建一些簡(jiǎn)單的測(cè)試,例如:
- public class SuccessfulFilterTest {
 - private static final double THRESHOLD_NET_SALARY = 68330.0;
 - @Test
 - public void under30AndNettingThresholdEnsureSuccessful() {
 - Person person = new Person(29, THRESHOLD_NET_SALARY);
 - Assert.assertTrue(new SuccessfulFilter().test(person));
 - }
 - @Test
 - public void exactly30AndNettingThresholdEnsureUnsuccessful() {
 - Person person = new Person(30, THRESHOLD_NET_SALARY);
 - Assert.assertFalse(new SuccessfulFilter().test(person));
 - }
 - @Test
 - public void under30AndNettingLessThanThresholdEnsureSuccessful() {
 - Person person = new Person(29, THRESHOLD_NET_SALARY - 1);
 - Assert.assertFalse(new SuccessfulFilter().test(person));
 - }
 - }
 
通過這三個(gè)測(cè)試,我們現(xiàn)在對(duì)現(xiàn)有代碼的工作方式有了大致的了解:如果一個(gè)人不到30歲,且每年賺$ 68,300,那么他被認(rèn)為是成功人士。雖然我們可以創(chuàng)建更多的測(cè)試來確保臨界情況(例如空白年齡或工資)功能正常,但是一些簡(jiǎn)短的測(cè)試不僅使我們了解了原始功能,還給出了一套自動(dòng)化測(cè)試,可用于確保在對(duì)現(xiàn)有代碼進(jìn)行更改時(shí),我們不會(huì)破壞現(xiàn)有功能。
使用現(xiàn)有測(cè)試
如果有足夠的代碼測(cè)試組件,那么我們可以從測(cè)試中學(xué)到很多東西。正如我們創(chuàng)建測(cè)試一樣,通過閱讀測(cè)試,我們可以了解代碼如何在功能層面上工作。此外,我們還可以知道原作者是如何讓代碼運(yùn)行的。即使測(cè)試是由原作者以外的人(在我們接觸之前)撰寫的,也依然能夠?yàn)槲覀兲峁╆P(guān)于其他人對(duì)代碼的看法。
雖然現(xiàn)有的測(cè)試可以提供幫助,但我們?nèi)匀恍枰獙?duì)此持保留態(tài)度。測(cè)試是否與代碼的開發(fā)更改一起與時(shí)俱進(jìn)是很難說的。如果是的話,那么這是一個(gè)很好的理解基礎(chǔ);如果不是,那么我們要小心不要被誤導(dǎo)。例如,如果初始的工資閾值是每年75,000美元,而后來更改為我們的68,330美元,那么下面這個(gè)過時(shí)的測(cè)試可能會(huì)使我們誤入歧途:
- @Test
 - public void under30AndNettingThresholdEnsureSuccessful() {
 - Person person = new Person(29, 75000.0);
 - Assert.assertTrue(new SuccessfulFilter().test(person));
 - }
 
這個(gè)測(cè)試還是會(huì)通過的,但沒有了預(yù)期的作用。通過的原因不是因?yàn)樗檬情撝?,而是因?yàn)樗隽碎撝怠H绻藴y(cè)試組件包含這樣一個(gè)測(cè)試用例:當(dāng)薪水低于閾值1美元時(shí),過濾器就返回false,這樣第二個(gè)測(cè)試將會(huì)失敗,表明閾值是錯(cuò)誤的。如果套件沒有這樣的測(cè)試,那么陳舊的數(shù)據(jù)會(huì)很容易誤導(dǎo)我們弄錯(cuò)代碼的真正意圖。當(dāng)有疑問時(shí),請(qǐng)相信代碼:正如我們之前所表述的那樣,求解閾值表明測(cè)試沒有對(duì)準(zhǔn)實(shí)際閾值。
另外,要查看代碼和測(cè)試用例的存儲(chǔ)庫日志(即Git日志):如果代碼的最后更新日期比測(cè)試的最后更新日期更近(對(duì)代碼進(jìn)行了重大更改,例如更改閾值),則測(cè)試可能已經(jīng)過時(shí),應(yīng)謹(jǐn)慎查看。注意,我們不應(yīng)該完全忽視測(cè)試,因?yàn)樗鼈円苍S仍然能為我們提供關(guān)于原作者(或最近撰寫測(cè)試的開發(fā)人員)意圖的一些文檔,但它們可能包含過時(shí)或不正確的數(shù)據(jù)。
2.與編寫代碼的人交流
在涉及多個(gè)人的任何工作中,溝通至關(guān)重要。無論是企業(yè),越野旅行還是軟件項(xiàng)目,缺乏溝通是損害任務(wù)最有效的手段之一。即使我們?cè)趧?chuàng)建新代碼時(shí)進(jìn)行溝通,但是當(dāng)我們接觸現(xiàn)有的代碼時(shí),風(fēng)險(xiǎn)會(huì)增加。因?yàn)榇藭r(shí)我們對(duì)現(xiàn)有的代碼并不太了解,因此我們所了解的內(nèi)容可能是被誤導(dǎo)的,或只代表了其中的一小部分。為了真正了解現(xiàn)有的代碼,我們需要和編寫它的人交流。
當(dāng)開始提出問題時(shí),我們需要確定問題是具體的,并且旨在實(shí)現(xiàn)我們理解代碼的目標(biāo)。例如:
- 這個(gè)代碼片段最適合放到系統(tǒng)的哪里?
 - 你有什么設(shè)計(jì)或圖表嗎?
 - 我應(yīng)該注意什么陷阱?
 - 這個(gè)組件或類是做什么的?
 - 有沒有什么你想放到代碼里,但當(dāng)時(shí)沒有做的?為什么?
 
始終要保持謙虛的態(tài)度,積極尋求原作者真正的答案。幾乎每個(gè)開發(fā)人員都碰到過這樣的場(chǎng)景,他或她看著別人的代碼,自問自答:“為什么他/她要這樣做?為什么他們不這樣做?”然后花幾個(gè)小時(shí)來得出本來只要原作者回答就能得到的結(jié)論。大多數(shù)開發(fā)人員都是有才華的程序員,所以即使如果我們遇到一個(gè)看似糟糕的決定,也有可能有一個(gè)很好的理由(可能沒有,但研究別人的代碼時(shí)最好假設(shè)他們這樣做是有原因的;如果真的沒有,我們可以通過重構(gòu)來改變)。
溝通在軟件開發(fā)中起次要副作用。1967年最初由Melvin Conway創(chuàng)立的康威定律規(guī)定:
- 設(shè)計(jì)系統(tǒng)的任何組織…都將不可避免地產(chǎn)生一種設(shè)計(jì),該設(shè)計(jì)結(jié)構(gòu)反映了組織的通信結(jié)構(gòu)。
 
這意味著,一個(gè)龐大、緊密溝通的團(tuán)隊(duì)可能會(huì)生成一體化,緊密耦合的代碼,但一些較小的團(tuán)隊(duì)可能會(huì)生成更獨(dú)立、松散耦合的代碼(有關(guān)此相關(guān)性的更多信息,請(qǐng)參閱《Demystifying Conway’s Law》)。對(duì)于我們來說,這意味著我們的通信結(jié)構(gòu)不僅影響特定的代碼段,也影響整個(gè)代碼庫。因此,與原作者密切溝通絕對(duì)是一個(gè)好辦法,但我們應(yīng)該自檢不要太過于依賴于原作者。這不僅可能會(huì)惹惱原作者,還可能在我們的代碼中產(chǎn)生無意識(shí)的耦合。
雖然這有助于我們深入研究代碼,但這是在假設(shè)可以接觸原作者的情況下。在很多時(shí)候,原作者可能已經(jīng)離開了公司,或恰巧不在公司(例如正在休假)。在此種情況下我們?cè)撟鍪裁?詢問可能對(duì)代碼有所了解的人。這個(gè)人不一定要曾真正工作于代碼,他可以是在原作者編寫代碼時(shí)就在周圍,也可以是認(rèn)識(shí)原作者。哪怕僅是從原開發(fā)者周圍的人中得到只言片語,也可能會(huì)啟迪其他未知的代碼片段。
3.刪除所有警告
心理學(xué)中有一個(gè)眾所周知的概念,稱為“破窗理論”,Andrew Hunt和Dave Thomas在《 The Pragmatic Programmer 》(第4-6頁)中詳細(xì)描述了這個(gè)概念。這個(gè)理論最初是由James Q.Wilson和George L. Kelling提出的,描述如下:
假設(shè)有一個(gè)建筑物有幾扇破了的窗戶。如果窗戶沒有修好,那么破壞者會(huì)趨向于打破更多的窗戶。最終,他們甚至可能會(huì)破門而入,如果建筑物是沒人住的,那么他們可能會(huì)非法占有或者在里面點(diǎn)火。也可以考慮人行道的情況。如果道路上面有垃圾堆積,那么不久之后,就會(huì)有更多的垃圾累積。最終,人們甚至?xí)_始往那里扔外賣垃圾,甚至打破汽車。
這個(gè)理論指出,如果似乎已經(jīng)沒人關(guān)心這個(gè)物品或事物,那么我們就會(huì)忽視對(duì)物品或事物的照顧,這是人的天性。例如,如果一棟建筑物看上去已經(jīng)凌亂不堪,那么它更有可能被肆意破壞。在軟件方面,這個(gè)理論意味著如果開發(fā)人員發(fā)現(xiàn)代碼已經(jīng)是一團(tuán)糟,那么人的本性會(huì)讓他弄壞代碼。從本質(zhì)上說,我們心里想的是(即使心理活動(dòng)沒有這么豐富),“既然最后一個(gè)人不在乎這代碼,我為什么要在乎?”或“都是亂糟糟的代碼,誰知道是誰寫的。”
但是,這不應(yīng)該成為我們的借口。只要我們接觸以前屬于其他人的代碼,那么我們就要對(duì)這些代碼負(fù)責(zé),并且如果它不能有效工作的話,我們得擔(dān)負(fù)后果。為了戰(zhàn)勝這種人的天性行為,我們需要采取一些小措施以避免我們的代碼更少地被弄臟(及時(shí)更換破掉的窗戶)。
一個(gè)簡(jiǎn)單方法是刪除來自我們正在使用的整個(gè)包或模塊中的所有警告。至于未使用或添加注釋的代碼,刪除它。如果我們稍后需要這部分代碼,那么在存儲(chǔ)庫中,我們總是可以從先前的提交中檢索它。如果存在無法直接解決的警告(例如原始類型警告),那么使用@SuppressWarnings注解注釋該調(diào)用或方法。這樣可以確保我們對(duì)代碼進(jìn)行過仔細(xì)的考慮:它們不是因?yàn)槭韬龆l(fā)出的警告,而是我們明確地注意到了警告(如原始類型)。
一旦我們刪除或明確地禁止所有警告,那么我們就必須確保代碼保持免除警告。這有兩個(gè)主要作用:
- 迫使我們仔細(xì)考慮我們創(chuàng)建的任何代碼。
 - 減少代碼腐敗的變化,現(xiàn)在的警告會(huì)導(dǎo)致以后的錯(cuò)誤。
 
這對(duì)其他人,以及我們自己都有心理暗示作用——我們其實(shí)關(guān)心我們正在處理的代碼。它不再是條單行線——我們強(qiáng)逼著自己更改代碼,提交,然后永不回頭。相反,我們認(rèn)識(shí)到我們需要對(duì)這代碼負(fù)責(zé)。這對(duì)之后的軟件開發(fā)也是有幫助的——它向?qū)淼拈_發(fā)人員展示,這不是一間窗戶都破了的倉庫:而是一個(gè)維護(hù)良好的代碼庫。
4.重構(gòu)
在過去幾十年中,重構(gòu)已經(jīng)成為了一個(gè)非常重要的術(shù)語,并且最近被當(dāng)作是對(duì)當(dāng)前工作代碼做任何改變的代名詞。雖然重構(gòu)確實(shí)涉及對(duì)當(dāng)前正在工作的代碼的更改,但并非整個(gè)大局。Martin Fowler在他關(guān)于這個(gè)話題的重要著作——《Refactoring》一書中將重構(gòu)定義為:
- 對(duì)軟件的內(nèi)部結(jié)構(gòu)進(jìn)行更改,使其更容易理解并且修改起來更便宜,而不改變其可觀察的行為。
 
這個(gè)定義的關(guān)鍵在于它涉及的更改不會(huì)改變系統(tǒng)可觀察的行為。這意味著當(dāng)我們重構(gòu)代碼時(shí),我們必須要有方法來確保代碼的外部可見行為不會(huì)改變。在我們的例子中,這意味著是在我們繼承或自己開發(fā)的測(cè)試套件中。為了確保我們沒有改變系統(tǒng)的外部行為,每當(dāng)我們進(jìn)行改變時(shí),都必須重新編譯和執(zhí)行我們的全部測(cè)試。
此外,并不是我們所做的每一個(gè)改變都被認(rèn)為是重構(gòu)。例如,重命名方法以更好地反映其預(yù)期用途是重構(gòu),但添加新功能不是。為了看到重構(gòu)的好處,我們將重構(gòu)SuccessfulFilter。執(zhí)行的第一個(gè)重構(gòu)是提取方法,以更好地封裝個(gè)人凈工資的邏輯:
- public class SuccessfulFilter implements Predicate<Person> {
 - @Override
 - public boolean test(Person person) {
 - return person.getAge() < 30 && getNetSalary(person) > 60000;
 - }
 - private double getNetSalary(Person person) {
 - return (((person.getSalary() - (250 * 12)) - 1500) * 0.94);
 - }
 - }
 
在我們進(jìn)行這種改變之后,我們重新編譯并運(yùn)行我們的測(cè)試套件,測(cè)試套件將繼續(xù)通過?,F(xiàn)在更容易看出,成功是通過一個(gè)人的年齡和凈薪酬定義的,但是getNetSalary方法似乎并不像Person類一樣屬于SuccessfulFilter(指示標(biāo)志就是該方法的唯一參數(shù)是Person,該方法的唯一調(diào)用是Person類的方法,因此對(duì)Person類有很強(qiáng)的親和力)。 為了更好地定位這個(gè)方法,我們執(zhí)行一個(gè)Move方法將其移動(dòng)到Person類:
- public class Person {
 - private int age;
 - private double salary;
 - public Person(int age, double salary) {
 - this.age = age;
 - this.salary = salary;
 - }
 - public void setAge(int age) {
 - this.age = age;
 - }
 - public int getAge() {
 - return age;
 - }
 - public void setSalary(double salary) {
 - this.salary = salary;
 - }
 - public double getSalary() {
 - return salary;
 - }
 - public double getNetSalary() {
 - return ((getSalary() - (250 * 12)) - 1500) * 0.94;
 - }
 - }
 - public class SuccessfulFilter implements Predicate<Person> {
 - @Override
 - public boolean test(Person person) {
 - return person.getAge() < 30 && person.getNetSalary() > 60000;
 - }
 - }
 
為了進(jìn)一步清理此代碼,我們對(duì)每個(gè)magic number執(zhí)行符號(hào)常量替換magic number行為。為了知道這些值的含義,我們可能得和原作者交流,或者向具有足夠領(lǐng)域知識(shí)的人請(qǐng)教,以引領(lǐng)正確的方向。我們還將執(zhí)行更多的提取方法重構(gòu),以確?,F(xiàn)有的方法盡可能簡(jiǎn)單。
- public class Person {
 - private static final int MONTHLY_BONUS = 250;
 - private static final int YEARLY_BONUS = MONTHLY_BONUS * 12;
 - private static final int YEARLY_BENEFITS_DEDUCTIONS = 1500;
 - private static final double YEARLY_401K_CONTRIBUTION_PERCENT = 0.06;
 - private static final double YEARLY_401K_CONTRIBUTION_MUTLIPLIER = 1 - YEARLY_401K_CONTRIBUTION_PERCENT;
 - private int age;
 - private double salary;
 - public Person(int age, double salary) {
 - this.age = age;
 - this.salary = salary;
 - }
 - public void setAge(int age) {
 - this.age = age;
 - }
 - public int getAge() {
 - return age;
 - }
 - public void setSalary(double salary) {
 - this.salary = salary;
 - }
 - public double getSalary() {
 - return salary;
 - }
 - public double getNetSalary() {
 - return getPostDeductionSalary();
 - }
 - private double getPostDeductionSalary() {
 - return getPostBenefitsSalary() * YEARLY_401K_CONTRIBUTION_MUTLIPLIER;
 - }
 - private double getPostBenefitsSalary() {
 - return getSalary() - YEARLY_BONUS - YEARLY_BENEFITS_DEDUCTIONS;
 - }
 - }
 - public class SuccessfulFilter implements Predicate<Person> {
 - private static final int THRESHOLD_AGE = 30;
 - private static final double THRESHOLD_SALARY = 60000.0;
 - @Override
 - public boolean test(Person person) {
 - return person.getAge() < THRESHOLD_AGE && person.getNetSalary() > THRESHOLD_SALARY;
 - }
 - }
 
重新編譯和測(cè)試,發(fā)現(xiàn)系統(tǒng)仍然按照預(yù)期的方式工作:我們沒有改變外部行為,但是我們改進(jìn)了代碼的可靠性和內(nèi)部結(jié)構(gòu)。有關(guān)更復(fù)雜的重構(gòu)和重構(gòu)過程,請(qǐng)參閱Martin Fowler的Refactoring Guru網(wǎng)站。
5.當(dāng)你離開的時(shí)候,代碼比你發(fā)現(xiàn)它的時(shí)候更好
最后這個(gè)技術(shù)在概念上非常簡(jiǎn)單,但在實(shí)踐中很困難:讓代碼比你發(fā)現(xiàn)它的時(shí)候更好。當(dāng)我們梳理代碼,特別是別人的代碼時(shí),我們大多會(huì)添加功能,測(cè)試它,然后前行,不關(guān)心我們會(huì)不會(huì)貢獻(xiàn)軟件腐爛,也不在乎我們添加到類的新方法會(huì)不會(huì)導(dǎo)致額外的混亂。因此,本文的全部?jī)?nèi)容可總結(jié)為以下規(guī)則:
- 每當(dāng)我們修改代碼時(shí),請(qǐng)確保當(dāng)你離開的時(shí)候,代碼比你發(fā)現(xiàn)它的時(shí)候更好。
 
前面提到過,我們需要對(duì)類造成的損壞和對(duì)改變的代碼負(fù)責(zé),如果它不能工作,那么修復(fù)是我們的職責(zé)。為了戰(zhàn)勝伴隨軟件生產(chǎn)而出現(xiàn)的熵,我們必須強(qiáng)制自己做到離開時(shí)的代碼比我們發(fā)現(xiàn)它的時(shí)候更佳。為了不逃避這個(gè)問題,我們必須償還技術(shù)債務(wù),確保下一個(gè)接觸代碼的人不需要再付出代價(jià)。說不定,將來可能是我們自己感謝自己這個(gè)時(shí)候的堅(jiān)持呢。















 
 
 




 
 
 
 