代码 | 一天一点代码坏味道(1)
【代碼精進(jìn)】|?總結(jié)/Edison Zhou
作為一個(gè)后端工程師,想必在職業(yè)生涯中都寫過一些不好維護(hù)的代碼。本文是我學(xué)習(xí)《代碼之丑》的學(xué)習(xí)總結(jié),今天第一天發(fā)車,先來看看在命名上的一些常犯的壞味道。
0為何要品代碼壞味道
Martin Flower在《重構(gòu)》一書中給不好維護(hù)的這一類代碼取了一個(gè)藝名:代碼的壞味道,而這些壞味道一旦堆積多了,整個(gè)系統(tǒng)雖然還是可以平穩(wěn)運(yùn)行,但是就是讓程序員不敢動(dòng),更別提重構(gòu)了。
因?yàn)?.....
哎,都是打工人,誰容易啊?
1不精準(zhǔn)的命名
直接來看一段壞味道代碼:
public void ProcessChapter(long chapterId) {Chapter chapter = _repository.GetChapterById(chapterId);if (chapter == null){throw new ArgumentException($"Unknown chapter [{chapterId}]");}chatper.TransactionState == TransactionState.TRANSLATING;_repository.UpdateChapter(chapter); }此段代碼存在的問題:方法名ProcessChapter命名過于寬泛,不能精準(zhǔn)描述意圖,是代碼難以理解的根源所在。
同類型的詞匯請(qǐng)各位看官自查,例如:data,info,flag,process,handle,build,maintain,manage,modify等等等,它們應(yīng)該都出現(xiàn)在你我的項(xiàng)目代碼中過。
重構(gòu)方法:命名需要能夠描述出這段代碼在做的事情,根據(jù)代碼的邏輯含義,調(diào)整其命名為 ChangeChapterToTranslating,是不是無論誰來接手這個(gè)方法的代碼就都好理解了?
一個(gè)好的名字應(yīng)該是描述意圖,而非細(xì)節(jié)的。那么,我們?cè)僦貥?gòu)一下,結(jié)合具體的業(yè)務(wù),將其命名改為 StartTranslation,即開始翻譯,是不是就更能體現(xiàn)業(yè)務(wù)含義了?
public?void?StartTranslation(long?chapterId) {...... }2用技術(shù)術(shù)語命名
這是一個(gè)我也經(jīng)常犯的壞味道:
List<Book> bookList = service.GetBooks();這個(gè)bookList的原因是因?yàn)樗念愋褪荓ist,還有xxxDict,xxxMap等,它不費(fèi)腦子,但它卻只是一種基于實(shí)現(xiàn)細(xì)節(jié)的命名方式。
重構(gòu)方法:使用面向意圖的名字。
又如,如果在業(yè)務(wù)代碼中出現(xiàn)了Redis這類的中間件:
通常來說,這里只是需要一個(gè)緩存,那么Redis也就只是這個(gè)緩存的一個(gè)具體實(shí)現(xiàn),如果換為其他的NoSQL存儲(chǔ)如Memcached呢?
因此,我們其實(shí)缺少了一個(gè)模型,在這里其實(shí)就是一個(gè)接口,假設(shè)這個(gè)接口如下:
public interface ICacheClient {object Get(string key);void Put(string key, object value); }使用接口替代之后,我們就是面向接口編程了:
技術(shù)人喜歡用技術(shù)名詞命名,因?yàn)檫@是大家習(xí)慣的語言。但是,對(duì)于業(yè)務(wù)項(xiàng)目而言,需要盡可能將技術(shù)術(shù)語隔離開,因?yàn)闃I(yè)務(wù)語言才是最好的命名方式。
DDD領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)方法就號(hào)召我們建立統(tǒng)一語言,這個(gè)統(tǒng)一語言是可以和業(yè)務(wù)部門的人員無障礙交流的語言,換句話說,也就是業(yè)務(wù)語言。另一方面來看,這就倒逼技術(shù)團(tuán)隊(duì)需要建立團(tuán)隊(duì)的業(yè)務(wù)詞匯表,讓團(tuán)隊(duì)成員達(dá)成統(tǒng)一共識(shí),這也是要統(tǒng)一共識(shí)需要付出的額外成本,但是這個(gè)成本是有價(jià)值的。
編寫可維護(hù)的代碼之路
比如,我們經(jīng)常會(huì)寫下面的參數(shù)命名:
public?void?ApproveChapter(long?chapterId,?long?userId)? {... }假設(shè)通過業(yè)務(wù)分析,這里的user其實(shí)是審核人,而我們?yōu)榱朔奖憔兔麨閡serId了。那么,將其改為reviewerUserId是不是更加貼近業(yè)務(wù)?
在實(shí)際開發(fā)中,這樣子的例子還有很多。
3亂用英語來命名
作為一個(gè)受了多年義務(wù)教育與高等教育的我們來說,English一點(diǎn)也不陌生,但是就是始終感覺用不到位。
如果能用中文來命名,我們是不會(huì)到處查單詞用英文來命名的,但是,用中文,沒有B格啊,我放棄!
違反語法規(guī)則的命名
類是一個(gè)名字,表示一個(gè)對(duì)象。而方法名一般是一個(gè)動(dòng)詞或動(dòng)賓短語,表示一個(gè)動(dòng)作。但是,有時(shí)候,我們喜歡忽視這個(gè)規(guī)則。
CompletedTranslate 是個(gè)啥(四不像結(jié)構(gòu))?改為 CompleteTranslation 是不是好一點(diǎn)(動(dòng)賓結(jié)構(gòu))?
又比如,一個(gè)方法名叫 ReTranslation(額,Translation好像是個(gè)名詞吧),意為重新翻譯,但作為方法名,應(yīng)該選擇動(dòng)詞,改為 ReTranslate 會(huì)更好(Translate是個(gè)動(dòng)詞,棒!)。
不準(zhǔn)確的英語詞匯
由于英文單詞可以有多個(gè)含義,且在不同場(chǎng)景下含義也可以不同,這就難為我們中國(guó)人了。
比如,下面的一個(gè)枚舉,想表達(dá)的是審核狀態(tài):
public enum ChapterAuditStatus {PENDING,APPROVED,REJECTED }但是,Audit這個(gè)詞雖然也有審核的含義,但是它更偏重于財(cái)務(wù)審計(jì)這塊,而這里的業(yè)務(wù)是文稿的審核。
因此,改為Review可能會(huì)更加貼近一些:
從上也可以看出,技術(shù)團(tuán)隊(duì)建立一個(gè)統(tǒng)一的業(yè)務(wù)詞匯表,很有必要!這是集體的智慧,而非個(gè)體的。一個(gè)人的英語可能不太好,但是一群人在一起,總有那么一個(gè)會(huì)找出合適的說法。
英語單詞拼寫錯(cuò)誤
這個(gè),我相信大家各自項(xiàng)目中都有不少拼錯(cuò)的案例,很多人查了單詞之后,都還是拼錯(cuò)...?
但是,往往很多時(shí)候就是差了或者多了那么一個(gè)字母,就會(huì)讓人懵逼了。
4小結(jié)
本文總結(jié)了命名相關(guān)的兩類壞味道,一是命名是否具有業(yè)務(wù)含義,二是命名是否符合英語語法。
最后,感謝鄭曄老師的這門《代碼之丑》課程,讓我受益匪淺!我也誠(chéng)心把它推薦給關(guān)注EdisonTalk公眾號(hào)的各位童鞋!
參考資料
鄭曄,《代碼之丑》(推薦訂閱學(xué)習(xí))
Martin Flower著,熊杰譯,《重構(gòu):改善既有代碼的設(shè)計(jì)》(推薦至少學(xué)習(xí)第三章)
????掃碼訂閱《代碼之丑》
????點(diǎn)擊購(gòu)買《重構(gòu):改善既有代碼的設(shè)計(jì)》
年終總結(jié):Edison的2020年終總結(jié)
數(shù)字化轉(zhuǎn)型:我在傳統(tǒng)企業(yè)做數(shù)字化轉(zhuǎn)型
C#刷題:C#刷劍指Offer算法題系列文章目錄
技術(shù)管理:IT技術(shù)人的技術(shù)管理學(xué)習(xí)進(jìn)階
商業(yè)知識(shí):IT技術(shù)人的底層商業(yè)知識(shí)兵器庫
.NET大會(huì):2020年中國(guó).NET開發(fā)者大會(huì)PDF資料
????掃碼關(guān)注EdisonTalk
不變的依舊是分享!
總結(jié)
以上是生活随笔為你收集整理的代码 | 一天一点代码坏味道(1)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c#爬虫-1688官网自动以图搜图
- 下一篇: 小心 Enum Parse 中的坑