作者:三省吾身丶丶
鏈接:https://zhuanlan.zhihu.com/p/99246269
幾個業務場景中的重構示例
請求順序依賴
在這種場景中,首先還是業務的復雜度決定了代碼的復雜度,首先我們來看一個在前端和node都有可能出現的一個簡單的例子:
我們有 A, B, C, D 四個請求獲取資料的函式(函式自己實作), C 依賴 B 的結果,D 依賴 ABC 的結果,最終輸出 D 的結果,
錯誤示例

雖然這個代碼是故意寫成這樣的,不過確實也有在一些初學者身上看到過,這份代碼還是能正確給出結果的,但是寫法丑陋,回呼地獄,如果后來人不進行重構,還有請求依賴,得繼續回呼嵌套,性能太差,沒有考慮 A 和 B 實際上是可以并發的,
這里介紹了一下最原始的 callback ... 中間大家可以去回顧一下 整個 ES2015+ ,callback (async.js) --> Promise --> generator + co --> async + await 的進化程序,其實是從原生的語法層面不斷去簡化和增強我們對于異步的控制能力,
下面直接給目前階段原生提供的終極方案:基于 Promise + async/await
正確示例

我們重新思考了一下上面的問題,理清楚了邏輯順序的依賴,并且用最新的語法,
使用 Promise.all 結合 async/await 的形式,考慮了并發和串行,寫法簡潔,達到了在示例要求下的最快方案,解決了無限嵌套的問題,這是跟隨語言進化本身帶給我們可以進行的優化,
但又不僅僅如此,我們將問題進行歸類 將 B,C 有依賴順序的請求,抽離出單獨的函式,讓他們去處理自身的邏輯,這個點我們稍后再提,
折磨人的 if else
可能存在下面一些問題
- 過多的嵌套
- 邏輯處理冗余
- 沒有做好防御編程(錯誤處理
直接來一個代碼例子,這是一個獲取背景顏色的方法,但是隨著業務的不斷變化,背景顏色的來源越來越多,在一些業務人員的處理下可能是這樣的:
錯誤示例

相信你在讀上面的代碼的時候是極為痛苦的,想要一目了然的知道最侄訓進入哪個分支,基本不可能,于是基于下面兩個原則
- 合理的抽取成函式
- 錯誤優先回傳
有了一個基礎版本的重構:
正確示例

可以看到整個邏輯,經過了重新梳理,拆分成了三個函式,子方法分別去處理對應層級的邏輯,由一個主方法負責調度,整體都變得一目了然了,
當然,在我們基于上面的原則進行重構之后,這個代碼有沒有問題呢?當然有,可以看到我們這三個函式,都依賴了全域變數,函式本身就不純了,如果是全域的問題,還是不易于排查,
我們可以將其修改為純函式,讓這一份代碼易于理解和測驗,
以一個函式的修改為示例:我們將 全域變數變成了引數,只需要在呼叫的時候,將全域變數傳入即可,但是這樣,我們得到了一個純函式,

為什么會在這里特別強調這個點呢,其實在函式式編程中的一個最基礎的問題那就是純函式,只有這樣輸入輸出才是可被觀測的,一個輸入一定會有一個輸出,也只有通過這樣的方式,才能讓系統中非純的函式越來越少,讓代碼變得更易于測驗,
當然作為我們如果以重構的角度去思考的話,我們還需要關注到這個點:

這里的邏輯會將會 最后一個被匹配到的資料,設定為 bgColor ,(我們都知道 find indexOf 等基本都是從前匹配,)是否真的是業務的需求呢?
可以看到將業務代碼寫好/重構的程序中其實也是對業務邏輯和業務理解的再一次提升,不論是抽取成函式還是錯誤優先回傳的設計,這其實也都是可以解決這樣一個問題:能在不去讀懂全域的情況下,了解某一個區域的細節邏輯,也就做到了讓代碼易于理解和修改,
... 這里的代碼即便是經過這樣的重構后,依然有可以考慮進一步優化的空間,比如函式與引數的命名,完整的測驗用例等等,受限于文章篇幅,暫不展開說明,
一些代碼中可能存在的其他問題
-
邏輯耦合在視圖層,
a === 'a' && b ==='b' && c==='c' && d ==='d'? <div>...</div>:null -
組件復用,函式復用,不封裝,代碼重復,
-
函式功能不單一,一個函式處理太多職責,且這些職責沒有任何關聯,但是都耦合在同一個區塊內,
-
引數串列混亂,有做好防御編程,不處理錯誤(介面錯誤,超時,重復提交等等
-
魔法數字,魔法字串,且沒說明,
-
糟糕資料結構 / 糟糕命名 (其實上面的具體代碼示例也存在)
關于優化代碼的思想準備
首先來說一下為什么會說需要優化代碼?
- 技術追求,
- 公司要求,線上有系統在用,有用戶在用,不寫好出問題實際上苦的還是自己,
- 團隊協作,我不好好寫,團隊成員其他人也不好好寫,惡性回圈苦的還是自己,
- 快速迭代,系統需要不斷的增加新功能,必須要寫好代碼才能做到,
- 其他人的看法,怕別人覺得自己技術能力差... xxxx....
那么就會有下面這些要求:
- 易于理解系統的架構
- 易于理解系統的生命周期與執行流程
- 易于理解每一個函式的作用
- 易于理解函式之間是如何呼叫與傳遞的(輸入輸出)
- 易于理解變數的含義,運算式的含義,
- 易于擴展...
最終實際上又回到了寫出來的代碼應該是 整潔的代碼,要使代碼易于理解/修改/測驗,(這里其實大部分時候,都隱含了一個人員協作的條件在里面,所以,既要寫好代碼,又不能過度封裝,讓團隊其他成員看不懂(當然如果確實有些人經驗不夠,那么是他自身的問題,需要他自己去加強,))
一些建議
- 更加清晰的去了解業務,去思考可能的變化,思考和設計清楚再動手,
- 看一些開源專案與業界最佳實踐,明白什么樣的是好代碼,什么樣的是不好的代碼,
- 建立明白代碼雖然是給計算機運行的,但最侄訓是人看的,不僅僅是沒有 bug 就行了,這樣的心智模型,
- 建立業務與代碼質量同等重要的思考模型,避免因為時間導致的不得不這么寫的代碼,
- 明白 code review 本身可能能發現和指出來一些問題,但最終的落實還的靠自己,不能變成形式,而是需要融合成自身的思考,
- 使用錯誤優先原則,盡可能的讓出錯的先回傳, 這樣后面就會得到干凈的代碼,(寫代碼的時候,不僅僅正向,反向的判斷也需要思考)
- 合理的拆分成獨立的函式,明確輸入輸出,錯誤處理等在函式內部的處理,(比如在一些場景中確實會存在大量邏輯判斷,首先就要思考在判斷內部的陳述句是否能被歸類與拆分出去)
- 對于多種狀態的判斷與組合,可以使用 組合狀態表 (map表)狀態機等模式
- 學習設計模式與重構等相關知識,
- 重構!!只要你覺得這個地方有問題了,那就不要等到以后,以后往往就是再也不,
結束
說到這可能會有一種戛然而止的感覺,在這一篇文章里面,我們首先以兩個優化代碼的具體實體為引子,讓大家明白了一些業務代碼的優化思路,在之后從列舉了一些其他可能出現的錯誤,以及是優化代碼的思想準備和理論指導,
其實都是希望大家能夠在業務中去發現問題,再去思考如何解決問題,因為說了那么多,到底能不把代碼寫好,還是得靠自己,
近期熱文推薦:
1.1,000+ 道 Java面試題及答案整理(2021最新版)
2.別在再滿屏的 if/ else 了,試試策略模式,真香!!
3.臥槽!Java 中的 xx ≠ null 是什么新語法?
4.Spring Boot 2.5 重磅發布,黑暗模式太炸了!
5.《Java開發手冊(嵩山版)》最新發布,速速下載!
覺得不錯,別忘了隨手點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/349480.html
標籤:Java
