工作半年的思考

C_nullptr發表於2021-01-11

記錄一下工作半年之後發現的現象和對應的思考。

  • 專案最終一定會成為“屎山”
  • 百分之八十的程式碼是特殊或異常情況處理
  • 引數校驗是一把雙刃劍

專案最終一定會成為“屎山“

大學畢業之前就知道程式設計師最頭疼的事是維護老專案,尤其是程式碼質量很差的”屎山”。很幸運的是,工作後遇到的第一個專案就是維護一個屎山,這個專案是龐大複雜系統中的一個模組,由於大版本的更新迭代導致現有功能已無法使用,必須進行重新適配。更幸運的是,領導給了我極大的自由度和很長時間自由發揮。

剛接手時,整個專案真是一團亂麻,定義最主要業務邏輯的類檔案有四千行、其中還有一個九百多行的 run 函式,另外還有一半的類在迭代過程中已經不再使用但是沒有刪除。截止到第三輪系統測試、整個專案持續了兩個月,全程由我一個人完成,經歷了從日誌檔案和主要程式碼中倒推出業務邏輯狀態機、通讀所有原始碼刪除無用部分、調整混雜在一起的各層程式碼、優化程式碼等過程。下方兩張圖分別是剛接手是程式碼掃描結果和目前的程式碼掃描結果,可以看出來改進了很多。

和無法違背的熱力學第二定律一樣,我認為只要一個專案還有維護的價值、還在迭代中,它的程式碼質量就一定會越來越差。有以下兩個主要原因:

  • 有維護需要的專案,很可能會不斷的加入新的功能,而再有經驗的架構師在最初設計時也不可能考慮到所有的情況。從這個角度來說,設計上的缺陷是一定存在的,沒有人敢篤定自己的設計萬無一失,設計之初只能儘可能的提高設計質量。
  • 軟體開發團隊自身就是複雜的,每個人水平參差不齊、會有人離開有人加入,老員工寫下一段程式碼時經歷了什麼樣的思考和辯證,可能永遠也沒機會讓後來加入的新人瞭解。這種情況下,維護老專案的新員工就可能破壞原本清晰的程式碼結構。

百分之八十的程式碼是特殊或異常情況處理

理想情況下,使用者會用最主流的瀏覽器、把正確賬號密碼填在正確的位置然後登陸。實際情況中,使用者可能會用 IE 瀏覽器、可能會把使用者米密碼填反中,甚至訪問應用的都不是活生生的使用者。

於是,前端需要做表單驗證以驗證使用者的輸入,做多瀏覽器適配以方便使用者;而後端需要做入參校驗防止後臺程式被前端同事和爬蟲搞崩。下面是作為一個 Java 語言後端開發者對於一些可能的異常情況的總結。

  • Java 的基礎資料型別含有預設值,因此 DAO 類中的基本資料型別要使用包裝類,避免資料庫中相關值實際為 null,查詢結果卻為 0 的情況發生。
  • 除了考慮資料型別自身的範圍限制避免溢位的情況以外,在特定的業務場景中,資料型別的值可能含有特定範圍,例如用於計數時 int(或 long)不可能為複數等。
  • 字串型別的特殊值有 null 和空字串,很多情況下這兩個特殊值會觸發 Bug,但有些特殊情況時又是業務邏輯息息相關的,需要謹慎處理。
  • 字串中的轉義字元處理:前後端資料互動時,如果使用 JSON 格式需要對使用者輸入的 {}", 等特殊符號進行轉義;如果使用 XML 格式需要對使用者輸入的 <>"等特殊符號進行轉義。

引數校驗是一把雙刃劍

在維護前文提到的專案時,有一個後端介面查詢經常超時,導致前端總是彈出“連線超時“的彈窗警告。這是一個統計伺服器資源使用量的功能,前端呼叫介面查詢到結果後會將資料渲染為一個折線圖,展示過去一段時間內相關資源的佔用情況。經過分析,發現該介面呼叫最耗時的過程是和主控節點進行 MQ 通訊進行引數校驗。與產品經理溝通後認為這個介面具有呼叫頻繁入參固定需要快速返回的特點,而使用者使用時關心的是某一時間段的資源佔用的變化情況、非特定時間點的瞬時資料。後來解決方案是刪除了一大段的條件判斷,使用 try-catch 捕獲了一個通用異常,發生異常時直接返回上一次的統計結果。

由此可見,引數校驗也是一把雙刃劍,提高程式可靠性的代價就是執行效率變慢,很多時候需要根據實際情況在效能和安全性之間做出取捨。下面關於引數校驗的規範摘自《阿里巴巴 Java 開發手冊》。

【參考】下列情形,需要進行引數校驗:

  1. 呼叫頻次低的方法。
  2. 執行時間開銷很大的方法。此情形中,引數校驗時間幾乎可以忽略不計,但如果因為引數錯誤導致中間執行回退、或者錯誤,那得不償失。
  3. 需要極高穩定性和可用性的方法。
  4. 對外提供的開放介面,不管是RPC/API/HTTP介面。
  5. 敏感許可權入口。

【參考】下列情形,不需要進行引數校驗:

  1. 極有可能被迴圈呼叫的方法。但在方法說明裡必須註明外部引數檢查要求。
  2. 底層呼叫頻度比較高的方法。畢竟是像純淨水過濾的最後一道,引數錯誤不太可能到底層才會暴露問題。一般 DAO 層與 Service 層都在同一個應用中,部署在同一臺伺服器中,所以 DAO 的引數校驗,可以省略。
  3. 被宣告成private只會被自己程式碼所呼叫的方法,如果能夠確定呼叫方法的程式碼傳入引數已經做過檢查或者肯定不會有問題,此時可以不校驗引數。

相關文章