如何處理前任程序員留下的代碼
來(lái)源:原創(chuàng) 時(shí)間:2017-10-30 瀏覽:0 次作為軟件工程師不可防止會(huì)遇到的一個(gè)場(chǎng)景是:我們?cè)诟膭?dòng)或增加一個(gè)功用到不是我們創(chuàng)立的、我們不熟悉的、與我們擔(dān)任的體系部分無(wú)關(guān)的代碼中時(shí),會(huì)遇到費(fèi)事。盡管這可能會(huì)是一個(gè)繁瑣而艱巨的使命,可是由于運(yùn)用其他開(kāi)發(fā)人員編寫的代碼有很大的靈活性,所以我們能夠從中得到大大的長(zhǎng)處,包括增加我們的影響規(guī)模,修正軟件腐朽以及學(xué)習(xí)我們?cè)?jīng)不了解的體系部分(更何況,還能夠?qū)W習(xí)其他程序員的技能和技巧)。
考慮到運(yùn)用其他開(kāi)發(fā)人員編寫的代碼既有其厭煩之處,又有其優(yōu)勢(shì)地點(diǎn),所以我們有必要當(dāng)心不要犯一些嚴(yán)峻的過(guò)錯(cuò):
我們的自我意識(shí):我們可能會(huì)覺(jué)得自己知道得最多,但一般現(xiàn)實(shí)并非如此。我們要更改的是我們知之甚少的代碼——我們不知道原作者的目的、導(dǎo)致此代碼的決議計(jì)劃以及原作者在寫代碼時(shí)可用的東西和結(jié)構(gòu),等等。謙遜的質(zhì)量無(wú)價(jià)之寶,你值得具有。
原作者的自我意識(shí):我們行將觸摸的代碼是由另一個(gè)開(kāi)發(fā)人員所編寫的,另一種風(fēng)格、束縛、期限和個(gè)人日子(耗費(fèi)他或她作業(yè)之外的時(shí)刻)。只需當(dāng)我們開(kāi)端質(zhì)疑他或她做出的決議或質(zhì)疑代碼為什么這么不潔凈的時(shí)分,那人才會(huì)自我檢討,不至于自高自大。我們應(yīng)該盡悉數(shù)盡力讓原作者協(xié)助我們作業(yè),而不是阻礙我們。
對(duì)不知道的驚駭:許多時(shí)分,我們即將觸摸的代碼是我們知之甚少或徹底一竅不通的。令人懼怕的是:我們將對(duì)我們所做的任何改動(dòng)擔(dān)任,可是我們基本上就像是在沒(méi)有光線的漆黑屋子里走動(dòng)一樣。其實(shí)我們不需求憂慮,而是應(yīng)該構(gòu)建一種使我們能夠在大小紛歧的改動(dòng)中感到舒適的結(jié)構(gòu),并答應(yīng)我們保證沒(méi)有損壞現(xiàn)有的功用。
由于開(kāi)發(fā)人員,包括我們自己,是人,所以在處理其他開(kāi)發(fā)人員編寫的代碼時(shí),處理好許多人的天分問(wèn)題是很有用的。在這篇文章中,我們將經(jīng)過(guò)我們能夠運(yùn)用的五種技能來(lái)保證將對(duì)人道的了解成為我們的優(yōu)勢(shì),從現(xiàn)有代碼和原作者羅致盡可能多的協(xié)助,并使得其他開(kāi)發(fā)人員編寫的代碼終究變得比正本更優(yōu)異。盡管這兒列出的5個(gè)辦法并不全面,可是運(yùn)用下面的技能將保證在完畢改動(dòng)其他開(kāi)發(fā)人員編寫的代碼時(shí),我們有決心堅(jiān)持現(xiàn)有功用的作業(yè)狀況,一同保證我們的新功用與現(xiàn)有的代碼庫(kù)協(xié)調(diào)一致。
work-with-someone-else-code
1.保證測(cè)驗(yàn)的存在
要想保證在其他開(kāi)發(fā)人員編寫的代碼中所存在的現(xiàn)有功用實(shí)踐能夠依照預(yù)期的辦法作業(yè),而且我們對(duì)其進(jìn)行的任何更改都不會(huì)影響到功用的完結(jié),僅有真實(shí)令人決心十足的辦法是用測(cè)驗(yàn)來(lái)支撐代碼。當(dāng)我們遇到另一位開(kāi)發(fā)人員編寫的代碼時(shí),代碼有兩種所在的狀況:(1)沒(méi)有滿足的測(cè)驗(yàn)水平,或(2)有滿足的測(cè)驗(yàn)水平。遇到前一種狀況,我們得擔(dān)任創(chuàng)立測(cè)驗(yàn),而在后一種狀況下,我們能夠運(yùn)用現(xiàn)有的測(cè)驗(yàn)來(lái)保證我們做出的任何更改都不會(huì)損壞代碼,并盡可能多地從測(cè)驗(yàn)去了解代碼的目的。
創(chuàng)立新測(cè)驗(yàn)
這是一個(gè)哀痛的比如:我們?cè)诟膭?dòng)其他開(kāi)發(fā)人員的代碼時(shí),要對(duì)更改成果擔(dān)任,可是我們沒(méi)有辦法保證我們?cè)谶M(jìn)行更改時(shí)不損壞任何東西。訴苦是沒(méi)有用的。不管我們發(fā)現(xiàn)代碼處在什么樣的條件下,我們總之是要觸摸代碼,因而如果代碼壞掉了,就是我們的責(zé)任。所以我們?cè)诟膭?dòng)代碼時(shí),一定要掌控自己的行為。斷定不會(huì)損壞代碼的僅有辦法是自己寫測(cè)驗(yàn)。
盡管這是庸俗的,但它答應(yīng)我們經(jīng)過(guò)編寫測(cè)驗(yàn)來(lái)學(xué)習(xí),這是它的首要長(zhǎng)處。假定代碼現(xiàn)在能夠正常作業(yè),而我們需求編寫測(cè)驗(yàn),以便預(yù)期的輸入會(huì)導(dǎo)致預(yù)期的輸出。在我們完結(jié)這個(gè)測(cè)驗(yàn)的進(jìn)程中,我們逐步了解到代碼的目的和功用。例如,給出以下代碼
我們對(duì)代碼的目的以及為什么在代碼中運(yùn)用Magic number知道得并不多,可是我們能夠創(chuàng)立一組測(cè)驗(yàn),已知輸入發(fā)生已知輸出。例如,經(jīng)過(guò)做一些簡(jiǎn)略的數(shù)學(xué)和處理構(gòu)成成功的閾值薪水問(wèn)題,我們發(fā)現(xiàn)如果一個(gè)人的年紀(jì)在30歲以下,且每年大約賺68,330美元,那么他被認(rèn)為是成功的(依照本規(guī)范的規(guī)范)。盡管我們不知道那些magic number是什么,可是我們知道它們的確削減了初始的薪水值。因而,68,330美元的閾值是扣除前的基本工資。經(jīng)過(guò)運(yùn)用這些信息,我們能夠創(chuàng)立一些簡(jiǎn)略的測(cè)驗(yàn),例如:
經(jīng)過(guò)這三個(gè)測(cè)驗(yàn),我們現(xiàn)在對(duì)現(xiàn)有代碼的作業(yè)辦法有了大致的了解:如果一個(gè)人不到30歲,且每年賺$ 68,300,那么他被認(rèn)為是成功人士。盡管我們能夠創(chuàng)立更多的測(cè)驗(yàn)來(lái)保證臨界狀況(例如空白年紀(jì)或工資)功用正常,可是一些簡(jiǎn)略的測(cè)驗(yàn)不只使我們了解了原始功用,還給出了一套自動(dòng)化測(cè)驗(yàn),可用于保證在對(duì)現(xiàn)有代碼進(jìn)行更改時(shí),我們不會(huì)損壞現(xiàn)有功用。
運(yùn)用現(xiàn)有測(cè)驗(yàn)
如果有滿足的代碼測(cè)驗(yàn)組件,那么我們能夠從測(cè)驗(yàn)中學(xué)到許多東西。正如我們創(chuàng)立測(cè)驗(yàn)一樣,經(jīng)過(guò)閱覽測(cè)驗(yàn),我們能夠了解代碼如安在功用層面上作業(yè)。此外,我們還能夠知道原作者是怎么讓代碼運(yùn)轉(zhuǎn)的。即便測(cè)驗(yàn)是由原作者以外的人(在我們觸摸之前)編撰的,也依然能夠?yàn)槲覀児┙o關(guān)于其他人對(duì)代碼的觀點(diǎn)。
盡管現(xiàn)有的測(cè)驗(yàn)?zāi)軌蚬┙o協(xié)助,但我們依然需求對(duì)此持保存情緒。測(cè)驗(yàn)是否與代碼的開(kāi)發(fā)更改一同與時(shí)俱進(jìn)是很難說(shuō)的。如果是的話,那么這是一個(gè)很好的了解根底;如果不是,那么我們要當(dāng)心不要被誤導(dǎo)。例如,如果初始的工資閾值是每年75,000美元,而后來(lái)更改為我們的68,330美元,那么下面這個(gè)過(guò)期的測(cè)驗(yàn)可能會(huì)使我們誤入歧途:
這個(gè)測(cè)驗(yàn)仍是會(huì)經(jīng)過(guò)的,但沒(méi)有了預(yù)期的效果。經(jīng)過(guò)的原因不是由于它正好是閾值,而是由于它超出了閾值。如果此測(cè)驗(yàn)組件包括這樣一個(gè)測(cè)驗(yàn)用例:當(dāng)薪水低于閾值1美元時(shí),過(guò)濾器就回來(lái)false,這樣第二個(gè)測(cè)驗(yàn)將會(huì)失利,標(biāo)明閾值是過(guò)錯(cuò)的。如果套件沒(méi)有這樣的測(cè)驗(yàn),那么陳腐的數(shù)據(jù)會(huì)很簡(jiǎn)略誤導(dǎo)我們弄錯(cuò)代碼的真實(shí)目的。當(dāng)有疑問(wèn)時(shí),請(qǐng)信任代碼:正如我們之前所表述的那樣,求解閾值標(biāo)明測(cè)驗(yàn)沒(méi)有對(duì)準(zhǔn)實(shí)踐閾值。
別的,要檢查代碼和測(cè)驗(yàn)用例的存儲(chǔ)庫(kù)日志(即Git日志):如果代碼的終究更新日期比測(cè)驗(yàn)的終究更新日期更近(對(duì)代碼進(jìn)行了嚴(yán)重更改,例如更改閾值),則測(cè)驗(yàn)可能現(xiàn)已過(guò)期,應(yīng)慎重檢查。留意,我們不應(yīng)該徹底忽視測(cè)驗(yàn),由于它們或許依然能為我們供給關(guān)于原作者(或最近編撰測(cè)驗(yàn)的開(kāi)發(fā)人員)目的的一些文檔,但它們可能包括過(guò)期或不正確的數(shù)據(jù)。
2.與編寫代碼的人溝通
在觸及多個(gè)人的任何作業(yè)中,溝通至關(guān)重要。不管是企業(yè),越野游覽仍是軟件項(xiàng)目,缺少溝通是危害使命最有用的手法之一。即便我們?cè)趧?chuàng)立新代碼時(shí)進(jìn)行溝通,可是當(dāng)我們觸摸現(xiàn)有的代碼時(shí),危險(xiǎn)會(huì)增加。由于此刻我們對(duì)現(xiàn)有的代碼并不太了解,因而我們所了解的內(nèi)容可能是被誤導(dǎo)的,或只代表了其間的一小部分。為了真實(shí)了解現(xiàn)有的代碼,我們需求和編寫它的人溝通。
當(dāng)開(kāi)端提出問(wèn)題時(shí),我們需求斷定問(wèn)題是詳細(xì)的,而且旨在完結(jié)我們了解代碼的方針。例如:
這個(gè)代碼片段最適合放到體系的哪里?
你有什么規(guī)劃或圖表嗎?
我應(yīng)該留意什么圈套?
這個(gè)組件或類是做什么的?
有沒(méi)有什么你想放到代碼里,但其時(shí)沒(méi)有做的?為什么?
一直要堅(jiān)持謙善的情緒,活躍尋求原作者真實(shí)的答案。簡(jiǎn)直每個(gè)開(kāi)發(fā)人員都碰到過(guò)這樣的場(chǎng)景,他或她看著他人的代碼,自問(wèn)自答:“為什么他/她要這樣做?為什么他們不這樣做?”然后花幾個(gè)小時(shí)來(lái)得出正本只需原作者答復(fù)就能得到的定論。大多數(shù)開(kāi)發(fā)人員都是有才調(diào)的程序員,所以即便如果我們遇到一個(gè)看似糟糕的決議,也有可能有一個(gè)很好的理由(可能沒(méi)有,但研討他人的代碼時(shí)最好假定他們這樣做是有原因的;如果真的沒(méi)有,我們能夠經(jīng)過(guò)重構(gòu)來(lái)改動(dòng))。
溝通在軟件開(kāi)發(fā)中起非有必要副效果。1967年開(kāi)端由Melvin Conway創(chuàng)立的康威規(guī)律規(guī)矩:
規(guī)劃體系的任何安排…都將不可防止地發(fā)生一種規(guī)劃,該規(guī)劃結(jié)構(gòu)反映了安排的通訊結(jié)構(gòu)。
這意味著,一個(gè)巨大、嚴(yán)密溝通的團(tuán)隊(duì)可能會(huì)生成一體化,嚴(yán)密耦合的代碼,但一些較小的團(tuán)隊(duì)可能會(huì)生成更獨(dú)立、松懈耦合的代碼(有關(guān)此相關(guān)性的更多信息,請(qǐng)參閱《Demystifying Conway’s Law》)。關(guān)于我們來(lái)說(shuō),這意味著我們的通訊結(jié)構(gòu)不只影響特定的代碼段,也影響整個(gè)代碼庫(kù)。因而,與原作者親近溝通肯定是一個(gè)好辦法,但我們應(yīng)該自檢不要太過(guò)于依賴于原作者。這不只可能會(huì)惹惱原作者,還可能在我們的代碼中發(fā)生無(wú)意識(shí)的耦合。
盡管這有助于我們深入研討代碼,但這是在假定能夠觸摸原作者的狀況下。在許多時(shí)分,原作者可能現(xiàn)已脫離了公司,或恰巧不在公司(例如正在度假)。在此種狀況下我們?cè)撟鍪裁矗繂?wèn)詢可能對(duì)代碼有所了解的人。這個(gè)人紛歧定要曾真實(shí)作業(yè)于代碼,他能夠是在原作者編寫代碼時(shí)就在周圍,也能夠是知道原作者。哪怕僅是從原開(kāi)發(fā)者周圍的人中得到只言片語(yǔ),也可能會(huì)啟迪其他不知道的代碼片段。
3.刪去一切正告
心思學(xué)中有一個(gè)眾所周知的概念,稱為“破窗理論”,Andrew Hunt和Dave Thomas在《 The Pragmatic Programmer 》(第4-6頁(yè))中詳細(xì)描繪了這個(gè)概念。這個(gè)理論開(kāi)端是由James Q.Wilson和George L. Kelling提出的,描繪如下:
假定有一個(gè)建筑物有幾扇破了的窗戶。如果窗戶沒(méi)有修好,那么損壞者會(huì)趨向于打破更多的窗戶。終究,他們乃至可能會(huì)破門而入,如果建筑物是沒(méi)人住的,那么他們可能會(huì)非法占有或許在里面焚燒。也能夠考慮人行道的狀況。如果道路上面有廢物堆積,那么不久之后,就會(huì)有更多的廢物累積。終究,人們乃至?xí)_(kāi)端往那里扔外賣廢物,乃至打破轎車。
這個(gè)理論指出,如果好像現(xiàn)已沒(méi)人關(guān)懷這個(gè)物品或事物,那么我們就會(huì)忽視對(duì)物品或事物的照料,這是人的天分。例如,如果一棟建筑物看上去現(xiàn)已凌亂不堪,那么它更有可能被任意損壞。在軟件方面,這個(gè)理論意味著如果開(kāi)發(fā)人員發(fā)現(xiàn)代碼現(xiàn)已是一團(tuán)糟,那么人的賦性會(huì)讓他弄壞代碼。從實(shí)質(zhì)上說(shuō),我們心里想的是(即便心思活動(dòng)沒(méi)有這么豐厚),“已然終究一個(gè)人不在乎這代碼,我為什么要在乎?”或“都是亂糟糟的代碼,誰(shuí)知道是誰(shuí)寫的。”
可是,這不應(yīng)該成為我們的托言。只需我們觸摸曾經(jīng)歸于其他人的代碼,那么我們就要對(duì)這些代碼擔(dān)任,而且如果它不能有用作業(yè)的話,我們得背負(fù)結(jié)果。為了打敗這種人的天分行為,我們需求采納一些小辦法以防止我們的代碼更少地被弄臟(及時(shí)替換破掉的窗戶)。
一個(gè)簡(jiǎn)略辦法是刪去來(lái)自我們正在運(yùn)用的整個(gè)包或模塊中的一切正告。至于未運(yùn)用或增加注釋的代碼,刪去它。如果我們稍后需求這部分代碼,那么在存儲(chǔ)庫(kù)中,我們總是能夠從從前的提交中檢索它。如果存在無(wú)法直接處理的正告(例如原始類型正告),那么運(yùn)用@SuppressWarnings注解注釋該調(diào)用或辦法。這樣能夠保證我們對(duì)代碼進(jìn)行過(guò)細(xì)心的考慮:它們不是由于疏忽而宣布的正告,而是我們明確地留意到了正告(如原始類型)。
一旦我們刪去或明確地制止一切正告,那么我們就有必要保證代碼堅(jiān)持革除正告。這有兩個(gè)首要效果:
迫使我們細(xì)心考慮我們創(chuàng)立的任何代碼。
削減代碼糜爛的改動(dòng),現(xiàn)在的正告會(huì)導(dǎo)致今后的過(guò)錯(cuò)。
這對(duì)其他人,以及我們自己都有心思暗示效果——我們其實(shí)關(guān)懷我們正在處理的代碼。它不再是條單行線——我們強(qiáng)逼著自己更改代碼,提交,然后永不回頭。相反,我們知道到我們需求對(duì)這代碼擔(dān)任。這對(duì)之后的軟件開(kāi)發(fā)也是有協(xié)助的——它向?qū)?lái)的開(kāi)發(fā)人員展現(xiàn),這不是一間窗戶都破了的庫(kù)房:而是一個(gè)保護(hù)杰出的代碼庫(kù)。
4.重構(gòu)
在曩昔幾十年中,重構(gòu)現(xiàn)已成為了一個(gè)十分重要的術(shù)語(yǔ),而且最近被當(dāng)作是對(duì)當(dāng)時(shí)作業(yè)代碼做任何改動(dòng)的代名詞。盡管重構(gòu)的確觸及對(duì)當(dāng)時(shí)正在作業(yè)的代碼的更改,但并非整個(gè)全局。Martin Fowler在他關(guān)于這個(gè)論題的重要著作——《Refactoring》一書中將重構(gòu)界說(shuō)為:
對(duì)軟件的內(nèi)部結(jié)構(gòu)進(jìn)行更改,使其更簡(jiǎn)略了解而且修正起來(lái)更廉價(jià),而不改動(dòng)其可調(diào)查的行為。
這個(gè)界說(shuō)的關(guān)鍵在于它觸及的更改不會(huì)改動(dòng)體系可調(diào)查的行為。這意味著當(dāng)我們重構(gòu)代碼時(shí),我們有必要要有辦法來(lái)保證代碼的外部可見(jiàn)行為不會(huì)改動(dòng)。在我們的比如中,這意味著是在我們承繼或自己開(kāi)發(fā)的測(cè)驗(yàn)套件中。為了保證我們沒(méi)有改動(dòng)體系的外部行為,每逢我們進(jìn)行改動(dòng)時(shí),都有必要從頭編譯和履行我們的悉數(shù)測(cè)驗(yàn)。
此外,并不是我們所做的每一個(gè)改動(dòng)都被認(rèn)為是重構(gòu)。例如,重命名辦法以更好地反映其預(yù)期用處是重構(gòu),但增加新功用不是。為了看到重構(gòu)的長(zhǎng)處,我們將重構(gòu)SuccessfulFilter。履行的第一個(gè)重構(gòu)是提取辦法,以更好地封裝個(gè)人凈工資的邏輯:
在我們進(jìn)行這種改動(dòng)之后,我們從頭編譯并運(yùn)轉(zhuǎn)我們的測(cè)驗(yàn)套件,測(cè)驗(yàn)套件將持續(xù)經(jīng)過(guò)。現(xiàn)在更簡(jiǎn)略看出,成功是經(jīng)過(guò)一個(gè)人的年紀(jì)和凈薪酬界說(shuō)的,可是getNetSalary辦法好像并不像Person類一樣歸于SuccessfulFilter(指示標(biāo)志就是該辦法的僅有參數(shù)是Person,該辦法的僅有調(diào)用是Person類的辦法,因而對(duì)Person類有很強(qiáng)的親和力)。 為了更好地定位這個(gè)辦法,我們履行一個(gè)Move辦法將其移動(dòng)到Person類:
為了進(jìn)一步整理此代碼,我們對(duì)每個(gè)magic number履行符號(hào)常量替換magic number行為。為了知道這些值的意義,我們可能得和原作者溝通,或許向具有滿足范疇常識(shí)的人討教,以引領(lǐng)正確的方向。我們還將履行更多的提取辦法重構(gòu),以保證現(xiàn)有的辦法盡可能簡(jiǎn)略。
從頭編譯和測(cè)驗(yàn),發(fā)現(xiàn)體系依然依照預(yù)期的辦法作業(yè):我們沒(méi)有改動(dòng)外部行為,可是我們改進(jìn)了代碼的可靠性和內(nèi)部結(jié)構(gòu)。有關(guān)更雜亂的重構(gòu)和重構(gòu)進(jìn)程,請(qǐng)參閱Martin Fowler的Refactoring Guru網(wǎng)站。
5.當(dāng)你脫離的時(shí)分,代碼比你發(fā)現(xiàn)它的時(shí)分更好
終究這個(gè)技能在概念上十分簡(jiǎn)略,但在實(shí)踐中很困難:讓代碼比你發(fā)現(xiàn)它的時(shí)分更好。當(dāng)我們整理代碼,特別是他人的代碼時(shí),我們大多會(huì)增加功用,測(cè)驗(yàn)它,然后前行,不關(guān)懷我們會(huì)不會(huì)奉獻(xiàn)軟件腐朽,也不在乎我們?cè)黾拥筋惖男罗k法會(huì)不會(huì)導(dǎo)致額定的紊亂。因而,本文的悉數(shù)內(nèi)容可總結(jié)為以下規(guī)矩:
每逢我們修正代碼時(shí),請(qǐng)保證當(dāng)你脫離的時(shí)分,代碼比你發(fā)現(xiàn)它的時(shí)分更好。
前面提到過(guò),我們需求對(duì)類形成的損壞和對(duì)改動(dòng)的代碼擔(dān)任,如果它不能作業(yè),那么修正是我們的責(zé)任。為了打敗隨同軟件出產(chǎn)而呈現(xiàn)的熵,我們有必要強(qiáng)制自己做到脫離時(shí)的代碼比我們發(fā)現(xiàn)它的時(shí)分更佳。為了不躲避這個(gè)問(wèn)題,我們有必要?dú)w還技能債款,保證下一個(gè)觸摸代碼的人不需求再付出代價(jià)。說(shuō)不定,將來(lái)可能是我們自己感謝自己這個(gè)時(shí)分的堅(jiān)持呢。作為軟件工程師不可防止會(huì)遇到的一個(gè)場(chǎng)景是:我們?cè)诟膭?dòng)或增加一個(gè)功用到不是我們創(chuàng)立的、我們不熟悉的、與我們擔(dān)任的體系部分無(wú)關(guān)的代碼中時(shí),會(huì)遇到費(fèi)事。盡管這可能會(huì)是一個(gè)繁瑣而艱巨的使命,可是由于運(yùn)用其他開(kāi)發(fā)人員編寫的代碼有很大的靈活性,所以我們能夠從中得到大大的長(zhǎng)處,包括增加我們的影響規(guī)模,修正軟件腐朽以及學(xué)習(xí)我們?cè)?jīng)不了解的體系部分(更何況,還能夠?qū)W習(xí)其他程序員的技能和技巧)。
考慮到運(yùn)用其他開(kāi)發(fā)人員編寫的代碼既有其厭煩之處,又有其優(yōu)勢(shì)地點(diǎn),所以我們有必要當(dāng)心不要犯一些嚴(yán)峻的過(guò)錯(cuò):
我們的自我意識(shí):我們可能會(huì)覺(jué)得自己知道得最多,但一般現(xiàn)實(shí)并非如此。我們要更改的是我們知之甚少的代碼——我們不知道原作者的目的、導(dǎo)致此代碼的決議計(jì)劃以及原作者在寫代碼時(shí)可用的東西和結(jié)構(gòu),等等。謙遜的質(zhì)量無(wú)價(jià)之寶,你值得具有。
原作者的自我意識(shí):我們行將觸摸的代碼是由另一個(gè)開(kāi)發(fā)人員所編寫的,另一種風(fēng)格、束縛、期限和個(gè)人日子(耗費(fèi)他或她作業(yè)之外的時(shí)刻)。只需當(dāng)我們開(kāi)端質(zhì)疑他或她做出的決議或質(zhì)疑代碼為什么這么不潔凈的時(shí)分,那人才會(huì)自我檢討,不至于自高自大。我們應(yīng)該盡悉數(shù)盡力讓原作者協(xié)助我們作業(yè),而不是阻礙我們。
對(duì)不知道的驚駭:許多時(shí)分,我們即將觸摸的代碼是我們知之甚少或徹底一竅不通的。令人懼怕的是:我們將對(duì)我們所做的任何改動(dòng)擔(dān)任,可是我們基本上就像是在沒(méi)有光線的漆黑屋子里走動(dòng)一樣。其實(shí)我們不需求憂慮,而是應(yīng)該構(gòu)建一種使我們能夠在大小紛歧的改動(dòng)中感到舒適的結(jié)構(gòu),并答應(yīng)我們保證沒(méi)有損壞現(xiàn)有的功用。
由于開(kāi)發(fā)人員,包括我們自己,是人,所以在處理其他開(kāi)發(fā)人員編寫的代碼時(shí),處理好許多人的天分問(wèn)題是很有用的。在這篇文章中,我們將經(jīng)過(guò)我們能夠運(yùn)用的五種技能來(lái)保證將對(duì)人道的了解成為我們的優(yōu)勢(shì),從現(xiàn)有代碼和原作者羅致盡可能多的協(xié)助,并使得其他開(kāi)發(fā)人員編寫的代碼終究變得比正本更優(yōu)異。盡管這兒列出的5個(gè)辦法并不全面,可是運(yùn)用下面的技能將保證在完畢改動(dòng)其他開(kāi)發(fā)人員編寫的代碼時(shí),我們有決心堅(jiān)持現(xiàn)有功用的作業(yè)狀況,一同保證我們的新功用與現(xiàn)有的代碼庫(kù)協(xié)調(diào)一致。
work-with-someone-else-code
1.保證測(cè)驗(yàn)的存在
要想保證在其他開(kāi)發(fā)人員編寫的代碼中所存在的現(xiàn)有功用實(shí)踐能夠依照預(yù)期的辦法作業(yè),而且我們對(duì)其進(jìn)行的任何更改都不會(huì)影響到功用的完結(jié),僅有真實(shí)令人決心十足的辦法是用測(cè)驗(yàn)來(lái)支撐代碼。當(dāng)我們遇到另一位開(kāi)發(fā)人員編寫的代碼時(shí),代碼有兩種所在的狀況:(1)沒(méi)有滿足的測(cè)驗(yàn)水平,或(2)有滿足的測(cè)驗(yàn)水平。遇到前一種狀況,我們得擔(dān)任創(chuàng)立測(cè)驗(yàn),而在后一種狀況下,我們能夠運(yùn)用現(xiàn)有的測(cè)驗(yàn)來(lái)保證我們做出的任何更改都不會(huì)損壞代碼,并盡可能多地從測(cè)驗(yàn)去了解代碼的目的。
創(chuàng)立新測(cè)驗(yàn)
這是一個(gè)哀痛的比如:我們?cè)诟膭?dòng)其他開(kāi)發(fā)人員的代碼時(shí),要對(duì)更改成果擔(dān)任,可是我們沒(méi)有辦法保證我們?cè)谶M(jìn)行更改時(shí)不損壞任何東西。訴苦是沒(méi)有用的。不管我們發(fā)現(xiàn)代碼處在什么樣的條件下,我們總之是要觸摸代碼,因而如果代碼壞掉了,就是我們的責(zé)任。所以我們?cè)诟膭?dòng)代碼時(shí),一定要掌控自己的行為。斷定不會(huì)損壞代碼的僅有辦法是自己寫測(cè)驗(yàn)。
盡管這是庸俗的,但它答應(yīng)我們經(jīng)過(guò)編寫測(cè)驗(yàn)來(lái)學(xué)習(xí),這是它的首要長(zhǎng)處。假定代碼現(xiàn)在能夠正常作業(yè),而我們需求編寫測(cè)驗(yàn),以便預(yù)期的輸入會(huì)導(dǎo)致預(yù)期的輸出。在我們完結(jié)這個(gè)測(cè)驗(yàn)的進(jìn)程中,我們逐步了解到代碼的目的和功用。例如,給出以下代碼
我們對(duì)代碼的目的以及為什么在代碼中運(yùn)用Magic number知道得并不多,可是我們能夠創(chuàng)立一組測(cè)驗(yàn),已知輸入發(fā)生已知輸出。例如,經(jīng)過(guò)做一些簡(jiǎn)略的數(shù)學(xué)和處理構(gòu)成成功的閾值薪水問(wèn)題,我們發(fā)現(xiàn)如果一個(gè)人的年紀(jì)在30歲以下,且每年大約賺68,330美元,那么他被認(rèn)為是成功的(依照本規(guī)范的規(guī)范)。盡管我們不知道那些magic number是什么,可是我們知道它們的確削減了初始的薪水值。因而,68,330美元的閾值是扣除前的基本工資。經(jīng)過(guò)運(yùn)用這些信息,我們能夠創(chuàng)立一些簡(jiǎn)略的測(cè)驗(yàn),例如:
經(jīng)過(guò)這三個(gè)測(cè)驗(yàn),我們現(xiàn)在對(duì)現(xiàn)有代碼的作業(yè)辦法有了大致的了解:如果一個(gè)人不到30歲,且每年賺$ 68,300,那么他被認(rèn)為是成功人士。盡管我們能夠創(chuàng)立更多的測(cè)驗(yàn)來(lái)保證臨界狀況(例如空白年紀(jì)或工資)功用正常,可是一些簡(jiǎn)略的測(cè)驗(yàn)不只使我們了解了原始功用,還給出了一套自動(dòng)化測(cè)驗(yàn),可用于保證在對(duì)現(xiàn)有代碼進(jìn)行更改時(shí),我們不會(huì)損壞現(xiàn)有功用。
運(yùn)用現(xiàn)有測(cè)驗(yàn)
如果有滿足的代碼測(cè)驗(yàn)組件,那么我們能夠從測(cè)驗(yàn)中學(xué)到許多東西。正如我們創(chuàng)立測(cè)驗(yàn)一樣,經(jīng)過(guò)閱覽測(cè)驗(yàn),我們能夠了解代碼如安在功用層面上作業(yè)。此外,我們還能夠知道原作者是怎么讓代碼運(yùn)轉(zhuǎn)的。即便測(cè)驗(yàn)是由原作者以外的人(在我們觸摸之前)編撰的,也依然能夠?yàn)槲覀児┙o關(guān)于其他人對(duì)代碼的觀點(diǎn)。
盡管現(xiàn)有的測(cè)驗(yàn)?zāi)軌蚬┙o協(xié)助,但我們依然需求對(duì)此持保存情緒。測(cè)驗(yàn)是否與代碼的開(kāi)發(fā)更改一同與時(shí)俱進(jìn)是很難說(shuō)的。如果是的話,那么這是一個(gè)很好的了解根底;如果不是,那么我們要當(dāng)心不要被誤導(dǎo)。例如,如果初始的工資閾值是每年75,000美元,而后來(lái)更改為我們的68,330美元,那么下面這個(gè)過(guò)期的測(cè)驗(yàn)可能會(huì)使我們誤入歧途:
這個(gè)測(cè)驗(yàn)仍是會(huì)經(jīng)過(guò)的,但沒(méi)有了預(yù)期的效果。經(jīng)過(guò)的原因不是由于它正好是閾值,而是由于它超出了閾值。如果此測(cè)驗(yàn)組件包括這樣一個(gè)測(cè)驗(yàn)用例:當(dāng)薪水低于閾值1美元時(shí),過(guò)濾器就回來(lái)false,這樣第二個(gè)測(cè)驗(yàn)將會(huì)失利,標(biāo)明閾值是過(guò)錯(cuò)的。如果套件沒(méi)有這樣的測(cè)驗(yàn),那么陳腐的數(shù)據(jù)會(huì)很簡(jiǎn)略誤導(dǎo)我們弄錯(cuò)代碼的真實(shí)目的。當(dāng)有疑問(wèn)時(shí),請(qǐng)信任代碼:正如我們之前所表述的那樣,求解閾值標(biāo)明測(cè)驗(yàn)沒(méi)有對(duì)準(zhǔn)實(shí)踐閾值。
別的,要檢查代碼和測(cè)驗(yàn)用例的存儲(chǔ)庫(kù)日志(即Git日志):如果代碼的終究更新日期比測(cè)驗(yàn)的終究更新日期更近(對(duì)代碼進(jìn)行了嚴(yán)重更改,例如更改閾值),則測(cè)驗(yàn)可能現(xiàn)已過(guò)期,應(yīng)慎重檢查。留意,我們不應(yīng)該徹底忽視測(cè)驗(yàn),由于它們或許依然能為我們供給關(guān)于原作者(或最近編撰測(cè)驗(yàn)的開(kāi)發(fā)人員)目的的一些文檔,但它們可能包括過(guò)期或不正確的數(shù)據(jù)。
2.與編寫代碼的人溝通
在觸及多個(gè)人的任何作業(yè)中,溝通至關(guān)重要。不管是企業(yè),越野游覽仍是軟件項(xiàng)目,缺少溝通是危害使命最有用的手法之一。即便我們?cè)趧?chuàng)立新代碼時(shí)進(jìn)行溝通,可是當(dāng)我們觸摸現(xiàn)有的代碼時(shí),危險(xiǎn)會(huì)增加。由于此刻我們對(duì)現(xiàn)有的代碼并不太了解,因而我們所了解的內(nèi)容可能是被誤導(dǎo)的,或只代表了其間的一小部分。為了真實(shí)了解現(xiàn)有的代碼,我們需求和編寫它的人溝通。
當(dāng)開(kāi)端提出問(wèn)題時(shí),我們需求斷定問(wèn)題是詳細(xì)的,而且旨在完結(jié)我們了解代碼的方針。例如:
這個(gè)代碼片段最適合放到體系的哪里?
你有什么規(guī)劃或圖表嗎?
我應(yīng)該留意什么圈套?
這個(gè)組件或類是做什么的?
有沒(méi)有什么你想放到代碼里,但其時(shí)沒(méi)有做的?為什么?
一直要堅(jiān)持謙善的情緒,活躍尋求原作者真實(shí)的答案。簡(jiǎn)直每個(gè)開(kāi)發(fā)人員都碰到過(guò)這樣的場(chǎng)景,他或她看著他人的代碼,自問(wèn)自答:“為什么他/她要這樣做?為什么他們不這樣做?”然后花幾個(gè)小時(shí)來(lái)得出正本只需原作者答復(fù)就能得到的定論。大多數(shù)開(kāi)發(fā)人員都是有才調(diào)的程序員,所以即便如果我們遇到一個(gè)看似糟糕的決議,也有可能有一個(gè)很好的理由(可能沒(méi)有,但研討他人的代碼時(shí)最好假定他們這樣做是有原因的;如果真的沒(méi)有,我們能夠經(jīng)過(guò)重構(gòu)來(lái)改動(dòng))。
溝通在軟件開(kāi)發(fā)中起非有必要副效果。1967年開(kāi)端由Melvin Conway創(chuàng)立的康威規(guī)律規(guī)矩:
規(guī)劃體系的任何安排…都將不可防止地發(fā)生一種規(guī)劃,該規(guī)劃結(jié)構(gòu)反映了安排的通訊結(jié)構(gòu)。
這意味著,一個(gè)巨大、嚴(yán)密溝通的團(tuán)隊(duì)可能會(huì)生成一體化,嚴(yán)密耦合的代碼,但一些較小的團(tuán)隊(duì)可能會(huì)生成更獨(dú)立、松懈耦合的代碼(有關(guān)此相關(guān)性的更多信息,請(qǐng)參閱《Demystifying Conway’s Law》)。關(guān)于我們來(lái)說(shuō),這意味著我們的通訊結(jié)構(gòu)不只影響特定的代碼段,也影響整個(gè)代碼庫(kù)。因而,與原作者親近溝通肯定是一個(gè)好辦法,但我們應(yīng)該自檢不要太過(guò)于依賴于原作者。這不只可能會(huì)惹惱原作者,還可能在我們的代碼中發(fā)生無(wú)意識(shí)的耦合。
盡管這有助于我們深入研討代碼,但這是在假定能夠觸摸原作者的狀況下。在許多時(shí)分,原作者可能現(xiàn)已脫離了公司,或恰巧不在公司(例如正在度假)。在此種狀況下我們?cè)撟鍪裁???wèn)詢可能對(duì)代碼有所了解的人。這個(gè)人紛歧定要曾真實(shí)作業(yè)于代碼,他能夠是在原作者編寫代碼時(shí)就在周圍,也能夠是知道原作者。哪怕僅是從原開(kāi)發(fā)者周圍的人中得到只言片語(yǔ),也可能會(huì)啟迪其他不知道的代碼片段。
3.刪去一切正告
心思學(xué)中有一個(gè)眾所周知的概念,稱為“破窗理論”,Andrew Hunt和Dave Thomas在《 The Pragmatic Programmer 》(第4-6頁(yè))中詳細(xì)描繪了這個(gè)概念。這個(gè)理論開(kāi)端是由James Q.Wilson和George L. Kelling提出的,描繪如下:
假定有一個(gè)建筑物有幾扇破了的窗戶。如果窗戶沒(méi)有修好,那么損壞者會(huì)趨向于打破更多的窗戶。終究,他們乃至可能會(huì)破門而入,如果建筑物是沒(méi)人住的,那么他們可能會(huì)非法占有或許在里面焚燒。也能夠考慮人行道的狀況。如果道路上面有廢物堆積,那么不久之后,就會(huì)有更多的廢物累積。終究,人們乃至?xí)_(kāi)端往那里扔外賣廢物,乃至打破轎車。
這個(gè)理論指出,如果好像現(xiàn)已沒(méi)人關(guān)懷這個(gè)物品或事物,那么我們就會(huì)忽視對(duì)物品或事物的照料,這是人的天分。例如,如果一棟建筑物看上去現(xiàn)已凌亂不堪,那么它更有可能被任意損壞。在軟件方面,這個(gè)理論意味著如果開(kāi)發(fā)人員發(fā)現(xiàn)代碼現(xiàn)已是一團(tuán)糟,那么人的賦性會(huì)讓他弄壞代碼。從實(shí)質(zhì)上說(shuō),我們心里想的是(即便心思活動(dòng)沒(méi)有這么豐厚),“已然終究一個(gè)人不在乎這代碼,我為什么要在乎?”或“都是亂糟糟的代碼,誰(shuí)知道是誰(shuí)寫的。”
可是,這不應(yīng)該成為我們的托言。只需我們觸摸曾經(jīng)歸于其他人的代碼,那么我們就要對(duì)這些代碼擔(dān)任,而且如果它不能有用作業(yè)的話,我們得背負(fù)結(jié)果。為了打敗這種人的天分行為,我們需求采納一些小辦法以防止我們的代碼更少地被弄臟(及時(shí)替換破掉的窗戶)。
一個(gè)簡(jiǎn)略辦法是刪去來(lái)自我們正在運(yùn)用的整個(gè)包或模塊中的一切正告。至于未運(yùn)用或增加注釋的代碼,刪去它。如果我們稍后需求這部分代碼,那么在存儲(chǔ)庫(kù)中,我們總是能夠從從前的提交中檢索它。如果存在無(wú)法直接處理的正告(例如原始類型正告),那么運(yùn)用@SuppressWarnings注解注釋該調(diào)用或辦法。這樣能夠保證我們對(duì)代碼進(jìn)行過(guò)細(xì)心的考慮:它們不是由于疏忽而宣布的正告,而是我們明確地留意到了正告(如原始類型)。
一旦我們刪去或明確地制止一切正告,那么我們就有必要保證代碼堅(jiān)持革除正告。這有兩個(gè)首要效果:
迫使我們細(xì)心考慮我們創(chuàng)立的任何代碼。
削減代碼糜爛的改動(dòng),現(xiàn)在的正告會(huì)導(dǎo)致今后的過(guò)錯(cuò)。
這對(duì)其他人,以及我們自己都有心思暗示效果——我們其實(shí)關(guān)懷我們正在處理的代碼。它不再是條單行線——我們強(qiáng)逼著自己更改代碼,提交,然后永不回頭。相反,我們知道到我們需求對(duì)這代碼擔(dān)任。這對(duì)之后的軟件開(kāi)發(fā)也是有協(xié)助的——它向?qū)?lái)的開(kāi)發(fā)人員展現(xiàn),這不是一間窗戶都破了的庫(kù)房:而是一個(gè)保護(hù)杰出的代碼庫(kù)。
4.重構(gòu)
在曩昔幾十年中,重構(gòu)現(xiàn)已成為了一個(gè)十分重要的術(shù)語(yǔ),而且最近被當(dāng)作是對(duì)當(dāng)時(shí)作業(yè)代碼做任何改動(dòng)的代名詞。盡管重構(gòu)的確觸及對(duì)當(dāng)時(shí)正在作業(yè)的代碼的更改,但并非整個(gè)全局。Martin Fowler在他關(guān)于這個(gè)論題的重要著作——《Refactoring》一書中將重構(gòu)界說(shuō)為:
對(duì)軟件的內(nèi)部結(jié)構(gòu)進(jìn)行更改,使其更簡(jiǎn)略了解而且修正起來(lái)更廉價(jià),而不改動(dòng)其可調(diào)查的行為。
這個(gè)界說(shuō)的關(guān)鍵在于它觸及的更改不會(huì)改動(dòng)體系可調(diào)查的行為。這意味著當(dāng)我們重構(gòu)代碼時(shí),我們有必要要有辦法來(lái)保證代碼的外部可見(jiàn)行為不會(huì)改動(dòng)。在我們的比如中,這意味著是在我們承繼或自己開(kāi)發(fā)的測(cè)驗(yàn)套件中。為了保證我們沒(méi)有改動(dòng)體系的外部行為,每逢我們進(jìn)行改動(dòng)時(shí),都有必要從頭編譯和履行我們的悉數(shù)測(cè)驗(yàn)。
此外,并不是我們所做的每一個(gè)改動(dòng)都被認(rèn)為是重構(gòu)。例如,重命名辦法以更好地反映其預(yù)期用處是重構(gòu),但增加新功用不是。為了看到重構(gòu)的長(zhǎng)處,我們將重構(gòu)SuccessfulFilter。履行的第一個(gè)重構(gòu)是提取辦法,以更好地封裝個(gè)人凈工資的邏輯:
在我們進(jìn)行這種改動(dòng)之后,我們從頭編譯并運(yùn)轉(zhuǎn)我們的測(cè)驗(yàn)套件,測(cè)驗(yàn)套件將持續(xù)經(jīng)過(guò)。現(xiàn)在更簡(jiǎn)略看出,成功是經(jīng)過(guò)一個(gè)人的年紀(jì)和凈薪酬界說(shuō)的,可是getNetSalary辦法好像并不像Person類一樣歸于SuccessfulFilter(指示標(biāo)志就是該辦法的僅有參數(shù)是Person,該辦法的僅有調(diào)用是Person類的辦法,因而對(duì)Person類有很強(qiáng)的親和力)。 為了更好地定位這個(gè)辦法,我們履行一個(gè)Move辦法將其移動(dòng)到Person類:
為了進(jìn)一步整理此代碼,我們對(duì)每個(gè)magic number履行符號(hào)常量替換magic number行為。為了知道這些值的意義,我們可能得和原作者溝通,或許向具有滿足范疇常識(shí)的人討教,以引領(lǐng)正確的方向。我們還將履行更多的提取辦法重構(gòu),以保證現(xiàn)有的辦法盡可能簡(jiǎn)略。
從頭編譯和測(cè)驗(yàn),發(fā)現(xiàn)體系依然依照預(yù)期的辦法作業(yè):我們沒(méi)有改動(dòng)外部行為,可是我們改進(jìn)了代碼的可靠性和內(nèi)部結(jié)構(gòu)。有關(guān)更雜亂的重構(gòu)和重構(gòu)進(jìn)程,請(qǐng)參閱Martin Fowler的Refactoring Guru網(wǎng)站。
5.當(dāng)你脫離的時(shí)分,代碼比你發(fā)現(xiàn)它的時(shí)分更好
終究這個(gè)技能在概念上十分簡(jiǎn)略,但在實(shí)踐中很困難:讓代碼比你發(fā)現(xiàn)它的時(shí)分更好。當(dāng)我們整理代碼,特別是他人的代碼時(shí),我們大多會(huì)增加功用,測(cè)驗(yàn)它,然后前行,不關(guān)懷我們會(huì)不會(huì)奉獻(xiàn)軟件腐朽,也不在乎我們?cè)黾拥筋惖男罗k法會(huì)不會(huì)導(dǎo)致額定的紊亂。因而,本文的悉數(shù)內(nèi)容可總結(jié)為以下規(guī)矩:
每逢我們修正代碼時(shí),請(qǐng)保證當(dāng)你脫離的時(shí)分,代碼比你發(fā)現(xiàn)它的時(shí)分更好。
前面提到過(guò),我們需求對(duì)類形成的損壞和對(duì)改動(dòng)的代碼擔(dān)任,如果它不能作業(yè),那么修正是我們的責(zé)任。為了打敗隨同軟件出產(chǎn)而呈現(xiàn)的熵,我們有必要強(qiáng)制自己做到脫離時(shí)的代碼比我們發(fā)現(xiàn)它的時(shí)分更佳。為了不躲避這個(gè)問(wèn)題,我們有必要?dú)w還技能債款,保證下一個(gè)觸摸代碼的人不需求再付出代價(jià)。說(shuō)不定,將來(lái)可能是我們自己感謝自己這個(gè)時(shí)分的堅(jiān)持呢。