背景:
持續快速交付線上版本並且保證品質、效能始終處於優良的狀態,是技術研發、專案管理團隊的永恆追求。隨著移動開發技術的成熟,產業競爭的加劇,各大頭部App逐步平臺化、容器化,承擔著各自公司業務主要入口的使命。這不可避免地導致其本身逐步巨型化,與早期移動應用相比,複雜度明顯上升。
除此之外,快速的迭代開發節奏,複雜的使用者環境(網路、裝置、場景等)、多樣的應用框架,這些都給移動端的開發和管理帶來了巨大的挑戰。事實上,傳統的軟體危機在移動開發上也有一定程度的體現。
在上述背景下,本文從移動端面臨的品質和效率的挑戰出發,結合愛奇藝App的具體情況,介紹了愛奇藝技術團隊對這個問題的思考與實踐。
業務規模大:業務模組多達幾十個,如何正確管理、隔離各模組之間的耦合、衝突,避免錯誤和故障的擴散蔓延,是一個不小的挑戰;開發人員規模大:上述模組很多分散歸屬於不同的開發團隊,且開發集成周期並不完全同步,這給整合釋出帶來了很大的複雜性;技術形態繁雜:由於業務的特點,各團隊/業務所選擇的技術棧不盡相同,Native,RN,H5,小程式,Flutter等多種形態並存;不同的跨端語言/技術並行,如JS、Lua、C/C++等,如何保證所有這些環境正確隔離,有序協作,需要考慮很多方面的問題;迭代速度快:目前愛奇藝App保持著雙週發版的節奏,後端前置開發,客戶端一週開發+一週測試,在這種快速的迭代週期下,保持App整體可維護性、可測試性等品質標準良好,對研發架構、流程、工具都提出了新的要求。從微觀上看,各業務模組自身也不同程度地面臨著技術複雜、需求變動頻繁、歷史沉澱追溯困難等挑戰,在快速迭代過程中大多數時候屬於行進過程中換輪子的狀態,其本身程式碼品質、功能品質也是一個需要持續關注的主題。
解決方案綜合上述各方面的因素,多種複雜性和不確定性的疊加給持續高品質交付帶來了巨大的挑戰。在這種情況下,單純簡單依賴測試人力覆蓋來進行品質保證,既不經濟,也不現實,無法持久保證產品的整體品質。
在調研了業界實踐情況並結合愛奇藝的實際情況,經過充分討論之後,我們確定了:自動化、規範化、主動化、系統化 的治理思路。具體來說,採取了下面一系列的措施:
首先,對於流程相對固定的UI業務場景,構造自動化測試;對於UI業務庫介面,均要求配套相應的單元測試case並自動化執行,將測試人員從繁瑣的重複工作中解放出來,聚焦於更復雜多變的場景;此外,在移動端引入了程式碼覆蓋率自動統計機制(支援真機/模擬器 覆蓋單次提交/整體App)。單次提交品質和測試覆蓋品質有了切實的資料評估,使得開發和測試對於改動的驗證有的放矢。
其次,考慮到自動化和人力測試只能發現已經引入的缺陷,並且成本很高,並希望將缺陷儘量扼殺在編碼和除錯階段,將成本降到最低。那麼,如何達到這個目標呢?首先觀念上大家要達成一致,經過討論,大家都認同“最終產品的品質,需要測試保證,更需要開發來保證“,觀念達成一致之後,還需要尋找有效的手段來達到最終目標。經過調研討論,認為日誌是一個很好的切入途徑,理由在於:
覆蓋面廣:統一的日誌系統能夠覆蓋所有模組,確保監控沒有死角;資訊詳實:日誌由開發人員新增,輸出該模組主要流程的關鍵節點,感興趣的上下文和內部狀態等內容,資訊量遠大於介面白盒測試,更不用說與黑盒測試比較了;能持久化:日誌資訊隨著模組程式碼一起迭代演化,沉澱下來。具體實施過程中,可以分期按優先順序逐步累積,其成果能持久化地利用;覆蓋全流程:日誌資訊覆蓋開發除錯->測試->內測->外測->線上釋出的全流程,能夠在各階段發揮其作用;方便工具化、自動化:開發統一的日誌SDK,統一日誌格式和規則,使日誌方便使用、更加工具化。如果同時開發相應的配套工具,就能夠在各階段將日誌的利用很大程度上自動化,提高效率,降低使用成本;綜合上述考量,團隊以日誌系統為核心構建了一套針對移動端的綜合診斷除錯系統。該系統通過對應用的開發、除錯、內測、釋出等各階段提供全面的工具支援,將各類問題,以規範化、流程化的形式儘量暴露在前期,且保證問題的完整處理過程的可追溯;在釋出後期,針對海量中特定使用者出現的特殊場景,提供全面的診斷定位資訊。此外,上傳的日誌、除錯資訊等入庫之後,會對其根據規範化的格式進行統一的大資料分析處理,並與智慧客服系統打通,形成上報、分析、監控、報表、智慧客服、確認修復的完整閉環,在提高開發除錯效率的同時,為整體品質保駕護航,整個系統可以用下面的示意圖表示:
日誌SDK日誌SDK整合在主App和獨立App中,為各模組中的關鍵節點提供日誌監控與跟蹤,目前已經覆蓋了主要模組。除了日誌分級、分片儲存等基本功能之外,日誌SDK還提供了不同的過濾策略、不同的儲存介質、不同的上報策略以及雲控遠端配置功能。為了防止日誌過度累積,支援儲存容量限制、過期自動清理等功能,日誌系統的結構如下圖:
支援日誌分級格式化後輸出到不同的目標,除了常規的console輸出、檔案儲存、服務端上傳之外,還支援定向輸出至日誌偵錯程式LogDebugger、Web檢視器等,方便開發和測試人員使用。
配套工具集日誌SDK只是為監控和診斷等功能提供了必要的途徑,為了將其充分利用起來,還需要開發配套的工具。這些工具按執行平臺可以分為: 客戶端、桌面端、Web端;按功能可以大體分為品質類和效率類兩大類:
日誌偵錯程式
平時使用日誌時遇到的一個常見的問題是,IDE的console除了業務方的日誌輸出外,還混雜著大量的系統日誌輸出、第三方庫的日誌輸出等,這些無關資訊會將有效資訊完全淹沒。篩選出感興趣的模組日誌主要靠關鍵詞搜尋,在不知道或者沒有統一關鍵詞的情況下,開發和測試人員很難對該模組的日誌輸出有全域性和直觀的了解。為了解決該問題,方便和鼓勵大家利用日誌診斷定位問題,我們開發了日誌偵錯程式,通過client-server的結構互相連線,支援本地除錯、交叉除錯、內網遠端除錯,統一日誌輸出管道,這有效避免了日誌資訊淹沒、無法有效提取的問題;同時還支援格式化顯示、按level、module、關鍵詞監控等功能。
啟動後,該工具會自動搜尋發現區域網內的客戶端,分別顯示客戶端App名稱、版本、裝置標識及連線狀態等資訊,並自動維護連線狀態,如下圖:
日誌偵錯程式支援對日誌分級別、分模組、分關鍵詞等進行監控的功能,使用者可以對按照指定條件篩選出的日誌進行匯出傳送。
Web檢視器為了方便相關人員在開發、除錯及內測階段能隨時有一種途徑獲取被除錯客戶端的日誌及內部狀態等資訊,開發了Web檢視器。Web檢視器支援檢視實時/非實時日誌,檢視指定模組除錯資訊等,如下圖是實時檢視日誌的場景:
為了進一步提高除錯效率以及應對復現機會稀少、甚至偵錯程式本身可能會對被除錯物件產生干擾(詳見海森伯效應、Heisenbug)等場景,我們借鑑嵌入式開發的除錯方法構造了一套主動診斷除錯機制,其特點在於:
化被動為主動:單純的日誌輸出與分析,還是相對被動,希望模組級別能支援一定的主動除錯功能,特別是對於內部複雜的強狀態模組/業務;非接觸式,甚至是在遠端除錯,覆蓋開發、測試、釋出階段:具體來說,在開發和內測階段,提供遠端命令通道,開發人員可以通過shell對App進行互動式除錯,如更精準地拉取日誌、精準地獲取該客戶端A/B測試狀態、相關配置資訊等,同時還可以執行各模組自定義的除錯指令,以獲取其特定的除錯資訊;釋出階段,通過push token通道下發主動除錯指令,獲取客戶端內部狀態資訊,方便更精準定位問題,為修復bug和改善體驗提供資料。框架可擴充套件:具體來說,框架實現最常用的基礎除錯指令,業務方可以根據其具體情況定義自己的擴充套件除錯指令;可除錯的設計上一節中提到了模組的主動除錯機制,為什麼要引入主動除錯?其背景在於高複雜度的軟體產品和快速的迭代節奏給可靠的測試和除錯帶來了巨大的困難,化解這些難題的一種做法是在設計和開發階段,規劃好除錯功能,未雨綢繆,化被動為主動,這就是Design for Debug的思想,該思想最初來源於積體電路開發領域,後來被引入軟體領域並逐步得到重視。
其實,寬泛一些來講,在移動開發中,大到整個App、小到某個模組、某個介面等都應該在一定程度上考慮到可除錯設計。當然這是一個非常大的主題,我們目前實現的模組主動除錯功能只是初步在模組層面實踐了其思想,還需要進一步探索。
總結日誌系統貫通開發、除錯、測試、釋出的全流程,是提高效率和品質的一個很好的抓手,本文介紹了愛奇藝技術團隊以其為核心構建的綜合診斷除錯系統及配套的相關工具。
此外還介紹了正在探索的主動診斷/除錯功能的原理,更進一步地談到了關於可除錯設計的思想,這個最初源於積體電路領域的概念,在軟體模組越來越複雜的今天,對我們有一定的啟發。當然關於可除錯設計,我們目前還處於早期探索階段,歡迎與業界朋友們進一步交流討論。