後端開發:如何寫出可靠的介面

lixiang9194發表於2019-04-01

畢業進入現在的公司已近一年,完整參與了部門新專案兩期的開發上線過程,作為一名後端開發,覺得最痛苦的是上線前和上線後的改 bug 階段,面對各種突如其來、莫名其妙的bug,頭昏腦漲、手忙腳亂、越改越懵,經常導致實驗式改 bug、改一個 bug 又出現倆 bug 的之類的慘劇,我就忍不住想,為什麼每次上線前都會有這麼多bug呢?

前幾天還讀到一篇豆瓣文章,沒有總結的就不是經驗,只是經歷。程式設計師也不能業務來了就寫程式碼,有bug了就改bug,這樣技術很難提升,也就難怪每次都會有那麼多bug了。有的開發人員工作多年,介面還是時不時500,前期忙著寫程式碼,後期忙著改bug,心累。

我從一期熟悉業務、框架,寫一寫邊緣介面,到二期負責一個小模組,嘗試資料庫、程式的設計,中間磕磕絆絆,昨天也順利上線,模模糊糊也感覺到了一些經驗,於是努力總結下,雖然簡單,也許能給自己和讀者一些啟發。(本文只針對初級水平,簡單的bug,不涉及高併發、海量資料等複雜問題)

辛辛苦苦寫的介面,自己測的時候好好的,怎麼別人一調就出錯了呢??(此處應有表情包,請自行腦補)當然可能是執行環境的問題,不過程式統一部署在伺服器上,這一般是架構師或者運維負責的工作,至於程式語言或者作業系統的問題,也通通不在今天考慮範圍內,今天,我們只考慮自己寫出的bug。

事實上,執行中的程式所涉及的,無非三樣:資源(cpu、記憶體等)+ 演算法(程式執行流程)+ 資料(使用者輸入、資料庫、第三方介面等)。通常我們認為資源是可靠的,出現bug主要是由於演算法的不可靠或者資料的異常。

更進一步,機器嚴格按照0/1執行指令,演算法上一次執行正常,為什麼這一次會失敗?本質上還是因為資料變了,而演算法沒能覆蓋此情況,因此,要想保證介面的穩定,主要從兩方面考慮:保證資料的可靠性、演算法的健壯性,而演算法的健壯性也就是考慮到資料的各種情況,兩者密不可分。

如前分析,資料的變化是介面bug最常見、本質的原因。而其中,使用者輸入又是資料變化最主要的原因。而程式必然要有使用者輸入,否則毫無意義。

程式設計界有句名言:永遠不要相信使用者輸入。你永遠不知道,使用者會在一個期待姓名的輸入框裡都輸入些什麼。不要因為前端做了過濾你就放心,一方面是使用者可能會使用爬蟲等手段直接訪問你的介面,另一方面,前端也是你的使用者,溝通也存在誤差,前端可能會使用錯誤的方式呼叫你的介面,而這種錯誤可能會更加隱蔽。

第一條建議:嚴格校驗使用者的輸入,包括格式、內容。

我知道很多人都懶得去逐條檢驗使用者輸入,覺得只要功能正常就ok了,但是,這經常會導致後期改bug時投入更多的經歷。經常測試提了bug,你查來查去,發現是前端傳錯了引數,或者沒有合理限制使用者輸入,當然你可以很剛,讓前端去改,但這個過程已經浪費了你大量的時間精力,還不如一開始自己做好檢驗,返回合適的錯誤訊息,會為你後期節省大量的精力。

對於PHP等動態語言,尤其如此,例如我們使用Laravel框架,我會在所有介面入口處,首先使用$request->validate()檢驗所有輸入資料的格式,如有必要,還會寫程式碼進一步校驗輸入內容,比如時間範圍、請求資料是否有效等等。

第二條建議:考慮使用者的騷操作,重複提交、延時提交

重複提交應該是大多數後端都能想到的情況,也就是介面的冪等性,有些資源只能操作一次,必須進行校驗,其實不僅是重複提交,還包括同一事件被兩人重複處理的情況。

而對於延時提交,其實是測試給我提bug後我才意識到的問題模式。例如我們通過get介面返回給使用者某種資源,使用者可以通過post介面回傳資源id並提交修改,由於是自己的get介面返回的,我們可能想著只驗證id合法就行了,看似形成嚴格閉環,但如果使用者停留在此頁面延時提交,則可能在此期間資源過期,或者資源已被他人修改,而改使用者也成功修改的bug。其實進一步思考,你會發現,這跟高併發情景下的資源失效有異曲同工之處。

第三條建議:檢驗資料庫、第三方介面的返回資料

除了使用者輸入,常見的資料來源還有資料庫、第三方介面。相對而言,這些資料介面會可靠的多,而且內容格式也更規範。不過為了介面的穩定性,最好也做一些檢驗。如常見的資料為空的情況,就要及時中止程式執行並丟擲合適的資訊。

對了,對於資料庫,我還遇到過bug,就是主從延遲導致的資料更新問題,由於經驗尚淺,這類問題不很擅長,就不再寫。

第四條建議:程式演算法儘可能覆蓋異常情況

這條實際上是對前三條的補充,有些不合法的使用者輸入你可以直接中止程式並返回錯誤資訊,但有些情況可能需要程式繼續執行,進行特殊處理,這些情況你在程式設計之初應該儘量考慮周全,後期bug會少很多,也更容易維護。

最後,再寫一點點關於關於介面效率、程式碼質量的思考。

1. 影響介面效率的主要是資料庫操作
以我有限的經歷來看,介面耗時長基本都是因為資料庫操作不合理,我們大多數的業務程式碼並不會有效能問題。我見過不少在for迴圈裡查詢資料庫的程式碼,一定要避免,我們可以先一次性取出所有資料,然後逐個去處理。例如我們會在框架層記錄所有資料庫操作,除錯介面時即可看到所有資料庫操作以及相應耗時,該合併的查詢要合併,該優化的耗時查詢相應去優化。

2. 合理使用Exception,日誌

這條主要針對php語言,由於歷史原因,我看到不少程式碼靠return中止程式並傳遞錯誤資訊,這樣在程式碼複雜、呼叫層次深了以後極難維護,遠沒有Exception機制直觀方便。還有,重要資訊一定要寫日誌,便於後期發現問題及除錯,也可用來自證清白。

3. 程式碼要合理劃分、抽象

不要複製貼上程式碼,重複的功能要獨立出來;設計時要合理考慮需求變更、擴充套件;寫小而專注的函式,不要把複雜功能一坨實現;這樣寫的程式碼才易於修改、測試以及擴充套件。這塊我做的也不好,上線後看自己的程式碼都是一坨一坨,難以維護,接下來還要多思考,多實踐。

祝大家寫的程式碼都沒有bug!

相關文章