經(jīng)常有人微信問我,什么樣的代碼才算是好代碼。這個問題其實見仁見智,業(yè)內(nèi)也沒有統(tǒng)一的標(biāo)準(zhǔn)可以使用。我仔細(xì)梳理了一下自己評價代碼的方法,總結(jié)了五個評價指標(biāo)。
規(guī)模
執(zhí)行效率
占用空間
可讀性
擴展性
Java學(xué)習(xí)交流群:495273252
這五個維度相互之間有著或強或弱的關(guān)聯(lián),任意兩份代碼之間可以參考這個體系進(jìn)行大概的比較,但沒有絕對的高下之分。
Java學(xué)習(xí)交流群:495273252
這里的規(guī)模說的是代碼的規(guī)模,也就是解決同樣問題的程序包含的代碼行數(shù)。如果單從這個因素講,那一定是代碼規(guī)模越小越好。但規(guī)模越小往往就會讓代碼本身的復(fù)雜程度變高,影響可讀性。
有個很有趣的情況,初學(xué)者和技術(shù)大牛兩種水平相差巨大的人都有對代碼規(guī)模的執(zhí)念。不過他們的訴求卻是完全不同的。
1.1 初學(xué)者追求簡單
初學(xué)者評價代碼是不是簡單的最樸素的方法就是看代碼規(guī)模,他們總是覺得代碼行數(shù)越少的程序就越簡單。經(jīng)常有人在微信中問為什么我給出的解法要寫二十幾行代碼,而網(wǎng)上的解法卻只有十幾行。于是就讓我講一下那個十幾行的代碼。我只能說,那個十幾行的代碼來自《算法導(dǎo)論》,我需要用4~5個篇幅來講,還不保證能講透徹。
在編程領(lǐng)域,往往簡單并不表示易懂,它可能蘊含著更高級更復(fù)雜的思想。這些對于初學(xué)者是有難度的。
Java學(xué)習(xí)交流群:495273252
這是一個計算臨接矩陣中任意兩點之間距離的一個經(jīng)典算法,叫Floyd,只有六行代碼。當(dāng)年參加ACM比賽的時候就死記硬背下了這段代碼,后來一直沒有仔細(xì)研究過這個算法的原理,目前也只是會用而已。在大部分情況下,它也不是最優(yōu)的算法。
1.2 大牛們追求省事
真正的大牛追求代碼行數(shù)少的原因一定是為了提高執(zhí)行效率,但也不乏一些從業(yè)多年沒養(yǎng)成好習(xí)慣也被人稱為“大?!钡娜苏讨约航?jīng)驗豐富圖省事的一些寫法。我就見過這樣的代碼:
Java學(xué)習(xí)交流群:495273252
本來應(yīng)該寫這段代碼定義一個數(shù)據(jù)結(jié)構(gòu),結(jié)果被某位“大?!睂懗蛇@樣:
Java學(xué)習(xí)交流群:495273252
九行代碼一下變成了一行,就為了少敲一些。當(dāng)然,換做初學(xué)者,這樣的二維數(shù)組可能已經(jīng)駕馭不了。我還見過更夸張的代碼:
Java學(xué)習(xí)交流群:495273252
寫這行代碼的人依然是個有多年工作經(jīng)驗的“大?!?,這個四維數(shù)組用的風(fēng)生水起。只是坑苦了后來接手他工作的同事。
這樣追求代碼規(guī)模的行為都是不可取的。
Java學(xué)習(xí)交流群:495273252
從某種意義上講,如今對程序的第一要求應(yīng)該就是執(zhí)行效率。人們說的最多的就是執(zhí)行效率和運行空間的關(guān)系,還有執(zhí)行效率和可讀性的關(guān)系。
2.1 以空間換時間
隨著硬件設(shè)備的成本越來越低,越來越多的行業(yè)都提倡以空間換時間的設(shè)計思想。一些能夠通過記錄中間數(shù)據(jù)減少計算量的地方就成了首選的優(yōu)化點。
最經(jīng)典的利用這個思想的算法就是桶排序:
Java學(xué)習(xí)交流群:495273252
這段代碼通過一個空間為20的一維數(shù)組下標(biāo)進(jìn)行排序,空間利用是土豪級的。它的特點是排序范圍有多大,就需要一個多大的數(shù)組。
2.2 不能犧牲可讀性
底層程序員喜歡用位運算,于是常有人把簡單的計算用位運算進(jìn)行優(yōu)化,比如把
Java學(xué)習(xí)交流群:495273252
改成
Java學(xué)習(xí)交流群:495273252
由于位運算的物理特性,下面這段代碼的確效率會更高一些。不過,很多人看到這種寫法都不一定能反應(yīng)上來。
對于一些特殊的行業(yè),比如嵌入式開發(fā),編程過程中一定要注意的就是節(jié)省空間。因為嵌入式設(shè)備的RAM普遍比較小。這時候,桶排序的方法一定是不允許的。另外,在申請堆空間時都有嚴(yán)格的限制。
嵌入式開發(fā)中常有類似這樣的代碼:
Java學(xué)習(xí)交流群:495273252
沒有嵌入式經(jīng)驗的人一定會問,這段代碼申請了一段空間后什么也沒做就釋放掉了,這不是畫蛇添足嗎。其實,這是一段容錯代碼,就是為了保證系統(tǒng)中有足夠的空間供后面的代碼執(zhí)行。
是不是想想就很可憐,程序運行中突然發(fā)現(xiàn)內(nèi)存不夠了,不得不停掉。
Java學(xué)習(xí)交流群:495273252
對于越來越提倡代碼規(guī)范的中國軟件行業(yè)來說,可讀性開始成為不可忽視的重要因素。無論是統(tǒng)一的代碼風(fēng)格,還是規(guī)范的命名、函數(shù)設(shè)計和注釋,這些都必須注意。
在某些公司,代碼規(guī)范被認(rèn)為是評價代碼的第一要素。鐵打的項目流水的程序員,一段可讀性差的代碼對項目而言很可能意味著滅頂之災(zāi)。
對于初學(xué)者,代碼規(guī)范這個要素必須非常重視,如果錯過了這個培養(yǎng)良好習(xí)慣的黃金時期,后面再改就很難了。
行業(yè)內(nèi)有一些沿襲了很久的陋習(xí),因為追求程序執(zhí)行效率損失可讀性、為了減少代碼行數(shù)損失可讀性、為了趕工期損失可讀性甚至還有為了省事兒損失可讀性。在這些思想的驅(qū)使下,產(chǎn)生了很多不好的代碼習(xí)慣。
Java學(xué)習(xí)交流群:495273252
這是一個實現(xiàn)變量交換功能的函數(shù),它利用了^運算的特性,完成了不借助第三個變量進(jìn)行交換的動作。有些公司的面試題甚至還會考這個。但無論從執(zhí)行效率還是從輸入效率來講,它都沒有什么優(yōu)勢。也許唯一的作用就是炫技。我建議還是老老實實地這么寫:
Java學(xué)習(xí)交流群:495273252
在如今的編譯技術(shù)中,這段代碼已經(jīng)能夠被優(yōu)化到一個相當(dāng)高的性能了。
再舉個例子:
Java學(xué)習(xí)交流群:495273252
這句話還是盡量寫成下面這種形式:
Java學(xué)習(xí)交流群:495273252
雖然功能上沒有問題,但下面這種寫法更有助于開發(fā)者理清自己的邏輯。
如果你仔細(xì)閱讀任意一個公司的代碼規(guī)范文檔,你都會發(fā)現(xiàn)它有一條最重要的指導(dǎo)思想,那就是為了提高代碼可讀性,允許犧牲一些其他方面的利益。
對于一些大型的、生命周期久的項目而言,擴展性相當(dāng)重要。但擴展性有一個死敵就是代碼量。仔細(xì)研究一下經(jīng)典的23種設(shè)計模式,沒有哪一個不是成倍地提高了代碼量。
在很多資深程序員中,還常常因為是否使用設(shè)計模式引發(fā)爭論。而這些爭論的焦點就是代碼量和擴展性這對矛盾。究竟這二者孰輕孰重呢,其實也沒有一定之規(guī),完全取決于具體的項目情況。具體問題具體分析才是王道。
對于初學(xué)者而言,究竟哪些指標(biāo)應(yīng)該最關(guān)注呢?我認(rèn)為,當(dāng)然是可讀性。
初學(xué)者學(xué)習(xí)編程時,最重要的一點就是能夠把樸素的算法用編程語言來實現(xiàn)。其他的都不重要。有時,過早地追求其他四種指標(biāo)會讓你誤入歧途。
面對一道題目的多種解法,你要去做選擇首先該去鉆研哪一個。是那個代碼函數(shù)最少的嗎?是那個運行時間最短的嗎?是那個開辟空間最少的嗎?還是那個擴展性最強的。這些都不是,應(yīng)該是那個可讀性最好的。
可讀性好的代碼一般都不是最短的那一個,但一定是你最容易學(xué)會的。當(dāng)你掌握了一個正確的解法之后,你的心里就有了底,之后再了解其他解法時就更加自信,學(xué)習(xí)的動力就這樣悄悄地到來了。
很多新同學(xué)害怕代碼量大的程序,所謂的代碼量大也不過三四十行代碼,一看到就先緊張。其實,當(dāng)你靜下心來以子功能為單位一點點地讀下去,你會發(fā)現(xiàn)它不過是幾道課后作業(yè)解法的簡單堆疊,并不難理解。相反,很多看似簡單只有十幾行代碼的程序往往是一個大坑,一旦你扎進(jìn)去,憑自己的本事根本爬不出來。
可能我說的這些很多初學(xué)者還無法明白,沒關(guān)系先記住,相信在不久的將來你完成了一定數(shù)量的練習(xí)之后,你就會明白我今天在講些什么。
學(xué)習(xí)Java的同學(xué)注意了!??!
學(xué)習(xí)過程中遇到什么問題或者想獲取學(xué)習(xí)資源的話,歡迎加入Java學(xué)習(xí)交流群495273252,我們一起學(xué)Java!
聯(lián)系客服