思想為源——讀《編寫(xiě)高質(zhì)量代碼:改善Java程序的151個(gè)建議》(十二)

讀書(shū),收獲,分享
建議后面的五角星僅代表筆者個(gè)人需要注意的程度。
Talk is cheap.Show me the code

建議144:提倡良好的代碼風(fēng)格★★☆☆☆

優(yōu)秀團(tuán)隊(duì)的編碼風(fēng)格應(yīng)該具有哪些特征:

  1. 整潔

    代碼首先是給人看的,然后才是給機(jī)器執(zhí)行的,對(duì)于機(jī)器來(lái)說(shuō),只要代碼符合規(guī)范,不在乎其格式是否整潔、是否有縮進(jìn)、是否有回車(chē),只要代碼正確就能正常運(yùn)行,而人就不同了,沒(méi)有縮進(jìn)沒(méi)有回車(chē)的代碼基本上是不可閱讀的。

  2. 統(tǒng)一

    從一個(gè)團(tuán)隊(duì)中誕生的代碼應(yīng)該具有一致的風(fēng)格,不要帶有個(gè)人色彩的風(fēng)格標(biāo)識(shí)。盡量讓我們的代碼看起來(lái)很職業(yè)。

  3. 流行

    一種潮流風(fēng)行世界的時(shí)候必然有其誕生的原因(感冒也包括在內(nèi)),一種編碼格式的流行也必然有它存在的理由,我們完全可以借鑒流行的編碼格式,沒(méi)有必要對(duì)這種風(fēng)格進(jìn)行重塑,而且使用流行風(fēng)格可以讓新成員盡快融入項(xiàng)目,避免出現(xiàn)進(jìn)入一個(gè)新環(huán)境而出現(xiàn)茫茫無(wú)助的狀態(tài)。

  4. 便捷

    制定出來(lái)的編碼規(guī)范必須有通用開(kāi)發(fā)工具支撐,不能制定出只能由個(gè)別開(kāi)發(fā)工具支持的規(guī)范。

建議145:不要完全依靠單元測(cè)試來(lái)發(fā)現(xiàn)問(wèn)題★★☆☆☆

原因有以下四點(diǎn):

  1. 單元測(cè)試不可能測(cè)試所有的場(chǎng)景(路徑)

    單元測(cè)試必須測(cè)試的三種數(shù)據(jù)場(chǎng)景是:正常場(chǎng)景、邊界場(chǎng)景、異常場(chǎng)景。如果這三種測(cè)試場(chǎng)景都能出現(xiàn)預(yù)期的結(jié)果,則認(rèn)為代碼正確。

  2. 代碼整合錯(cuò)誤是不可避免的

    單元測(cè)試只是保證了分割的獨(dú)立單元的正確性,它不能保證一個(gè)功能的完整性。

  3. 部分代碼無(wú)法(或很難)測(cè)試

  4. 單元測(cè)試驗(yàn)證的是編碼人員的假設(shè)

敏捷開(kāi)發(fā)中提倡的TDD(Test-Driven Development)測(cè)試驅(qū)動(dòng)開(kāi)發(fā):?jiǎn)卧獪y(cè)試先行,而后才會(huì)編寫(xiě)生產(chǎn)代碼,這可以大幅度地提升代碼質(zhì)量,加快項(xiàng)目開(kāi)發(fā)的進(jìn)度。

建議146:讓注釋正確、清晰、簡(jiǎn)潔★★☆☆☆

一些不好的注解習(xí)慣:

  1. 廢話式注釋

  2. 故事式注釋

    一句話說(shuō)清即可,不需要講故事

  3. 不必要的注釋?zhuān)ㄏ胄Γ?/p>

        //默認(rèn)值為0
        private int num;
    
  4. 過(guò)時(shí)的注釋

    注釋與代碼的版本不一致,注釋是1.0版本,而代碼早已竄到了5.0版本

  5. 大塊注釋代碼

    廢棄(在生產(chǎn)版本上肯定不用該代碼),則應(yīng)該完全刪除掉。

  6. 流水賬式的注釋

  7. 專(zhuān)為JavaDoc編寫(xiě)的注釋

    建議在注釋中只保留<p>、<code>等幾個(gè)常用的標(biāo)簽,不要增加<font>、<table>、<div>等標(biāo)簽。

那好的注釋?xiě)?yīng)該是這樣子的:首先要求正確,注釋與代碼意圖吻合;其次要求清晰,格式統(tǒng)一,文字準(zhǔn)確;最后要求簡(jiǎn)潔,說(shuō)明該說(shuō)明的,惜字如金,拒絕不必要的注釋。

