作者簡介 新茗 螞蟻金服·資料體驗技術團隊
前言
之前也介紹過我們團隊的前端專案從零開始經歷8個月迭代業務程式碼10萬行(僅為產品長期規劃需求的20%),至今仍然在不斷迭代的過程。
團隊成員除了設計好的架構來管理這種複雜度極高的前端應用,還開始補充設計模式以及重構方面的知識,目的是為了讓專案程式碼在不斷迭代的過程中優化專案程式碼,保持程式碼的新鮮度,魯棒性,可維護性… 讓後續加入的團隊新人也可以快速加入我們的產品開發中
PS: 不管對於何種語言,重構都是軟體開發過程中不可或缺的一部分。如果已經瞭解重構的基礎,可以直接跳往至文章後面的重構案例
部分。
重構背景
“如果尿布臭了,就換掉它”。
- 隨著業務需求的不斷加入,程式碼隨著時間的推移變得越來越糟。
- 這其中可能包括以下壞味道(僅列舉):
- 重複的程式碼
- 過長的函式
- 遵循一條原則: 每當感覺需要註釋來說明什麼的時候,可以嘗試將需要說明的東西寫進一個函式中
- 冗贅類
- 當子類沒有做足夠的工作的時候,或者說在可見的預期內,不會有新的情況出現,考慮將類內聯化。
- 過長的類
- 這種情況容易出現冗餘程式碼。比如如果類內出現了多個變數帶有相同的字首或者字尾,這意味著你可以考慮把他們提煉到某個元件內,或者考慮這個元件是否可以成為子類,使用提煉類的手法來重構。
什麼是重構
我們回過頭來看一下"什麼是重構"
-
不改變軟體可觀察行為的前提下,改善其內部結構
-
以提高理解性和降低修改成本
摘自《重構 - 改善既有程式碼的設計》(下面簡稱《重構》) 複製程式碼
何時重構?
我們需要明確的一點是: 重構不是一件應該特地撥出一段時間來做的事情。重構不是目的,但是重構可以幫助你把事情做好。
事不過三,三則重構
- 重複性工作,既有的程式碼無法幫助你輕鬆新增新特性時
- 修補bug時,排查邏輯困難
- code review 可以讓他人來複審程式碼檢查是否具備可讀性,可理解性
- 太多的程式碼無註釋,已然連自己都無法快速理清程式碼邏輯
重構的衡量指標
- 數量: 程式碼的行數
- 質量: 程式碼複雜度,耦合度,可讀性,架構依賴複雜度等
- 成本: 花費的時間
- 回報(成果): 支援後續功能的快速疊加,解決現有因程式碼設計問題無法優化的矛盾等
抓重點 抓重點啦
說了這麼多廢話,其實大家都明白沒有與實踐結合的理論都是空虛的。
但是 重構
和 設計模式
一樣,也是需要一個"學習——領悟——突破"的過程。第一步的學習讓你瞭解基本的重構手法,第二步的實踐勾起你對重構手法的回憶以及重溫應用,第三步的應用以及實踐經驗激發你的思考,領悟以及總結,以致於靈活運用。
但凡是人,總是在不斷學習,不斷溫習,以達到具體場景具體應用,靈活自如。 重構是一個很大的話題,《重構》作者本人也是經歷了N多的專案,以及多年的經驗才總結出來的重構技巧。
重構技巧
《重構》一書作者總結的重構手法實在是太多了,只能通過圖片來展示一下所有作者總結的重構列表。
具體的補充,大家可以看看《重構》一書。
重構的實踐
作者推薦的一種做法:
隨機挑選一個目標
先給自己選擇一個目標(譬如“去掉一堆不必要的子類”),然後朝著目標前進,每一步走得小而堅定沒把握就停下來
當你無法證明自己所做的一切能夠保證原有程式的邏輯和語義時,請你停下來思考:既有的重構是改善了還是毫無成果需要撤銷。保證每次重構後的測試都能正常跑通
作為開發者, 應當把重構作為開發的一部分,一邊開發一邊重構。在快速堆疊程式碼,實現基本需求功能的基礎上,寫好測試用例,保證功能不變,逐步重構。
這也是我們團隊要求每個人都掌握重構這門必備技能的原因。優秀的程式設計師應當儘量避免低質量的程式碼。
重構案例
故事場景
- 有三種型別的電影,顧客可以進行租賃
- 租賃規則
- 價格計算規則:
普通片兒 —— 起步價2¥,超過2天的部分每天每部電影收費1.3元
新片兒 —— 每天每部3元
兒童片 —— 起步價2¥,超過3天的部分每天每部電影收費0.8元 - 積分計算規則:
每借一部電影積分加1,新片每部加2
- 價格計算規則:
原始程式碼
程式結果:(請保證重構後結果不變~)
- 類圖
- 劃分職責關係,遵循單一職責原則
- statement列印賬單函式承擔了很多功能,包括收費計算,積分計算以及結果展示等等
- 解法1: 6.1 Extract Method(提煉函式) —— 最常用的重構手法
- 解法2: 9.1 Decompose Conditional(分解條件表示式)
- 使用者類中承擔了不屬於它的職責,包括:收費規則、積分規則。這些職責應該是屬於電影型別的。
- statement列印賬單函式承擔了很多功能,包括收費計算,積分計算以及結果展示等等
- 整理清楚其中的業務邏輯,比如收費規則和積分規則 - 見故事場景
- 不要直接訪問物件的資料。容易發生其他物件改變該物件的資料,而擁有該資料的物件卻一無所知。
- 解法:8.10 Encapsulate Field(封裝欄位手法) —— 使資料和行為想分離
- 重構不應該被外界所感知,保證testcases依然可行
部分重構
這裡為了更好的展示重構的手法,使用TS,根據上面的討論進行了部分重構,重構的方式其實是根據業務未來的擴充套件方向而定,並沒有最優解,有興趣的可以加入我們,丟擲你的見解~
- CODEPEN 執行結果:
- 重構後的類圖關係
基本技巧
- 小步前進,頻繁測試(保證足夠的測試來支援你的重構行動)
- 使用智慧開發工具(比如VSCode右鍵可以將過長的函式程式碼拆解函式化)
推薦書籍
重構其實是一件需要長期投入,並且投入產出比很高的事情。對重構感興趣的同學可以關注專欄或者傳送簡歷至'tao.qit####alibaba-inc.com'.replace('####', '@'),歡迎有志之士加入~