《設(shè)計(jì)模式之美》筆記:規(guī)范與重構(gòu)

理解重構(gòu)

  • 重構(gòu)是一種對軟件內(nèi)部結(jié)構(gòu)的改善,目的是在不改變軟件的可見行為的情況下,使其更易理解,修改成本更低。
  • 在保持功能不變的前提下,利用設(shè)計(jì)思想、原則、模式、編程規(guī)范等理論來優(yōu)化代碼,修改設(shè)計(jì)上的不足,提高代碼質(zhì)量。
  • 重構(gòu)是避免過渡設(shè)計(jì)的有效手段。在我們維護(hù)代碼的過程中,真正遇到問題的時(shí)候,再對代碼進(jìn)行重構(gòu),能有效避免前期投入太多時(shí)間做過度的設(shè)計(jì)。
  • 不要等到代碼爛到一定程度才去重構(gòu),持續(xù)重構(gòu)是一個(gè)良好的習(xí)慣。


單元測試

  • 單元測試的測試對象是類或者函數(shù),是代碼層級的測試。
  • 代碼的可測試性是評判代碼質(zhì)量的一個(gè)重要標(biāo)準(zhǔn)。
  • 寫單元測試的過程本身就是代碼重構(gòu)的過程。
  • 單元測試用例實(shí)際上就是用戶用例,反映了代碼的功能和如何使用,有助于幫助其他人快速熟悉相關(guān)的代碼。
  • 寫單元測試就是針對代碼設(shè)計(jì)覆蓋各種輸入、異常、邊界條件的測試用例,并將這些測試用例翻譯成代碼的過程。
  • 依賴注入是實(shí)現(xiàn)代碼可測試性的最有效的手段。


常見的Anti-Patterns (即測試性不好的代碼)

  • 未決行為:代碼的輸出是隨機(jī)或者說不確定的,比如跟時(shí)間、隨機(jī)數(shù)有關(guān)的代碼。
  • 全局變量
  • 靜態(tài)方法
  • 復(fù)雜繼承
  • 高耦合代碼


解耦

  • 解耦,是保證代碼不至于復(fù)雜到無法控制的有效手段。
  • 如何判斷代碼是否需要解耦?
    • 修改代碼是否牽一發(fā)而動全身?
    • 把模塊間、類間的依賴關(guān)系畫出來,看看依賴關(guān)系圖是否過于復(fù)雜?
  • 解耦的手段
    • 封裝與抽象:可以有效地隱藏實(shí)現(xiàn)的復(fù)雜性,隔離實(shí)現(xiàn)的易變性,給依賴的模塊提供穩(wěn)定且易用的抽象接口。
    • 中間層
    • 模塊化:模塊化思想的本質(zhì)就是分而治之。
    • 其他設(shè)計(jì)思想和原則
      • 單一職責(zé)原則
      • 基于接口而非實(shí)現(xiàn)變成
      • 依賴注入
      • 多用組合少用繼承
      • 迪米特法則