如下類(lèi)型的注釋就是好的注釋?zhuān)?/p>

  1. 法律版權(quán)信息

    這是我們?cè)陂喿x源代碼時(shí)經(jīng)??吹降?,一般都是指向同一個(gè)法律版權(quán)聲明的。

  2. 解釋意圖的注釋

    說(shuō)明為什么要這樣做,而不是怎么做的

  3. 警示性注釋

  4. TODO注釋

    對(duì)于一些未完成的任務(wù),則增加上TODO提示,并標(biāo)明是什么事情沒(méi)有做完,以方便下次看到這個(gè)TODO標(biāo)記時(shí)還能記憶起要做什么事情

注意:注釋不是美化劑,而是催化劑,或?yàn)閮?yōu)秀加分,或?yàn)樽玖訙p分。

建議147:讓接口的職責(zé)保持單一★★☆☆☆

職責(zé)是一個(gè)接口(或類(lèi))要承擔(dān)的業(yè)務(wù)含義,或是接口(或類(lèi))表現(xiàn)出的意圖。

單一職責(zé)有以下三個(gè)優(yōu)點(diǎn):

  1. 類(lèi)的復(fù)雜性降低

    職責(zé)單一,在實(shí)現(xiàn)什么職責(zé)時(shí)都有清晰明確的定義,那么接口(或類(lèi))的代碼量就會(huì)減少,復(fù)雜度也就會(huì)減少。當(dāng)然,接口(或類(lèi))的數(shù)量會(huì)增加上去,相互間的關(guān)系也會(huì)更復(fù)雜,這就需要適當(dāng)把握了。

  2. 可讀性和可維護(hù)性提高

    職責(zé)單一,會(huì)讓類(lèi)中的代碼量減少,我們可以一眼看穿該類(lèi)的實(shí)現(xiàn)方式,有助于提供代碼的可讀性,這也間接提升了代碼的可維護(hù)性。

  3. 降低變更風(fēng)險(xiǎn)

    變更是必不可少的,如果接口(或類(lèi))的單一職責(zé)做得好,一個(gè)接口修改只對(duì)相應(yīng)的實(shí)現(xiàn)類(lèi)有影響,對(duì)其他的接口無(wú)影響,那就會(huì)對(duì)系統(tǒng)的擴(kuò)展性、維護(hù)性都有非常大的幫助。

注意:接口職責(zé)一定要單一,實(shí)現(xiàn)類(lèi)職責(zé)盡量單一。

建議148:增強(qiáng)類(lèi)的可替換性★★☆☆☆

里氏替換原則是說(shuō)“所有引用基類(lèi)的地方必須能透明地使用其子類(lèi)的對(duì)象”,通俗點(diǎn)講,只要父類(lèi)型能出現(xiàn)的地方子類(lèi)型就可以出現(xiàn),而且將父類(lèi)型替換為子類(lèi)型還不會(huì)產(chǎn)生任何錯(cuò)誤或異常,使用者可能根本就不需要知道是父類(lèi)型還是子類(lèi)型。但是,反過(guò)來(lái)就不行了,有子類(lèi)型出現(xiàn)的地方,父類(lèi)型未必就能適應(yīng)。

為了增強(qiáng)類(lèi)的可替換性,就要求我們?cè)谠O(shè)計(jì)類(lèi)的時(shí)候考慮以下三點(diǎn):

  1. 子類(lèi)型必須完全實(shí)現(xiàn)父類(lèi)型的方法

  2. 前置條件可以被放大

        class Base {
            public void doStuff(HashMap hashMap) {
            }
        }
    
        class Sub extends Base {
            public void doStuff(Map map) {
            }
        }
    
  1. 后置條件可以被縮小

增強(qiáng)類(lèi)的可替換性,則增強(qiáng)了程序的健壯性,版本升級(jí)時(shí)也可以保持非常好的兼容性。即使增加子類(lèi),原有的子類(lèi)還可以繼續(xù)運(yùn)行。

建議149:依賴(lài)抽象而不是實(shí)現(xiàn)★★☆☆☆

在面向過(guò)程開(kāi)發(fā)中,我們考慮的是如何實(shí)現(xiàn),依賴(lài)的是每個(gè)具體實(shí)現(xiàn),而在OOP中,則需要依賴(lài)每個(gè)接口,而不能依賴(lài)具體的實(shí)現(xiàn),比如我們要到北京出差,應(yīng)該依賴(lài)交通工具,而不是依賴(lài)的具體飛機(jī)或火車(chē),也就是說(shuō)我們依賴(lài)的是交通工具的運(yùn)輸能力,而不是具體的一架飛機(jī)或某一列火車(chē)。這樣的依賴(lài)可以讓我們實(shí)現(xiàn)解耦,保持代碼間的松耦合,提高代碼的復(fù)用率,這也是依賴(lài)倒置原則(Dependence Inversion Principle,簡(jiǎn)稱(chēng)DIP)提出的要求:

  1. 高層模塊不應(yīng)該依賴(lài)低層模塊,兩者都應(yīng)該依賴(lài)其抽象。
  2. 抽象不應(yīng)該依賴(lài)細(xì)節(jié)。
  3. 細(xì)節(jié)應(yīng)該依賴(lài)抽象。

