java代碼規(guī)范之不合理命名與重復(fù)代碼示例詳解
一. 命名
1.1 命名是否具有業(yè)務(wù)含義
(1) 命名不精準(zhǔn),用詞寬泛,不能有效反應(yīng)代碼含義
從溝通的角度看,這就不是一個(gè)有效的溝通。要想理解它,需要消耗大量的認(rèn)知成本,時(shí)間和精力,同樣也增加了后來(lái)人包括我們自己維護(hù)代碼的成本。
其中,Info、data、flag、process、handler、build、maintain、manager、modify
等,都是屬于典型的過(guò)于寬泛的名字,當(dāng)這些名字出現(xiàn)的地方,多半都是寫(xiě)代碼的人當(dāng)時(shí)沒(méi)有想好用什么名字。
命名要能夠描述出這段代碼在做的事情,好的名字應(yīng)該描述意圖,而非細(xì)節(jié)。
命名演化示例:
processChapter:處理章節(jié),命名寬泛
changeChapterToTranlsating:將章節(jié)修改為翻譯中 在描述細(xì)節(jié)
startTranslation:開(kāi)始翻譯,描述意圖
(2) 用技術(shù)術(shù)語(yǔ)命名
xxxList,xxxMap,xxxSet
這是一種不費(fèi)腦子的命名方式,因?yàn)樗且环N基于實(shí)現(xiàn)細(xì)節(jié)的命名方式。
重要原則:面向接口編程,不要面向?qū)崿F(xiàn)編程。因?yàn)榻涌谑欠€(wěn)定的,而實(shí)現(xiàn)是易變的。
正確示例:
bookList -> books xxxMap -> xxxMaping
實(shí)際上,在實(shí)際的代碼中,技術(shù)術(shù)語(yǔ)的出現(xiàn),往往代表著缺少了一個(gè)應(yīng)有的模型。
比如在業(yè)務(wù)代碼中直接出現(xiàn)了redis,通常來(lái)說(shuō),我們真正需要的只是一個(gè)緩存,而redis只是緩存這個(gè)模型的一個(gè)實(shí)現(xiàn)而已。
而再進(jìn)一步,緩存這個(gè)概念也是一種技術(shù)術(shù)語(yǔ),從某種意義上,它也不應(yīng)該出現(xiàn)在業(yè)務(wù)代碼中。Spring就做的比較好,需要緩存,就加上@Cacheable
的注解。
注意,在技術(shù)類(lèi)項(xiàng)目中,存在技術(shù)術(shù)語(yǔ)即是業(yè)務(wù)語(yǔ)言的情況;但對(duì)于業(yè)務(wù)項(xiàng)目,這個(gè)說(shuō)法就必須重新審視。
(3) 用業(yè)務(wù)語(yǔ)音寫(xiě)代碼
編寫(xiě)可維護(hù)的代碼,要使用業(yè)務(wù)語(yǔ)音,而怎么知道自己的命名是否用的是業(yè)務(wù)語(yǔ)音呢,就是把這個(gè)詞講給產(chǎn)品經(jīng)理,看他是否知道。
一個(gè)好的做法:在團(tuán)隊(duì)建立自己的業(yè)務(wù)語(yǔ)言詞匯表。
approveChapter(long chapterId,long userId) -> approveChapter(long chapterId,long reviewerId)
(4) 小結(jié)
- 壞味道:不精準(zhǔn)的命名,用技術(shù)術(shù)語(yǔ)命名。
- 解決之道:好的命名要體現(xiàn)代碼在做什么,但無(wú)需展示代碼的細(xì)節(jié),更進(jìn)一步,要準(zhǔn)確體現(xiàn)意圖,而不是實(shí)現(xiàn)細(xì)節(jié),更高的要求是,用業(yè)務(wù)語(yǔ)言寫(xiě)代碼。
- 原則:描述意圖,而非細(xì)節(jié);面向接口編程,接口是穩(wěn)定的,實(shí)現(xiàn)是易變的;命名出現(xiàn)技術(shù)名詞,往往是缺少了一個(gè)模型;使用業(yè)務(wù)語(yǔ)音。
1.2 命名是否符合英語(yǔ)語(yǔ)法
(1)違反語(yǔ)法規(guī)則命名
完成翻譯,方法名:completedTranslate 不是有效的動(dòng)賓結(jié)構(gòu) ->completeTranslation
重新翻譯,方法名:retranslation 應(yīng)該是一個(gè)動(dòng)詞 -> retranslate
常見(jiàn)的命名規(guī)則:類(lèi)名是一個(gè)名詞,表示一個(gè)對(duì)象;方法名是一個(gè)動(dòng)詞,或是動(dòng)賓短語(yǔ),表示一個(gè)動(dòng)作。
(2)不準(zhǔn)確的英語(yǔ)詞匯
審核:
audit:更官方,偏向?qū)徲?jì)
review
常用的做法就是把中文詞扔到字典網(wǎng)站從返回的眾多結(jié)果中找到一個(gè)自己看著順眼的。好一點(diǎn)的做法是根據(jù)google翻譯,然后根據(jù)二者的英文釋義進(jìn)行比較。
其實(shí),在這種情況下,最好的解決方案就是建立一個(gè)業(yè)務(wù)詞匯表,而不是自己臆想。建立詞匯表的一個(gè)關(guān)鍵點(diǎn)是用集體智慧,而非個(gè)體智慧。另外,業(yè)務(wù)詞匯表也是屬于構(gòu)建團(tuán)隊(duì)同樣語(yǔ)言的一部分成果。
(3)英語(yǔ)單詞拼寫(xiě)錯(cuò)誤
一個(gè)好的解決方案,借助工具插件檢查拼寫(xiě)錯(cuò)誤。
(4)小結(jié)
- 壞味道:命名違反語(yǔ)法規(guī)則,用詞不準(zhǔn)確,單詞拼寫(xiě)錯(cuò)誤。更低級(jí)的一些,使用拼音,使用不恰當(dāng)?shù)膯卧~簡(jiǎn)寫(xiě)。(如果非要用縮寫(xiě),可以用一些行業(yè)通用的縮寫(xiě),而最好不要自己創(chuàng)造,前提是一定要約定好)
- 解決之道:制定代碼規(guī)范,比如類(lèi)名用名詞,函數(shù)名用動(dòng)詞或動(dòng)賓短語(yǔ);建立團(tuán)隊(duì)詞匯表;經(jīng)常進(jìn)行代碼評(píng)審。
-小工具:命名插件codelf。
二. 重復(fù)代碼
重復(fù)代碼產(chǎn)生的一些常見(jiàn)原因:
- 代碼結(jié)構(gòu)不合理導(dǎo)致同一個(gè)實(shí)現(xiàn)散落各處。由于初期代碼結(jié)構(gòu)設(shè)計(jì)不合理導(dǎo)致后續(xù)功能實(shí)現(xiàn)無(wú)法快速找到已有實(shí)現(xiàn),或者找到了但是不好引用已有實(shí)現(xiàn)。改進(jìn):初期設(shè)計(jì)代碼邏輯合理,對(duì)于不合理的地方要及時(shí)重構(gòu) 防止演變成原因2。
- 為了穩(wěn)定性,不動(dòng)老邏輯,拷貝一份。由于對(duì)于業(yè)務(wù)的不熟悉和對(duì)自己代碼能力的不信任,不敢重構(gòu)導(dǎo)致。改進(jìn):通過(guò)微重構(gòu)進(jìn)行多次迭代小改進(jìn)慢慢優(yōu)化。
- 寫(xiě)的時(shí)候?yàn)榱丝?,由于時(shí)間緊張或者能力問(wèn)題,無(wú)法識(shí)別出的壞代碼。改進(jìn):提升能力。
復(fù)制粘貼的代碼
結(jié)構(gòu)重復(fù)的代碼
示例如下:
@Task public void sendBook() { try { this.service.sendBook(); } catch (Throwable t) { this.notification.send(new SendFailure(t))); throw t; } } @Task public void sendChapter() { try { this.service.sendChapter(); } catch (Throwable t) { this.notification.send(new SendFailure(t))); throw t; } }
優(yōu)化之后:
@Task public void sendChapter() { executeTask(this.service::sendChapter); } @Task public void sendBook() { executeTask(this.service::sendBook); } private void executeTask(final Runnable runnable) { try { runnable.run(); } catch (Throwable t) { this.notification.send(new SendFailure(t))); throw t; } }
對(duì)于支持函數(shù)式編程的程序設(shè)計(jì)語(yǔ)言來(lái)說(shuō),可以用語(yǔ)言提供的便利寫(xiě)法簡(jiǎn)化代碼的編寫(xiě),就像上面的代碼就是用了 Java 里的方法引用(Method Reference)
。
if 和 else 代碼塊中的語(yǔ)句高度類(lèi)似
只要你看到 if 語(yǔ)句出現(xiàn),而且 if 和 else 的代碼塊長(zhǎng)得又比較像,多半就是出現(xiàn)了這個(gè)壞味道。
if (user.isEditor()) { service.editChapter(chapterId, title, content, true); } else { service.editChapter(chapterId, title, content, false); }
優(yōu)化之后:
service.editChapter(chapterId, title, content, user.isEditor());
小結(jié)
- 壞味道:重復(fù)的代碼,重復(fù)的結(jié)構(gòu),if 和 else 代碼塊中的語(yǔ)句高度類(lèi)似
- 解決之道:不要使用復(fù)制粘貼;先提取函數(shù),然后在需要的地方調(diào)用這個(gè)函數(shù)。
以上就是java代碼規(guī)范之不合理命名與重復(fù)代碼示例詳解的詳細(xì)內(nèi)容,更多關(guān)于java命名代碼規(guī)范的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java使用Collections工具類(lèi)對(duì)List集合進(jìn)行排序
這篇文章主要介紹了Java使用Collections工具類(lèi)對(duì)List集合進(jìn)行排序,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10Java程序打包成帶參數(shù)的jar文件實(shí)例代碼
這篇文章主要介紹了Java程序打包成帶參數(shù)的jar文件實(shí)例代碼,需要的朋友可以參考下2017-09-09SpringBoot整合EasyExcel進(jìn)行大數(shù)據(jù)處理的方法詳解
EasyExcel是一個(gè)基于Java的簡(jiǎn)單、省內(nèi)存的讀寫(xiě)Excel的開(kāi)源項(xiàng)目。在盡可能節(jié)約內(nèi)存的情況下支持讀寫(xiě)百M(fèi)的Excel。本文將在SpringBoot中整合EasyExcel進(jìn)行大數(shù)據(jù)處理,感興趣的可以了解一下2022-05-05詳解SpringBoot注冊(cè)Windows服務(wù)和啟動(dòng)報(bào)錯(cuò)的原因
這篇文章主要介紹了詳解SpringBoot注冊(cè)Windows服務(wù)和啟動(dòng)報(bào)錯(cuò)的原因,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-03-03Java System類(lèi)詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
System類(lèi)是jdk提供的一個(gè)工具類(lèi),有final修飾,不可繼承,由名字可以看出來(lái),其中的操作多數(shù)和系統(tǒng)相關(guān)。這篇文章主要介紹了Java System類(lèi)詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理,需要的朋友可以參考下2017-04-04SpringBoot請(qǐng)求參數(shù)相關(guān)注解說(shuō)明小結(jié)
這篇文章主要介紹了SpringBoot請(qǐng)求參數(shù)相關(guān)注解說(shuō)明,主要包括@PathVariable,@RequestHeader、@CookieValue、@RequestBody和@RequestParam,本文結(jié)合實(shí)例代碼給大家講解的非常詳細(xì),需要的朋友可以參考下2022-05-05SpringBoot集成Spring Data JPA及讀寫(xiě)分離
這篇文章主要介紹了SpringBoot集成Spring Data JPA及讀寫(xiě)分離的相關(guān)知識(shí),需要的朋友可以參考下2017-04-04Java基礎(chǔ)知識(shí)精選 你答對(duì)了幾道?
精選Java基礎(chǔ)知識(shí)講解,看看你能答對(duì)多少?2017-09-09