編碼規(guī)范

  • 命名
    • 長度:首先要求準(zhǔn)確達(dá)意,在此基礎(chǔ)上越短越好。
    • 利用上下文簡化命名。
    • 命名要可讀、可搜索。
      • 可讀就是,得讓人能讀出來,比如 eyrie 這種命名,沒人知道怎么讀。
      • 可搜索就是,整個(gè)項(xiàng)目有個(gè)命名習(xí)慣,比如,統(tǒng)一使用getxxx,不要這里用getxxx,那里用queryxxx。
    • 對接口和抽象類的命名,項(xiàng)目內(nèi)統(tǒng)一一下,比如:接口類都寫成Ixxx。
  • 注釋
    • 注釋跟命名同等重要。
    • 注釋寫什么?
      • 目的是為了讓代碼更容易看懂,應(yīng)包含三個(gè)方面:做什么、為什么、怎么做。
        • 具體情況具體分析,簡單易懂的函數(shù),沒必要寫“為什么、怎么做”,但對于復(fù)雜的函數(shù),或者一些類來說,注釋起到了總結(jié)性作用、文檔的作用,可以讓閱讀代碼的人通過注釋就能大概了解代碼的實(shí)現(xiàn)思路,對閱讀代碼有幫助。
    • 注釋是否越多越好?
      • 通常類和函數(shù)一定要寫注釋,且酌情詳細(xì)些。函數(shù)內(nèi)部的注釋相對少一些。
  • 代碼風(fēng)格
    • 類、函數(shù)多大才合適?
      • 看感覺。團(tuán)隊(duì)項(xiàng)目約定。
    • 一行代碼多長合適?
      • 看感覺。團(tuán)隊(duì)項(xiàng)目約定。
    • 善用空行分割單元塊。
    • 四格縮進(jìn)還是兩格縮進(jìn)?
      • 團(tuán)隊(duì)項(xiàng)目約定。反正,不要用tab,因?yàn)椴煌腎DE下,tab的顯示寬度不同。
    • 大括號是否要另起一行?
      • 團(tuán)隊(duì)項(xiàng)目約定。
    • 類中成員的排列順序
      • emmm..在現(xiàn)代IDE的加持下,感覺不太所謂呢,如果追求好看就約定一下吧。(這句我說的)
  • 提高代碼可讀性的一些編程技巧
    • 把代碼分割成更小的單元塊。
      • 把大塊的復(fù)雜邏輯提煉成類或者函數(shù),屏蔽掉細(xì)節(jié),讓閱讀代碼的人不至于迷失在細(xì)節(jié)中。
      • 只有代碼邏輯比較復(fù)雜的時(shí)候才建議提煉。
    • 避免函數(shù)參數(shù)過多。
      • 處理方法:
        • 考慮函數(shù)是否職責(zé)單一,能否拆分成多個(gè)函數(shù)。
        • 將函數(shù)的參數(shù)封裝成對象。
    • 勿用函數(shù)參數(shù)來控制邏輯。
      • 明顯未被單一職責(zé)原則和接口隔離原則。
      • (我說的)這個(gè)還是具體情況具體分析,沒那么絕對。比如要寫一個(gè)支持篩選獲取列表的接口,篩選條件本身就會影響邏輯,但不太適合拆開,不然得寫一堆函數(shù)。
    • 函數(shù)設(shè)計(jì)要職責(zé)單一。
    • 移除過深的嵌套層次。
      • 代碼嵌套過審?fù)且驗(yàn)閕f-else、switch-case、for循環(huán)過度嵌套導(dǎo)致。
      • 如果嵌套超過兩層,就要思考一下能否減少嵌套。嵌套本身就不好理解,嵌套過深,不僅理解起來費(fèi)勁,也會因?yàn)槎啻慰s進(jìn)影響代碼整潔。
      • 常見的解決思路:
        • 去掉多余的if或else。
        • 使用continue、break、return關(guān)鍵字,提前退出嵌套。
        • 調(diào)整執(zhí)行順序來減少嵌套。
        • 將部分嵌套邏輯封裝成函數(shù)調(diào)用。
    • 學(xué)會使用解釋性變量。
      • 常量取代魔法數(shù)字。比如:定義一個(gè)PI,替換代碼里的3.1415魔法數(shù)字。
      • 使用解釋性變量來解釋復(fù)雜表達(dá)式。
  • 統(tǒng)一編碼規(guī)范(最重要)


如何發(fā)現(xiàn)代碼質(zhì)量問題 - 常規(guī) checklist

  • 目錄設(shè)置是否合理,模塊劃分是否清晰,代碼結(jié)構(gòu)是否滿足“高內(nèi)聚、松耦合”?
  • 是否遵循經(jīng)典的設(shè)計(jì)原則和設(shè)計(jì)思想(SOLID、DRY、KISS、YAGNI、LOD等)?
  • 設(shè)計(jì)模式是否應(yīng)用得當(dāng)?是否有過度設(shè)計(jì)?
  • 代碼是否容易擴(kuò)展?如果要添加新功能,是否容易實(shí)現(xiàn)?
  • 代碼是否可以復(fù)用?是否可以復(fù)用已有的項(xiàng)目代碼或類庫?是否有重復(fù)造輪子?
  • 代碼是否容易測試?單元測試是否全面覆蓋各種正常和異常的情況?
  • 代碼是否易讀?是否符合編碼規(guī)范(比如命名和注釋是否恰當(dāng)、代碼風(fēng)格是否一致等)?


如何發(fā)現(xiàn)代碼質(zhì)量問題 - 業(yè)務(wù)需求 checklist

  • 代碼是否實(shí)現(xiàn)了預(yù)期的業(yè)務(wù)需求?
  • 邏輯是否正確?是否處理了各種異常情況?
  • 日志打印是否得當(dāng)?是否方便debug排查問題?
  • 接口是否易用?是否支持冪等、事務(wù)等?
  • 代碼是否存在并發(fā)問題?是否線程安全?
  • 性能是否有優(yōu)化空間,比如,SQL、算法是否可以優(yōu)化?
  • 是否有安全漏洞?比如,輸入輸出校驗(yàn)是否全面?
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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