依賴(lài)倒置原則在Java語(yǔ)言中的表現(xiàn)就是:

  1. 模塊間的依賴(lài)是通過(guò)抽象發(fā)生的,實(shí)現(xiàn)類(lèi)之間不發(fā)生直接的依賴(lài)關(guān)系,其依賴(lài)關(guān)系是通過(guò)接口或抽象類(lèi)產(chǎn)生的。
  2. 接口或抽象類(lèi)不依賴(lài)于實(shí)現(xiàn)類(lèi)。
  3. 實(shí)現(xiàn)類(lèi)依賴(lài)接口或抽象類(lèi)。

我們?cè)趺丛陧?xiàng)目中使用這個(gè)規(guī)則呢?只要遵循以下的幾個(gè)規(guī)則就可以:

  1. 盡量抽象
  2. 表面類(lèi)型必須是抽象的
  3. 任何類(lèi)都不應(yīng)該從具體類(lèi)派生
  4. 盡量不要覆寫(xiě)基類(lèi)的方法
  5. 抽象不關(guān)注細(xì)節(jié)

建議150:拋棄7條不良的編碼習(xí)慣★★☆☆☆

  1. 自由格式的代碼

  2. 不使用抽象的代碼

  3. 彰顯個(gè)性的代碼

    “最小驚詫原則”(Principle Of Least Surprise簡(jiǎn)稱(chēng)POLS,或者Principle Of LeastAstonishment簡(jiǎn)稱(chēng)POLA),其意是說(shuō)要使用最常見(jiàn)的,而不是最新穎的功能。

  4. 死代碼,冗余代碼

    忘記刪除的代碼或者廢棄的代碼等

  5. 拒絕變化的代碼

    一個(gè)在JDK 1.1中就過(guò)時(shí)的方法還還能在使用JDK 1.6項(xiàng)目中存在,謂之曰“沒(méi)有壞,就不要去修它”—該重構(gòu)它了,它沒(méi)壞,但它賴(lài)以生存的環(huán)境已經(jīng)變了!

  6. 自以為是的代碼

    相信自己編寫(xiě)的工具類(lèi),而不是開(kāi)源工具,寧愿自己寫(xiě)序列化工具,也不選擇kryoprotostuff;寧愿自己寫(xiě)日期處理工具,也不選擇Jodadate4j;寧愿自己寫(xiě)批處理框架,也不選擇Spring Batch,這樣是不行的!—相信天外有天吧,更多更好的工具等待著你去發(fā)掘。

建議151:以技術(shù)員自律而不是工人★★★★★

