能夠說,任何軟件系統從設計部署好的次日起,就都變成了 既有代碼(existing code)。一個幾年的系統和一個幾周的系統中存在的問題,並沒有本質上的差別。react
俗話說,創業容易守業難。比新搭建一個系統更常見的工做,正是對既有系統的平常維護,通常包括:架構
如何有效進行這些工做,而不是陷入「修復一個bug,還你幾個新bug」的惡性循環,是每一個開發者必然面對的課題。函數
既有代碼的一種極端狀況,就 是遺留代碼(legacy code),通常指那些無人再維護的,或架構很是過期,亦或運行在老舊的操做系統上的代碼。性能
相比於在大抵上每幾天就打個照面的既有代碼中修修改改;當面對一頭霧水的遺留代碼時,若是沒有正確的方法,即使再當心翼翼,也總會陷入一籌莫展的境地。單元測試
每一個開發者可能都見過奇奇怪怪的各類具體問題,但概括起來,主要有這麼三種狀況:測試
面對以上困境,須要作的就是重構:優化
在不改變代碼功能的前提下,改善其設計的行爲被稱爲 重構(refactor)ui
重構的意義:使既有代碼更具可維護性,並消除其不肯定性操作系統
重構的關鍵:在其過程當中不該該有任何功能上的改變設計
在以前提到過的幾種平常工做中,無一例外不須要先進行有效的重構,才能保證工做的順利進行。
一樣顯而易見的是,將三重困境一一化解,就能夠達到理想的重構:
依賴:
封裝:
測試:
簡而言之,前兩項是最後「落在實處」的工做,而測試的重要性並不亞於任何工做,甚至是保證前兩項進行下去的關鍵。 **測試覆蓋率(test coverage)**越高,說明所覆蓋部分的可靠性越有保證,而沒必要時時擔憂改動帶來的未知影響。
遵循爲獨立單元(視狀況爲函數、類或組件等)編寫測試的理念,就能夠寫出小而易理解的一個個測試用例,也反過來使得代碼比寫註釋更容易理解。
對於新開發的功能,能夠用測試驅動開發(TDD)的方法,即重複「寫一點代碼->編寫測試->失敗->修改代碼->測試經過」的過程,最終達到方法的完成。
對於既有代碼,能夠根據平常需求,對涉及到的部分逐步引入單元測試,持續不斷的提升系統的測試覆蓋率。
這裏舉一個足夠簡單也比較典型的例子:重構stepper組件
在這個由 react 組件構建的既有系統中,在若干界面中都引用了一個常見的 數字選擇器(numeric stepper),其變化會觸發判斷邏輯,提示商品對應的數量是否有足夠庫存、是否達到了限購數量等
NumberStepper
裏糅雜了具體業務邏輯「限購」和「庫存」的判斷NumberStepper
和各類容器組件中,均分別存在用 0|1|2|3
定義的判斷和顯示邏輯,且無註釋說明困境 | 問題A | 問題B | 問題C |
---|---|---|---|
依賴太重 | √ | √ | |
封裝錯誤 | √ | √ | √ |
缺少測試 | √ | √ |
NumberStepper
中的具體業務邏輯依賴刪除NumberStepper
暴露props.checkLimit
,在數量增減時響應,將判斷邏輯交給調用者onLimitOver
的函數簽名,明確參數的意義NumberStepper
和OverLimit
等組件編寫測試,保證改動的全面和正確性至此,以前的結構獲得了有效的梳理;再進行相關的功能添加就有章可循、心中有數了。