01 先聊聊這個系統的歷史包袱
#我們的廣告引擎在這次重構前大概經歷了1年半時間的迭代,初期針對的是搜尋場景,業務單一,流程清晰。
#1、業務場景開始變得複雜,除了搜尋廣告,還需要支援資訊流推薦以及相似推薦場景。
2、廣告流量開始快速增加,除了滿足功能性需求,還需要兼顧好效能。
已經過梳理,整個引擎有大部分邏輯是可以公用的,因此我們定義了一個主體框架,同時將可擴展部分進行了抽象化。這樣,各個場景能夠根據自身業務的特殊性實現某些公共介面即可。另外,從效能角度考慮,我們犧牲了一些程式碼可讀性,把某些邏輯並行化了。
隨著業務的發展,搜尋場景開始進入快速迭代期,新增策略越來越多,我們的主體框架也是在這個時候逐漸變得不靈活。
#1、為了相容搜尋的特殊邏輯,我們需要在其他場景中增加各種if 判斷來繞過這些邏輯。
2、廣告策略越來越多,累計了幾十個,當框架失去清晰的結構後,有些策略的實現開始變得客製化,缺少層次化的劃分和可插拔式的抽象設計。
轉機出現在2019 年底,由於廣告業務的特殊性,流量開始自然走低,另外產品營運團隊將重心放在了第2 年的工作規劃上,因此給了我們非常好的窗口期來開始此次重構。
我們將工期定成了1 個月,最終只比預期晚上線了一天,雖然出現了兩個線上問題,但是在灰度期都及時發現修復了,並沒有造成線上事故。
02 重構前,我們做了哪些準備工作?
這次重構的程式碼量很大,3 萬多行,而且是廣告系統最核心的引擎部分。啟動前,我們能預期到以下這些困難:
1、業務端的阻力#:廣告是極為以業務為導向的,本次重構雖然能帶來長期研發效率的提升,但是沒法直接提升業務收益,而且開發週期不會太短,如何才能得到業務同學的支持?
▍讓所有人看到痛點
#前面提到:隨著業務迭代,我們廣告引擎的主體框架已經變得模糊不清,另外幾十個廣告策略散落在不同的業務場景中,配置凌亂。
針對這兩個痛點,我們提前1個月啟動了現有業務的梳理,走讀舊程式碼、同時翻閱先前的需求文檔,最終我們將不同場景的核心流程而廣告策略歸類成了一張清晰的表格。
正是這張表格,讓技術和產品第一次很清晰地看到了我們引擎部分的全貌,體會到了業務的複雜度以及當前技術上的瓶頸。
▍明確重構的目標與價值
讓所有人感受到痛點後,我們規劃了本次重構的兩個核心目標:
#1、主體框架的重建:將主流程模組化,重新定義上下層協議,確保介面清晰;各層級內部也需要做好抽象,具備良好的擴充性。
2、策略靈活可設定:將廣告策略依照業務意圖進行歸類抽象,策略的執行條件動態可配置,同時策略可任意插拔。
此外,我們將這兩個核心目標完成後可帶來的預期收益進行了細化:
1、技術效益:程式碼結構更清晰,更容易理解與維護;可擴展性增強,引擎的開發效率將進一步提升。
2、業務效益:策略能做到更細緻的配置與擴展,對業務支援更友善;研發提效後能進一步加快業務的迭代速度。
▍整體節奏的把控
整體節奏的把控也是非常重要的一環,能讓所有人對這件事情有一個時間上的預期。
首先,我們將工期定成了1 個月,一方面考慮了業務側可以接受的最大周期,技術上也希望速戰速決;另一方面,春節即將來臨,我們必須趕在公司封網前上線,同時預留出1-2週的buffer 以防意外情況發生。
03 執行過程中有哪些可分享的經驗?
1. 高品質的技術設計方案
這一點得益於日常的要求,針對開發週期超過3天的專案我們都會進行技術方案設計,本次重構當然也不例外。
框架部分的整體架構、模組之間的協定設計、以及策略的可擴展性設計是本次技術方案的重點,團隊前後討論了不下3次。
在大方案定稿後,團隊進一步對資料庫、介面欄位、快取結構、日誌埋點等公共部分進行了細化,因為涉及到多人協作開發,團隊約定以文件作為溝通介面,文件始終保持和程式碼同步。
2. 預重構出框架性程式碼
這一個PR 非常關鍵,是我們從技術方案落地到程式碼最重要的一步。我們把重構後的套件結構、模組劃分、各層之間的API定義、不同廣告策略的抽象進行了梳理,先忽略實現的細節。
這樣主體程式碼基本上成型,能很清楚地描繪出我們理想中的框架。然後,我們組織了多次集中程式碼審查,最終形成了統一意見。
這一步能很好地避免過早陷入實現細節,導致主體框架專注不夠、程式碼不穩固,後期再返工反而會拖累效率。
3. 頻繁溝通與成對程式碼Review 機制
進入到細節實作階段後,很重要的一點是:對現有邏輯的理解。引擎程式碼經過一年半的迭代,歷史上被很多人開發過,但這次只有 3 個同學參與重構。
整個過程中,我們遇到任何程式碼邏輯不明確的地方,都是反覆溝通和求證,不主觀猜想,這份謹慎其實很關鍵。
另外在程式碼審查上,我們按模組分配了對這塊業務比較熟悉的同學來負責,成對搭配,機制靈活。
4. 有效的測試方案
#重構未動,測試先行。這個原則是《重構》一書中重點強調的,也是我們這次技術方案討論的重點,我在這裡單獨拎出來詳細展開下。
首先,我們先事先約定好:不動任何舊程式碼,完全建立新的 package 進行重構。這樣方便比對重構前後的結果,同時進行線上灰階實驗。
測試方案上,以下4 點值得借鏡:
##1 、端對端測試:本次重構不涉及功能性的調整,因此外層API的行為是不會有任何變化的,這樣端到端的測試方法最為有效,這個是研發和QA測試最主要的手段。
2、冒煙測試:QA同學提供冒煙Case,由研發同學進行冒煙,研發提測前必須保證所有冒煙Case 執行通過。 這一點在大部分網路公司都不常見,但是對於大型專案絕對有效。
3、沙箱環境雙流程驗證:前面提到我們重構前後的程式碼都保留了,因此可以透過腳本抓取線上環境的入參作為case,然後用自動化的方式將API 的回傳欄位逐一比對。
4、線上環境灰階實驗:灰階對於重構非常重要,我們利用現有的ABTest平台,逐步放開灰階流量,從5% 、到10%、到30%、最後到100%,制定了很謹慎的放量節奏,然後透過日誌以及業務指標監控進行驗證。
寫在最後
#回顧整個重構的過程,總結成下面7個關鍵點:
7、小心求證,為每行程式碼負責
當然,最關鍵的因素還是人,大型專案重構極為考驗團隊的協作能力,如果每個人都很可靠,重構就已經成功了一半。
以上是硬派乾貨:一個核心系統 3 萬多行程式碼的重建之旅的詳細內容。更多資訊請關注PHP中文網其他相關文章!