下20條建議可以逐步把我們向技術(shù)人員方向培養(yǎng):

  1. 熟悉工具

    軍人手中有槍?zhuān)r(nóng)民手中有鋤頭,而我們手里只有Java,這也是我們能夠引以為豪的工具,我們應(yīng)該了解它的使用范圍,了解的它的生態(tài)系統(tǒng),了解它的發(fā)展趨勢(shì)—它也可能就是陪伴我們一生的那個(gè)工具,也祝愿它是。

  2. 使用IDE

    在技術(shù)領(lǐng)域,不要相信“無(wú)刀勝有刀”之類(lèi)的鬼話—“高手都用記事本或VI開(kāi)發(fā)”

  3. 堅(jiān)持編碼

    不要考慮自己的職位、崗位,只要是Java圈子的生物都應(yīng)該堅(jiān)持編碼,沒(méi)有編碼,就等于是無(wú)源之水,無(wú)本之木,何來(lái)靈感和靈性?

  4. 編碼前思考

    在坐下來(lái)開(kāi)始編碼之前,必須已經(jīng)完成設(shè)計(jì),最低要求是對(duì)開(kāi)發(fā)中遇到的問(wèn)題有清晰的認(rèn)識(shí),不要在編碼中解決問(wèn)題。

  5. 堅(jiān)持重構(gòu)

    不要相信一次就能寫(xiě)出優(yōu)秀的代碼,這是不現(xiàn)實(shí)的,任何優(yōu)秀的代碼、算法都是經(jīng)過(guò)多次重構(gòu)磨練的,堅(jiān)信自己的下一個(gè)版本或代碼更優(yōu)秀。

  6. 寫(xiě)注釋、寫(xiě)說(shuō)明、寫(xiě)報(bào)告都是對(duì)代碼或項(xiàng)目的回顧和總結(jié),不僅僅是為了后續(xù)的參與人員,同時(shí)也是為了整理自己頭腦中混亂的思維。

  7. 保持程序版本的簡(jiǎn)單性

    一個(gè)項(xiàng)目不要保持多個(gè)版本,即使有分支也必須定義出項(xiàng)目合并的條件,或者時(shí)間約束,或者目標(biāo)約束,不可任由版本擴(kuò)散。

  8. 做好備份

    世界上沒(méi)有萬(wàn)無(wú)一失的事情,不做備份,一旦災(zāi)難發(fā)生就無(wú)挽救的余地了

  9. 做單元測(cè)試

    單元測(cè)試不僅能增強(qiáng)你的信心,也能給你帶來(lái)好名聲—后續(xù)者一看,“哇哦,單元測(cè)試寫(xiě)得這么完整,肯定是一個(gè)認(rèn)真、負(fù)責(zé)的人”。

  10. 不要重復(fù)發(fā)明輪子

    在項(xiàng)目中使用已經(jīng)成熟的工具或框架,而不是自己編寫(xiě)。但是如果想共享一個(gè)新的MVC框架,那就盡管去重復(fù)發(fā)明輪子吧,它不是以交付為目的的,而是以技術(shù)研究為目標(biāo)的。

  11. 當(dāng)按下Ctrl+C的時(shí)候,問(wèn)問(wèn)自己“我在做什么?拷貝是否是唯一能做的?為什么不能重構(gòu)一下呢”,不要讓大段的代碼散落在各處,不要做搬運(yùn)工,不要做拷貝工,要做技術(shù)工。

  12. 讓代碼充滿靈性

    為變量、類(lèi)、方法起個(gè)好聽(tīng)的名字是一個(gè)不錯(cuò)的主意,為代碼增加必要的注釋也是很好的辦法,“One Line”能解決一個(gè)上百行代碼的問(wèn)題,也是一個(gè)優(yōu)秀的實(shí)現(xiàn)。

  13. 測(cè)試自動(dòng)化

    不管是性能測(cè)試、單元測(cè)試,還是功能測(cè)試,想盡辦法讓它自動(dòng)化,不要在測(cè)試之前手動(dòng)配置或觸發(fā)條件,這不夠人性化,也同時(shí)讓代碼“汗顏”—本是用來(lái)自動(dòng)執(zhí)行的,但卻被手動(dòng)設(shè)置了條件。

  14. 做壓力測(cè)試

    不要相信業(yè)務(wù)人員“最多200個(gè)用戶使用”之類(lèi)的話,把業(yè)務(wù)人員制定的指標(biāo)擴(kuò)大3倍,然后再做壓力測(cè)試。不要迷信自己的代碼很健壯,在高并發(fā)時(shí)只有上帝知道發(fā)生了何事,你又怎么能知道?

  15. “剽竊”不可恥

    多看開(kāi)源代碼,學(xué)習(xí)一下人家是如何編碼的,然后經(jīng)?!柏飧`”一下,這也是提高技能的最佳途徑,我們不是孔乙己,“剽竊”不可恥。

  16. 堅(jiān)持向敏捷學(xué)習(xí)

    不管“敏捷”與“非敏捷”之間的爭(zhēng)論有多激烈,敏捷中的一些思想是非常優(yōu)秀的,例如TDD測(cè)試驅(qū)動(dòng)開(kāi)發(fā)、交流的重要性、循序漸漸開(kāi)發(fā)等。

  17. 重里更重面

UI(User Interface)是“面”,Java程序是“里”,客戶首先感受到的是“面”,然后才是“里”,要想獲得良好的第一印象,那就需要有一個(gè)簡(jiǎn)潔、清晰、便捷的UI,即使“金玉其外敗絮其中”,我們也可以繼續(xù)重構(gòu)。

  1. 分享

    “獨(dú)樂(lè)樂(lè)”不如“眾樂(lè)樂(lè)”,把自己的代碼分享出去收獲的不僅僅是贊許,還有自己能力的提升—暴露出自己的Bug,在眾目睽睽之下修正之,知恥而后勇也。

  2. 刨根問(wèn)底

    有問(wèn)題不可怕,可怕的是掩蓋,或者虛假掩蓋,“哦,這個(gè)問(wèn)題呀,加上這個(gè)參數(shù)就可以解決了”—這不是解決問(wèn)題的辦法,在答案之后加上“是因?yàn)椤?,這才是解決了問(wèn)題。

  3. 橫向擴(kuò)展

    Java要運(yùn)行在JVM、操作系統(tǒng)上,同時(shí)還要與硬件、網(wǎng)絡(luò)、存儲(chǔ)交互,另外要遵循諸如FTPSMTP、HTTP等協(xié)議,還要實(shí)現(xiàn)Web Service、RMIXML-RPC等接口,所以我們必須熟悉相關(guān)的知識(shí)—擴(kuò)展知識(shí)面,這些都是必須去學(xué)習(xí)的。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容