<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    代碼重構(gòu)的藝術(shù)

    共 3616字,需瀏覽 8分鐘

     ·

    2020-12-17 12:09

    原文出自:https://juejin.cn/post/6903054491273625614

    什么是重構(gòu)

    所謂重構(gòu)是這樣一個過程:在不改變代碼外在行為的前提下,對源代碼做出修改,以改進程序的內(nèi)部結(jié)構(gòu),從而使代碼變得易于理解,可維護和可擴展。本質(zhì)上來說重構(gòu)就是在代碼寫好之后改進它的設(shè)計。

    重構(gòu)的目的是什么

    首先,重構(gòu)是時刻保證代碼質(zhì)量的一個極其有效的手段,不至于讓代碼腐化到無可救藥的地步。項目在演進,代碼不停地在堆砌。如果沒有人為代碼的質(zhì)量負(fù)責(zé)任,代碼總是會往越來越混亂的方向演進。當(dāng)混亂到一定程度之后,量變引起質(zhì)變,項目的維護成本已經(jīng)高過重新開發(fā)一套新代碼的成本,想要再去重構(gòu),已經(jīng)沒有人能做到了。

    ? 劣質(zhì)代碼可能會影響后續(xù)優(yōu)化的效率,從而進一步造成代碼劣化;隨著時間的推移,這種效應(yīng)將會導(dǎo)致代碼質(zhì)量大幅下降。破窗效應(yīng) (The Broken Windows Theory) ?

    其次,優(yōu)秀的代碼或架構(gòu)不是一開始就能完全設(shè)計好的,就像優(yōu)秀的公司和產(chǎn)品也都是迭代出來的。我們無法100%遇見未來的需求,也沒有足夠的精力、時間、資源為遙遠(yuǎn)的未來買單,所以,隨著系統(tǒng)的演進,重構(gòu)代碼也是不可避免的。

    何時需要重構(gòu)

    第一次做某件事時只管去做;第二次做類似的事會產(chǎn)生反感,但無論如何還是可以去做;第三次再做類似的事,你就應(yīng)該重構(gòu).

    添加新功能時重構(gòu)

    「種一棵樹最好的時間是十年前,其次是現(xiàn)在。」 重構(gòu)的最佳時機就是在添加新的功能之前。再動手添加新功能之前,我們不妨先考慮一下,如果對現(xiàn)有的代碼結(jié)構(gòu)做些微調(diào),是否會使加入新的功能變的容易的多。

    ? 如果你要給程序添加一個特性,但發(fā)現(xiàn)代碼因缺乏良好的結(jié)構(gòu)而不易于進行更改,那就先重構(gòu)那個程序,使其比較容易添加該特性,然后再添加該特性 ?

    修改問題時重構(gòu)

    「掃去窗上的塵埃,才可以看到窗外的美景?!?修改一個問題時,我們需要先理解代碼在做什么,然后才可以著手去修改。這段代碼可能是別人寫的,也可能時自己寫的,但無論如何,當(dāng)你覺得這段代碼邏輯糟糕,需要花費幾分鐘才能明白其中的含義時,你就要想著如何去重構(gòu)才可以使代碼變的更加簡潔直觀

    有計劃的對代碼重構(gòu)

    「找尋重構(gòu)和開發(fā)進度中適合自己的平衡點」 但有些時候我們在準(zhǔn)備重構(gòu)的時會發(fā)現(xiàn),之前的代碼結(jié)構(gòu)和依賴關(guān)系錯綜復(fù)雜,這時我們就要考慮當(dāng)前是否有足夠時間去很好的處理這些混亂的代碼。盡管重構(gòu)的目的是加快開發(fā)速度,但同時重構(gòu)也會拖慢軟件的開發(fā)進度。如果時間充足,那么當(dāng)下就是進行重構(gòu)最好的時機。當(dāng)魚和熊掌不可兼得的時候,應(yīng)當(dāng)保證軟件的開發(fā)進度不受影響,其次才是進行重構(gòu)。可以先把需要重構(gòu)地方記錄下來,整理出一個計劃,在未來的一段時間內(nèi)解決掉。

    Code Review時重構(gòu)

    「處明者不見暗中一物,處暗者能見明中區(qū)事?!?Code Review有助于在開發(fā)團隊中傳播知識,也有助于讓較有經(jīng)驗的開發(fā)者把知識傳遞給比較欠缺經(jīng)驗的人。Code Review對于編寫清晰的代碼也很重要,我寫的代碼也許對于我自己來說很清晰,但對于別人來說則不然。Code Review讓更多人有機會提出有用的建議來對代碼進行調(diào)整。三人行,則必有我?guī)煛?/p>

    何時不應(yīng)該重構(gòu)

    「有所為,有所不為?!?并非所有的糟糕代碼都需要重構(gòu),如果你不需要使用到這段代碼,那么就不必花心思去重構(gòu)它。只有你需要理解其中的工作原理時,對其重構(gòu)才有價值。當(dāng)然如果重寫比重構(gòu)更容易,那么就不需要重構(gòu)了。

    如何保證重構(gòu)后程序的正確性

    保證代碼正確性最好的方法就是進行「單元測試(Unit Testing)」 。當(dāng)重構(gòu)完成之后,如果新的代碼仍然能通過單元測試,那就說明代碼原有邏輯的正確性未被破壞,原有的外部可見行為未變。

    測試驅(qū)動開發(fā)是非常完美的方案。但實際上大部分IT公司的程序由于種種原因并沒有單元測試。這時需要一些工具用來幫助我們快速掃描代碼中的問題。比如可以給代碼增加Lint語法檢查,使用SonarQube對代碼進行質(zhì)量和漏洞掃描,前端同學(xué)還可以使用TypeScript等等。把這些代碼自動掃描工具集成到CI里面,可以大幅度 減少出現(xiàn)bug的情況。目前我所在部門前端組的一系列產(chǎn)品包括項目,已經(jīng)把這些功能集成在CI里面的,每次的代碼更新,都會觸發(fā)掃描代碼的流程,CI失敗就無法將代碼合并到開發(fā)分支上面。

    有了上述這些還不夠,在重構(gòu)完成之后,還要把改動部分的功能完整的自測一遍,以保證程序無誤。當(dāng)自測通過之后,就可以請測試同學(xué)來幫忙進行更加完整的測試流程。

    ? 為什么要進行這么嚴(yán)格的測試流程,因為要保證程序可靠性。如果一件事有可能出錯,那么它一定會出錯。?

    需要重構(gòu)的Bad Code

    糟糕的命名

    整潔代碼最重要的一環(huán) 就是好的名字,所以我們要深思熟慮如何給函數(shù)、模塊、變量和類命名,使它們 能清晰地表明自己的功能和用法。

    無意義的注釋

    學(xué)會只編寫夠用的注釋,過猶不及,應(yīng)當(dāng)重視質(zhì)量而不是數(shù)量

    多層的if語句嵌套

    if-else在程序設(shè)計中是不可避免的,作為程序員能做的就是減少嵌套,提升代碼的可閱讀性和質(zhì)量

    很酷卻不宜理解代碼

    上面這種寫法看起來是不是很酷,但是過一段時間再來看,你還能一眼看出這部分功能是做什么的嗎?在我剛接觸后端,使用python的時候?qū)戇^這樣的代碼,結(jié)果就是在排查問題的時候相當(dāng)頭疼。代碼寫的別人看不懂并不厲害,而是寫的誰都看的懂才是厲害。

    ? 調(diào)試在一開始就比編寫程序困難一倍。因此,按照定義,如果你的代碼寫得非常巧妙,那么你就沒有足夠的能力來調(diào)試它??铝譂h定律 (Kernighan's Law) ?

    不必要的繼承寫法

    繼承雖然是面向?qū)ο蟮乃拇筇匦灾唬褂美^承可以解決代碼復(fù)用的問題,但也有其缺點: 繼承層次過深、過于復(fù)雜會影響到代碼的可維護性。如果子類中有方法依賴于父類中的 方法或?qū)傩?,那么?dāng)父類發(fā)生改變時,子類很可能會發(fā)生無法預(yù)知的錯誤。

    而組合的方式是把類中所有的接口功能單獨實現(xiàn),然后使用這些單獨的對象組合在一起,完成和目標(biāo)類一致的功能。繼承是用來表示類之間的 is-a 關(guān)系,而組合是一種 has-a 的關(guān)系。使用組合+接口+委托的方式可以代替大多數(shù)的繼承場景。

    重構(gòu)代碼的設(shè)計原則

    開閉原則 (The Open/Closed Principle)

    ? 實體應(yīng)開放擴展并關(guān)閉修改。?

    實體(可以是類、模塊、函數(shù)等)應(yīng)該能夠使它們的行為易于擴展,但是它們的擴展行為不應(yīng)該被修改。

    里氏替換原則 (The Liskov Substitution Principle)

    ? 可以在不破壞系統(tǒng)的情況下,用子類型替換類型。?

    如果組件依賴于類型,那么它應(yīng)該能夠使用該類型的子類型,而不會導(dǎo)致系統(tǒng)失敗或者必須知道該子類型的詳細(xì)信息。

    依賴反轉(zhuǎn)原則 (The Dependency Inversion Principle)

    ? 高級模塊不應(yīng)該依賴于低級實現(xiàn)。?

    更高級別的協(xié)調(diào)組件不應(yīng)該知道其依賴項的詳細(xì)信息。

    接口隔離原則 (The Interface Segregation Principle)

    ? 不應(yīng)強制任何客戶端依賴于它不使用的方法。?

    組件的消費者不應(yīng)該依賴于它實際上不使用的組件函數(shù)。

    單一功能原則 (The Single Responsibility Principle)

    ? 每個模塊或者類只應(yīng)該有一項功能。?

    模塊或者類只應(yīng)該做一件事。實際上,這意味著對程序功能的單個小更改,應(yīng)該只需要更改一個組件。例如,更改密碼驗證復(fù)雜性的方式應(yīng)該只需要更改程序的一部分。

    合成/聚合復(fù)用原則(Composite/Aggregate Reuse Principle)

    ? 量的使用合成和聚合,而不是繼承關(guān)系達到復(fù)用的目的。?

    合成/聚合復(fù)用原則就是指在一個新的對象里通過關(guān)聯(lián)關(guān)系(包括組合關(guān)系和聚合關(guān)系)來使用一些已有的對象,使之成為新對象的一部分;新對象通過委派調(diào)用已有對象的方法達到復(fù)用已有功能的目的。簡而言之:要盡量使用組合/聚合關(guān)系,少用繼承。

    總結(jié)

    如果文中有錯誤的地方,還望不吝賜教。寫了這么多,其實是想表達一個觀點:代碼是寫給人看的,所以要做到良好的編程風(fēng)格,方便其他人閱讀,維護。 如果你所在的團隊代碼感覺并不十分優(yōu)雅的話,那就應(yīng)當(dāng)重構(gòu)了。引用前面說到的一句話 「種一棵樹最好的時間是十年前,其次是現(xiàn)在。

    ??愛心三連擊

    1.看到這里了就點個在看支持下吧,你的點贊,在看是我創(chuàng)作的動力。

    2.關(guān)注公眾號程序員成長指北,回復(fù)「1」加入Node進階交流群!「在這里有好多 Node 開發(fā)者,會討論 Node 知識,互相學(xué)習(xí)」!

    3.也可添加微信【ikoala520】,一起成長。


    “在看轉(zhuǎn)發(fā)”是最大的支持

    瀏覽 50
    點贊
    評論
    收藏
    分享

    手機掃一掃分享

    分享
    舉報
    評論
    圖片
    表情
    推薦
    點贊
    評論
    收藏
    分享

    手機掃一掃分享

    分享
    舉報

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    成人福利 | 无码操逼视频 | 欧美激情视频网站 | 日韩无码免费中文 | 一级黄色片免费 |