代碼整潔的意義
最近讀了《代碼整潔之道》這本書绿店,結(jié)合自己工作之后的項目經(jīng)驗璃搜,對代碼整潔的重要性有了一些新的理解與感悟。首先我想先談?wù)勈裁词钦麧嵉拇a授滓,從字面意思上理解琳水,整潔的代碼,對于程序員來說非常的一目了然般堆,簡單在孝、整潔,結(jié)構(gòu)清晰淮摔,邏輯清楚私沮。那么整潔的代碼到底對一個項目的影響有多大?對于這個問題沒有明確的數(shù)據(jù)支撐我給出答案噩咪,我只知道糟糕的代碼對于一個項目的影響是與這個項目的規(guī)模呈正比的顾彰,我覺得大概可以算作是呈指數(shù)級的增長。
糟糕的代碼是如何影響一個項目的胃碾?想象一下一份只有10行的充斥了i涨享、j、k等變量的代碼仆百,讀完并不是一件難事厕隧,或許邏輯并不那么清晰,但是好歹還是能夠理解作者的意圖俄周,但是如果變成1000行呢吁讨?或許這個數(shù)量增長到100行的時候就已經(jīng)讓人想要放棄,隨意的命名讓人一頭霧水峦朗,錯綜復(fù)雜的邏輯混在一起建丧。如果還要在這樣的代碼上繼續(xù)疊加邏輯,這幾乎已經(jīng)是不可完成的任務(wù)了波势。
從我自己的經(jīng)驗來說翎朱,我?guī)缀跤洸蛔〈a的具體實(shí)現(xiàn)是怎樣的,盡管這是自己所寫出來的代碼尺铣,在每一次進(jìn)行一個新的功能的開發(fā)時拴曲,我都需要去熟悉一下舊代碼的實(shí)現(xiàn)邏輯,然后才能在此之上進(jìn)行新功能的疊加凛忿。一份整潔的代碼可以讓閱讀它的程序員快速的了解其實(shí)現(xiàn)邏輯澈灼,而不需要去了解具體的實(shí)現(xiàn)細(xì)節(jié)。如果一份代碼需要程序員了解了所有的實(shí)現(xiàn)細(xì)節(jié)才能知道這份代碼的作用,這勢必意味著程序員需要花費(fèi)大量的時間在閱讀一份與工作關(guān)系并不大的代碼叁熔。這樣的代碼越多委乌,程序員花費(fèi)的時間也就越多,這就是為什么我在文章開頭說糟糕的代碼對于一個項目的影響是與這個項目的規(guī)模呈指數(shù)級的增長者疤。
所以糟糕的代碼意味著難以維護(hù)福澡,也意味著代碼會慢慢的腐爛。所以在完成代碼后花一些時間去保持代碼的整潔反而是一種提升效率的手段驹马。
怎樣的代碼才叫整潔的代碼呢革砸?對于這個問題我的理解是這樣的,代碼其實(shí)是一種語言糯累,傳遞的是邏輯算利,如果這份代碼可以像我們說話一樣快速的將邏輯傳遞給讀者,那么這樣一份代碼就是一份整潔的代碼泳姐。
如何保持代碼整潔
在明白了代碼整潔的意義之后效拭,如何保持代碼整潔就是當(dāng)前最緊迫的問題。私以為可以從幾個點(diǎn)來進(jìn)行考慮:
意識
首先便是要有保持代碼整潔的意識胖秒,我很喜歡《代碼整潔之道》中反復(fù)提到的一條童子軍軍規(guī):讓營地比你來時更干凈缎患。我認(rèn)為有保持代碼整潔的意識并不是說從寫代碼的時候就一直是整潔的,如果能夠這樣當(dāng)然很好阎肝,但是這很難做到挤渔。在一開始編寫代碼的時候我們可以按照自己的思維順序,個人習(xí)慣风题,甚至是只是為了追求想要可以工作的代碼來寫出一些較為混亂的代碼判导,但是在結(jié)束當(dāng)前的工作之前,在讓自己的大腦脫離開之前沛硅,一定要整理代碼眼刃,一定!
明天的你與今天的你總會有所不同摇肌,在再次進(jìn)入工作之后擂红,你或許會忘記很多的細(xì)節(jié),而混亂的代碼只會讓思維更加的混亂围小。所以趁著你的思維還沒有與你代碼中巧妙的實(shí)現(xiàn)斷線之前昵骤,整理你的代碼,使代碼盡可能的保持整潔吩抓。這便是我理解的童子軍軍規(guī)涉茧,你可以把營地搞得一團(tuán)糟赴恨,但在你離開之前疹娶,一定要整理的更加干凈。
代碼規(guī)范
從代碼規(guī)范入手是最基礎(chǔ)也是最容易實(shí)現(xiàn)的保持代碼整潔的方式伦连。從幾個方面來體現(xiàn)代碼形式的整潔:足夠好的命名雨饺,簡單專注的函數(shù)钳垮,有意義的注釋以及規(guī)范的代碼格式。
一個好的命名可以幫助讀者快速的理解變量以及函數(shù)的意義额港,所要實(shí)現(xiàn)的事情是什么饺窿。很多時候程序員寧愿花費(fèi)更多的時間在變量名后加一些注釋,也不愿意取一個簡單易懂的名字移斩,這實(shí)際是一件本末倒置的做法肚医。一個函數(shù)、變量向瓷、類或者接口應(yīng)該只通過命名就可以把它所做的事情傳達(dá)給讀者肠套。所以不要害怕花費(fèi)時間在思考命名上。
函數(shù)應(yīng)該做一件事猖任。做好這件事你稚。只做這一件事。這句話摘選自函數(shù)這一章節(jié)朱躺。這句話很重要刁赖,我總會在函數(shù)中看到比函數(shù)名描述的更多的事情,有的時候我不得不花時間去閱讀一些我不想了解的實(shí)現(xiàn)細(xì)節(jié)才能明白這個函數(shù)到底做了一件什么事长搀。所以一個函數(shù)只做一件事宇弛,這是我認(rèn)為很容易達(dá)到卻又很容易被忽略的非常重要的事情。同時盈滴,函數(shù)還應(yīng)該盡可能的短小涯肩,一個函數(shù)就算寫的再清晰,如果一下子展示出100多行巢钓,那種龐大的行數(shù)也會讓讀者瞬間放棄病苗。當(dāng)然我相信,如果一個函數(shù)只專注于一件事症汹,是不會產(chǎn)生過于龐大的代碼量的硫朦。所以我認(rèn)為,一個好的代碼背镇,應(yīng)該像洋蔥一樣咬展,可以一層一層的剝開,由粗略到細(xì)致瞒斩。而不是像一個煮雞蛋破婆,完全一整個,讓人無法一點(diǎn)一點(diǎn)的理解胸囱。
關(guān)于有意義的注釋祷舀,我想我在前邊兩段的描述已經(jīng)傳達(dá)了一個信息,注釋或許并不那么必要。如果編程語言足夠有表現(xiàn)力裳扯,能夠傳遞給讀者所要表達(dá)的信息抛丽,注釋其實(shí)就失去了意義。只在真正需要的地方寫代碼才是注釋應(yīng)該存在的意義饰豺。
好的代碼格式亿鲜,例如縮進(jìn)的形式,可以有力的將層級結(jié)構(gòu)傳遞給讀者冤吨。我很討厭沒有縮進(jìn)的代碼蒿柳,因為我根本記不住哪個}是哪個{的結(jié)束。有的時候漩蟆,代碼格式也是一種有力的信息其馏。
質(zhì)量保證
所謂質(zhì)量保證,便是指可運(yùn)行的自動化測試以及代碼中的錯誤處理爆安。測試與錯誤處理代碼的整潔常常被人們所忽略叛复,或者不止是整潔,連測試和錯誤處理本身都常常是會被忽略的事情扔仓。事實(shí)是褐奥,測試很好的保證了我們的代碼質(zhì)量,給了我們對代碼修改的信心翘簇,這是另一個話題了撬码,這里不做贅述。
錯誤處理是指在代碼中程序員常常為了覆蓋更多的情況版保、給出更多的錯誤信息而在代碼的前后加try catch呜笑。設(shè)想一個極端的情況,每一行代碼都被一個try catch包圍彻犁,整個結(jié)構(gòu)就已經(jīng)一團(tuán)糟了叫胁,再清晰的結(jié)構(gòu)這個時候也已經(jīng)被拆解的支離破碎。錯誤處理可以匯總到某一處集中處理汞幢,不要讓隨處添加異常處理破壞代碼的邏輯驼鹅。
除了異常處理,測試的整潔同樣重要森篷。測試與編程語言一樣输钩,也是一種向讀者傳遞實(shí)現(xiàn)內(nèi)容的一種方式,隨著代碼的衍進(jìn)仲智,測試也同樣在進(jìn)行著改變买乃。所以測試代碼的整潔和生產(chǎn)代碼的整潔同樣重要。一團(tuán)糟糕的測試代碼或許可以保證代碼的質(zhì)量钓辆,但當(dāng)代碼產(chǎn)生變動時剪验,對于測試代碼的改動或許比對生產(chǎn)代碼的改動所花時間還要長哼绑,我們需要花費(fèi)更大的代價去維護(hù)測試代碼,這是一件得不償失的事情碉咆。為了不讓這類事情發(fā)生,需要對測試代碼的整潔與生產(chǎn)代碼的整潔給予同樣的重視蛀恩。同方法的職責(zé)單一原則一致疫铜,斷言的內(nèi)容也需要職責(zé)單一。每個斷言應(yīng)該只判斷一件事双谆。如此便可以更好的幫助我們快速精準(zhǔn)的定位問題壳咕。
分層與結(jié)構(gòu)
分層是指代碼從整體上,由上至下的一種層級結(jié)構(gòu)應(yīng)該是清晰的顽馋,并且一層一層應(yīng)該很好的區(qū)分開谓厘。與分層平級的便是結(jié)構(gòu),結(jié)構(gòu)是指從業(yè)務(wù)邏輯上寸谜,各個模塊應(yīng)該很好的區(qū)別開竟稳。分層與結(jié)構(gòu)的構(gòu)建清晰與否極大的影響了整個項目的整潔程度。
從大的方面來說熊痴,系統(tǒng)的使用與構(gòu)造需要明確的區(qū)分開他爸,才不會將整個結(jié)構(gòu)混雜在一起。與此同時果善,決定了系統(tǒng)的數(shù)據(jù)流走向便是決定了整個系統(tǒng)的層級劃分诊笤,不同的層級也需要明確的區(qū)分開來。從小一些的方面來看巾陕,當(dāng)創(chuàng)建一個類時讨跟,類的職責(zé)也需要明確,一個類應(yīng)該只有一個職責(zé)鄙煤。以上這些無論大的或是小的方面晾匠,之所以都需要明確劃分職責(zé),都是為了更好的實(shí)現(xiàn)內(nèi)聚梯刚。
內(nèi)聚代表著職責(zé)的專一混聊,這是整潔的一個很重要準(zhǔn)則。當(dāng)我們實(shí)現(xiàn)內(nèi)聚的時候乾巧,便會很自然的存在一個分類的界限句喜。舉個可能并不是很恰當(dāng)?shù)睦樱瑢W(xué)校里有很多學(xué)院沟于,每個學(xué)院有很多專業(yè)咳胃,每個專業(yè)有很多班,每個班里有很多學(xué)生旷太,這樣層層遞進(jìn)展懈,每一層也分的很清楚销睁,每一層的結(jié)構(gòu)也很清晰。如果換一種說法呢存崖,還是學(xué)校冻记,學(xué)校里有很多學(xué)生1、2来惧、3冗栗,有專業(yè)1、2供搀、3隅居, 有學(xué)院1、2葛虐、3胎源。這樣的話,學(xué)校還是那個學(xué)校屿脐,分層完全沒有體現(xiàn)涕蚤,有的更糟糕的,還會把不同層級的诵、不同結(jié)構(gòu)混合在一起赞季。
所以好的結(jié)構(gòu)和層級的劃分可以認(rèn)為是一種邏輯上的整潔,是相對更加抽象的代碼整潔奢驯,要求程序員自上而下地來進(jìn)行代碼的整潔申钩。
如何整理代碼
說完如何保持整潔的代碼,如果遇到了一團(tuán)混亂的代碼瘪阁,我們要如何將它整理的井井有條呢撒遣?首先我們要能夠明確的找到混亂地方,當(dāng)然我們不太可能一下子就找到所有管跺,不用太著急义黎,我們就要像剝洋蔥一樣一點(diǎn)一點(diǎn)的拆解代碼,小幅的進(jìn)行改動豁跑。每次改動廉涕,都有前邊提到的測試來保證我們并沒有破壞現(xiàn)有的功能。
當(dāng)我們要整理一大坨代碼的時候艇拍,我自己的經(jīng)驗是狐蜕,如果不知道如何改動的時候,可以先從最基本的入手卸夕,看懂一段代碼并且明確這是做了一件事之后层释,提取出來,取一個具有描述意義的名字快集。當(dāng)將代碼這樣拆解成一個一個的方法之后贡羔,結(jié)構(gòu)就清晰了很多廉白。之后我們就會聞到很多的code smell,發(fā)現(xiàn)很多的重復(fù)乖寒。關(guān)于如何發(fā)現(xiàn)和解決code smell猴蹂,可以參考《重構(gòu)》這本書,這本書列舉了很多的code smell楣嘁,并且給出了很好的解決方案磅轻。
小幅的、迭代式的進(jìn)行代碼的改動可以幫助我們一點(diǎn)一點(diǎn)的梳理結(jié)構(gòu)马澈,朝著更清晰的方向行走。同時千萬不要忘記每一次的改動都需要運(yùn)行測試來保證我們做的是對的事情弄息。