《代碼整潔之道》總結(jié)
我們需要寫出整潔的代碼嗎
我是個6年開發(fā)經(jīng)驗的java程序員,在我的職業(yè)生涯中陕贮,看到過不少讓產(chǎn)生罵人沖動的代碼偶妖,當(dāng)然也寫過讓別人讓別人想罵人的代碼??。我曾很多次想改進(jìn)的我的代碼風(fēng)格找默,想讓它們更易懂,更嚴(yán)謹(jǐn)吼驶,更整潔惩激,更高效。但是終究還是寫了很多爛代碼旨剥。我總結(jié)了寫爛代碼的原因:
1咧欣、活多、時間緊轨帜。這可能是我們多數(shù)程序員寫爛代碼的直接原因魄咕,我們總抱怨需求緊時間少,功能實現(xiàn)就不錯了蚌父,哪管代碼的好賴哮兰,或許這只是一個接口毛萌,真正的原因是我們懶于思考。如何去改進(jìn)代碼風(fēng)格喝滞。一個需求我們寫代碼的時間往往只占一小部分阁将,就我個人而言,如果一個一天工作量的需求我寫代碼的時間往往不到2個小時右遭。更多的時間一部分是搞清楚需求做盅,另外一部分時間是和各種聯(lián)調(diào)測試,當(dāng)然還有同事隨時來找我打斷我的工作窘哈,重新開始寫時就需要重新 理下寫代碼思路吹榴。如果是修改之前的功能那耗費(fèi)最多時間的那就是閱讀這個功能之前的代碼。不管是調(diào)試代碼還是閱讀代碼滚婉,代碼的可讀性至關(guān)重要,易讀才是寫代碼高效的關(guān)鍵图筹。多抽象出一個公用方法,變量名起的更貼切易懂寫真的占用很多時間嗎?好吧這些確實要占用你幾分鐘但當(dāng)你調(diào)試或者修改時或許可以幫你省下幾個小時.
2让腹、老代碼多人經(jīng)手無力回天远剩。這種情況我也遇到過很多,但是當(dāng)我們放任這種情況不管骇窍,那這些代碼只能越來越糟瓜晤、越來越難以維護(hù),最終變得不可維護(hù)像鸡。這種情況如果我們沒有足夠的信心去重構(gòu)一些方法活鹰,那我們至少需要讓 "讓營地比你來時更干凈"哈恰, 讓代碼簽入時比簽出時更干凈只估。
3、我也想寫出漂亮干凈的代碼着绷,但是缺乏整體風(fēng)格蛔钙,想一出是一出,難以為繼荠医。這種情況也較為多見吁脱,什么叫整潔的代碼,每個人理解不一樣彬向,一千個程序員就有一千種對好代碼的理解兼贡。我的理解是寫出最多人更易讀懂的代碼就是好代碼。因為代碼更多是被讀的娃胆。不管是代碼的作者自己還是別的程序員遍希。
基于以上我認(rèn)為整潔的代碼應(yīng)該是一個好程序員的基本素質(zhì)。那么如何寫出整潔的代碼呢里烦?以下是我在讀完《代碼整潔之道》然后基于我7年寫代碼的經(jīng)驗所做總結(jié)凿蒜,以期能成為一個真正的好程序員禁谦。
java是有個@Auther注解~是的,作者废封,我們是代碼的作者州泊。我們要以作者心態(tài)自居,精心雕琢我們的代碼漂洋,以期讓我們的讀者在讀代碼時能賞心悅目遥皂。
如何能寫出好的代碼
好的代碼自己會說話-讓命名更有意義
程序中通常需要命名的有三種:方法、變量刽漂、類渴肉。其中變量又分為局部變量和成員變量。首先我們看下下面這個變量
int d //過去的天數(shù);
是不是很懵逼爽冕,要知道這個d表示的什么意思仇祭,你要通讀這個變量的上下文才能知道。颈畸,即使你寫了注釋乌奇,當(dāng)你寫代碼時或讀代碼時是不是經(jīng)常要往上翻尋找這個d的注釋。如果你起一個有含義的變量名眯娱,那讀起來就大不一樣了礁苗,在代碼中直接就知道什么意思了。
int elapsedTimeInDays;
int daysSinceCreation;
int daysSinceModification;
int fileAgeInDays;
起上面這樣的變量名是不是好多了徙缴,在代碼中遇到直接就知道這個變量是什么意思试伙,甚至不用寫注釋也知道這個變量的意思,不用去翻看程序的上下文或者找這個變量的注釋于样。
再看下面的方法
public List<int[]> getThem() {
List<int[]> list1 = new ArrayList<int[]>();
for (int[] x : theList)
if (x[0] == 4)
list1.add(x);
return list1;
}
看這樣的方法疏叨,你的頭頂是不是有很很多問號。倘若我們把方法名和變量名起的有意義一些呢如下:
public List<int[]> getFlaggedCells() {
List<int[]> flaggedCells = new ArrayList<int[]>();
for (int[] cell : gameBoard)
if (cell[STATUS_VALUE] == FLAGGED)
flaggedCells.add(cell);
return flaggedCells;
}
這樣是不是好多了穿剖,僅僅把變量名改成的有意義寫蚤蔓,代碼就變得已讀了很多,此時還未改變代碼的結(jié)構(gòu)和嵌套糊余。如果更進(jìn)一步我們不用 int 數(shù)組表示單元格秀又,而是另寫一個類,這個類有個方法是否是Flagged的贬芥,遮掩住那個魔法變量則方法就能變成下面這樣吐辙。是不是更易讀了。
public List<Cell> getFlaggedCells() {
List<Cell> flaggedCells = new ArrayList<Cell>();
for (Cell cell : gameBoard)
if (cell.isFlagged())
flaggedCells.add(cell);
return flaggedCells;
}
以上蘸劈,我們只是簡單了改變了代碼的名稱昏苏,代碼的易讀性大大提高。,代碼本身就是最好的注釋說明捷雕。
好的代碼自己會說話-準(zhǔn)確的命名椒丧、避免誤導(dǎo)
如果我們命名一個數(shù)組的話,那便不要使用accountList的命名救巷,這會給讀者誤導(dǎo)壶熏,誤以為這個變量是個List類型,所以用accountGroup或者arrayOfAccount甚至直接用accounts都會比accountList更好浦译。不準(zhǔn)確命名的另外一個經(jīng)常發(fā)生的例子是含有數(shù)字的變量名棒假,這種經(jīng)常發(fā)生我們要起一個變量名的時候發(fā)現(xiàn)這個變量重名了,我們經(jīng)常會再新變量后面加個數(shù)字來區(qū)分和原來的變量精盅。
public static void copyChars(char a1[], char a2[]) {
for (int i = 0; i < a1.length; i++) {
a2[i] = a1[i];
}
}
上面的代碼如果改成下面的會不會好點
public static void copyChars(source a1[], destination a2[]) {
for (int i = 0; i < a1.length; i++) {
destination[i] = source[i];
}
}
命名還有一個經(jīng)常發(fā)生不準(zhǔn)確的命名的例子如下,這三個方法有什么區(qū)別呢帽哑,我們在使用時應(yīng)該用哪個呢?這種命名區(qū)分毫無意義叹俏,調(diào)用者照樣需要去看方法的實現(xiàn)或者注釋來決定使用哪個方法∑拚恚現(xiàn)代聰明的ide會把所有的方法列出來,然而你卻不知道該使用那個方法粘驰。
getActiveAccount();
getActiveAccounts();
getActiveAccountInfo();
消除魔法數(shù)字如下一段代碼屡谐,在代碼中直接使用數(shù)字,通常讀者不知道這個數(shù)字的含義蝌数,那當(dāng)別人來讀這段代碼的時候就要去找這個數(shù)字的含義
Order order = new Order();
order.setStatus(0);
這段代碼明顯是給訂單設(shè)置狀態(tài)愕掏。但是0是什么狀態(tài),如果沒有注釋或文檔的情況顶伞,需要找別的同事問呢饵撑,即使有注釋和文檔是不是也需要通過這段代碼的上下文去找0的含義呢。如果我們把訂單狀態(tài)定義成一個enum或者常量:
Orderd order= new Order();
order.setStatus(ORDER_STATUS_PAY);
改進(jìn)后的代碼是不是很明顯就知道這個地方把訂單的狀態(tài)設(shè)置為支付狀態(tài)了唆貌。
好的代碼自己會說話-類名和方法命名的更好實踐
如何才能讓我們的代碼命名更清晰簡短有效呢滑潘。下面是《代碼代碼簡潔之道》一書中做的總結(jié):
- 類名應(yīng)該是名詞或名詞短語。如 Customer挠锥、WikiPage众羡、Account 和 AddressParser侨赡。避免使用 Manager蓖租、Processor、Data 或 Info 這樣的類名羊壹。類名不應(yīng)當(dāng)是動詞蓖宦。
- 方法名應(yīng)當(dāng)是動詞或動詞短語,如 postPayment油猫、deletePage 或 save稠茂。屬性訪問器、修改器和斷言應(yīng)該根據(jù)其值命名,并依 Javabean 標(biāo)準(zhǔn)加上 get睬关、set 和 is 前綴诱担。
String name = employee.getName();
customer.setName("mike");
if (paycheck.isPosted())
重載構(gòu)造器時,使用描述了參數(shù)的靜態(tài)工廠方法名电爹。例如蔫仙,
Complex fulcrumPoint = Complex.FromRealNumber(23.0);
通常好于
Complex fulcrumPoint = new Complex(23.0);
因為FromRealNumber描述了這個構(gòu)造器和別的構(gòu)造器的不同之處。
- 盡量給方法和類的命名都通俗易懂丐箩,不要為了耍寶起一些罕見的罕見的名字摇邦。畢竟代碼是用來讀的不是用來炫耀的。
- 每種概念都對應(yīng)一個單詞屎勘,并且一以貫之施籍。如查詢方法經(jīng)常有g(shù)et、query概漱、find丑慎、select、fetch等詞我們最好選一個詞來對應(yīng)查詢這個概念
- 盡量避免用含有多個意思的詞如add瓤摧,既可以表示加法立哑,又可以表示添加元素,有時會對讀程序的人產(chǎn)生誤導(dǎo)姻灶。
- 使用某種解決方案領(lǐng)域的專有名稱铛绰,如果你使用了監(jiān)聽器,可以把類名后綴寫成listener产喉、如果使用訪問者模式捂掰,可以用visitor作為類的后綴,如果使用了門面模式可用face作為后綴曾沈,這樣在別的程序員讀你的代碼時就會有個全局的概念这嚣,知道你設(shè)計代碼時的思路。更好的理解代碼塞俱。
- 如果不能使用計算機(jī)解決方案領(lǐng)域的名詞來命名姐帚,那就使用業(yè)務(wù)領(lǐng)域的名詞來命名吧。至少障涯,負(fù)責(zé)維護(hù)代碼的程序員就能去請教領(lǐng)域?qū)<伊耍?strong>優(yōu)秀的程序員和設(shè)計師罐旗,其工作之一就是分離解決方案領(lǐng)域和業(yè)務(wù)領(lǐng)域的概念。與所涉問題領(lǐng)域更為貼近的代碼唯蝶,應(yīng)當(dāng)采用源自業(yè)務(wù)領(lǐng)域的名稱九秀。