畢業進入現在的公司已近一年,完整參與了部門新專案兩期的開發上線過程,作為一名後端開發,覺得最痛苦的是上線前和上線後的改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!
更多Laravel相關技術文章,請造訪Laravel教學專欄進行學習!
以上是後端開發:如何寫出可靠的接口的詳細內容。更多資訊請關注PHP中文網其他相關文章!