自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

高德APP全鏈路源碼依賴分析工程

移動(dòng)開(kāi)發(fā)
高德 App 經(jīng)過(guò)多年的發(fā)展,其代碼量已達(dá)到數(shù)百萬(wàn)行級(jí)別,支撐了高德地圖復(fù)雜的業(yè)務(wù)功能。但與此同時(shí),隨著團(tuán)隊(duì)的擴(kuò)張和業(yè)務(wù)的復(fù)雜化,越來(lái)越碎片化的代碼以及代碼之間復(fù)雜的依賴關(guān)系帶來(lái)諸多維護(hù)性問(wèn)題,這些問(wèn)題已經(jīng)達(dá)到了我們必須開(kāi)始治理的程度了,而解決此類問(wèn)題的關(guān)鍵在于需要了解代碼間的依賴關(guān)系。

一、背景

高德 App 經(jīng)過(guò)多年的發(fā)展,其代碼量已達(dá)到數(shù)百萬(wàn)行級(jí)別,支撐了高德地圖復(fù)雜的業(yè)務(wù)功能。但與此同時(shí),隨著團(tuán)隊(duì)的擴(kuò)張和業(yè)務(wù)的復(fù)雜化,越來(lái)越碎片化的代碼以及代碼之間復(fù)雜的依賴關(guān)系帶來(lái)諸多維護(hù)性問(wèn)題,較為突出的問(wèn)題包括:

  • 不敢輕易修改或下線對(duì)外暴露的接口或組件,因?yàn)椴恢烙惺裁吹胤綄?duì)自己有依賴、會(huì)受到影響,于是代碼變得臃腫,包大小也變得越來(lái)越大;
  • 模塊在沒(méi)有變動(dòng)的情況下,發(fā)布到新版本的客戶端時(shí),需要全量回歸測(cè)試整個(gè)功能,因?yàn)椴恢浪蕾嚨哪K是否有變動(dòng);
  • 難以判斷 Native 從業(yè)務(wù)實(shí)現(xiàn)轉(zhuǎn)變?yōu)榈讓又蔚内厔?shì)是否合理,治理是否有效;

這些問(wèn)題已經(jīng)達(dá)到了我們必須開(kāi)始治理的程度了,而解決此類問(wèn)題的關(guān)鍵在于需要了解代碼間的依賴關(guān)系。

二、高德 APP 平臺(tái)架構(gòu)

為了消除一些疑惑,在討論依賴分析的實(shí)現(xiàn)前,先簡(jiǎn)單說(shuō)明一下高德 APP 的平臺(tái)架構(gòu),以便對(duì)一些名詞和場(chǎng)景有一些背景了解。

高德APP全鏈路源碼依賴分析工程

高德 APP 從語(yǔ)言平臺(tái)上可以分為 4 個(gè)部分,JS 層主要負(fù)責(zé)業(yè)務(wù)邏輯和 UI 框架;中間有 C++層做高性能渲染(主要是地圖渲染),同時(shí)實(shí)現(xiàn)了一些切面 API,這樣可以在雙端只維護(hù)一套邏輯了;Android 和 iOS 層主要作為適配層,做一些操作系統(tǒng)接口的對(duì)接和雙端差異化的(盡可能)抹平。

這里的切面是指 JS 層與 Native/C++ 層的分界線,這里會(huì)實(shí)現(xiàn)一些切面 API,也就是 JS 層與 Native/C++ 層交互的一系列接口,如藍(lán)牙接口、系統(tǒng)信息接口等,由 Native/C++ 層來(lái)實(shí)現(xiàn)接口,然后往 JS 層暴露,由 JS 層調(diào)用。

三、基礎(chǔ)實(shí)現(xiàn)原理

整個(gè)項(xiàng)目最基本也是最重要的數(shù)據(jù)就是依賴關(guān)系。所謂依賴關(guān)系,最簡(jiǎn)單的例子就是文件 A 依賴文件 B 的某個(gè)方法。

要將這個(gè)關(guān)系查出來(lái),一般來(lái)說(shuō)需要經(jīng)過(guò)兩個(gè)步驟。

第一步:編譯源碼,獲得 AST

遍歷所有源碼,通過(guò)語(yǔ)法分析,生成抽象語(yǔ)法樹(Abstract Syntax Tree, AST)。以 JS 掃描器為例,我采用了 typeScript 模塊作為編譯器,它同時(shí)支持 JS(X)、TS(X),通過(guò) ts.createSourceFile 來(lái)生成 AST。除 JS 外,iOS 采用的是 CLang,Android 采用的是字節(jié)碼分析,C++ 采用的是符號(hào)表分析。

第二步:路徑提取,依賴尋路

從 AST 上我們可以找到所有的引用和暴露表達(dá)式,以 JS 為例就是 import/ require 和 export/ module.exports。尋找表達(dá)式的方法就是遞歸地遍歷所有語(yǔ)法節(jié)點(diǎn),在 JS 中我采用了 TypeScript 編譯器提供的 ts.forEachChild 來(lái)進(jìn)行遍歷,通過(guò) ts.SyntaxKind 進(jìn)行語(yǔ)法節(jié)點(diǎn)類型的識(shí)別。

找到表達(dá)式后,通過(guò)依賴路徑找到具體的依賴文件。以 JS 為例,我們可以通過(guò) const { identifierName } = require('@bundleName/fileName') 的方式引用其它模塊(bundleName)的某個(gè)文件(fileName)的某些標(biāo)識(shí)符(identifierName),我們就需要根據(jù)這表達(dá)式來(lái)定位到具體的標(biāo)識(shí)符。

跨切面的依賴會(huì)需要多做一步,需要將切面 API 分為調(diào)用側(cè)和聲明側(cè),在 JS 層通過(guò) AST 分析出調(diào)用側(cè)數(shù)據(jù),在 Native/C++ 層分析出聲明側(cè)數(shù)據(jù)(對(duì)應(yīng)到具體實(shí)現(xiàn)切面 API 的標(biāo)識(shí)符),將調(diào)用側(cè)和聲明側(cè)數(shù)據(jù)通過(guò)版本號(hào)關(guān)聯(lián)到一起,即可實(shí)現(xiàn)全依賴鏈路貫通。

我們把這個(gè)關(guān)系以及一些元數(shù)據(jù)保存下來(lái),就可以作為源數(shù)據(jù)來(lái)作數(shù)據(jù)分析了。

四、項(xiàng)目架構(gòu)

整體項(xiàng)目架構(gòu)如下:

高德APP全鏈路源碼依賴分析工程

我們使用 Node.js 和集團(tuán)的 egg.js 框架搭建了本依賴分析工程服務(wù),并且考慮到數(shù)據(jù)使用場(chǎng)景的多變性和多樣性,我選用了 GraphQL 作為查詢接口,輸出我們定義的數(shù)據(jù)類型,由上層應(yīng)用自行封裝,如果出現(xiàn)多個(gè)上層應(yīng)用同時(shí)需要類似的數(shù)據(jù),我們也會(huì)進(jìn)行整合復(fù)用。

其中數(shù)據(jù)加工模塊是獨(dú)立模塊,由 Node.js 編寫,支持其它項(xiàng)目復(fù)用,未來(lái)會(huì)計(jì)劃在 IDE 等項(xiàng)目復(fù)用。

左側(cè)是我們的數(shù)據(jù)消費(fèi)方,這里只列舉了幾個(gè);右側(cè)是我們的數(shù)據(jù)庫(kù),用于儲(chǔ)存分析結(jié)果;下側(cè)是四端掃描器和觸發(fā)器,四端分別對(duì)自己平臺(tái)的源碼進(jìn)行源數(shù)據(jù)生產(chǎn),觸發(fā)器支持發(fā)布流程觸發(fā)事件觸發(fā)、定時(shí)觸發(fā)、前端觸發(fā)(應(yīng)用側(cè)前端,不是 Web 前端)和人工觸發(fā)等。

五、應(yīng)用場(chǎng)景及實(shí)現(xiàn)原理

全鏈路依賴關(guān)系的使用場(chǎng)景有無(wú)窮的想象力,這里挑幾個(gè)來(lái)舉例。

影響范圍判斷(逆向依賴分析)

第一個(gè)我們能想到的應(yīng)用場(chǎng)景就是影響范圍判斷,這也是我們這個(gè)項(xiàng)目的第一個(gè)抓手。大家都能想到,如果維護(hù)一個(gè)接口(或組件),我們會(huì)發(fā)現(xiàn)當(dāng)越來(lái)越多地方用的時(shí)候,迭代它的風(fēng)險(xiǎn)會(huì)隨之而越來(lái)越高,我們需要明確地知道到底有哪些地方調(diào)用了這個(gè)接口,以確定到底要回歸測(cè)試多少功能、要怎么做發(fā)布、怎么做兼容等。而這就需要進(jìn)行逆向依賴分析了。

逆向依賴是相對(duì)掃描器中分析出來(lái)的依賴關(guān)系的,掃描器分析出來(lái)的我們稱之為正向依賴,它主要表示「此模塊依賴了哪些別的模塊」;而逆向依賴則指的是「此模塊被哪些模塊依賴了」。所以很自然地,我們的逆向依賴就是基于正向依賴關(guān)系做的數(shù)據(jù)加工。

 

高德APP全鏈路源碼依賴分析工程

(逆向依賴查詢頁(yè)面)

 

基于逆向依賴數(shù)據(jù),結(jié)合多個(gè)版本的數(shù)據(jù),我們還能算出「連續(xù)未被引用的版本數(shù)」,以衡量下線接口的安全性。

 

高德APP全鏈路源碼依賴分析工程

(一些切面 API 的連續(xù)未被使用的版本數(shù))

 

組件庫(kù)、框架和切面 API 的維護(hù)者是這個(gè)能力的重度用戶,這個(gè)能力為他們帶來(lái)了數(shù)據(jù)支撐,明確了自己的修改將會(huì)影響多少的其它模塊,從而進(jìn)行變更、發(fā)布決策和回歸測(cè)試。

版本間變動(dòng)分析

版本提測(cè)時(shí),我們可以對(duì)兩個(gè)版本進(jìn)行依賴鏈比對(duì),分析出文件的變動(dòng)及其整個(gè)影響鏈路,為 QA 提供一些數(shù)據(jù)支持,能更精確地知道有哪些功能要進(jìn)行回歸測(cè)試,有哪些不需要。

版本間變動(dòng)分析有很多場(chǎng)景,除了正常的版本迭代的場(chǎng)景之外,還有一個(gè)常見(jiàn)的場(chǎng)景:模塊在未變動(dòng)的情況下被集成到新版本的高德 APP 中,那就會(huì)出現(xiàn)「發(fā)布代碼不變,而所依賴的其它模塊有變動(dòng)」的情況,尤其有是 Native/C++ 和公用模塊。測(cè)試環(huán)境需要知道的是,當(dāng)前模塊所依賴的其它模塊到底有哪些變動(dòng)、這些變動(dòng)對(duì)此模塊的影響是什么、需要回歸測(cè)試哪些功能點(diǎn)等。

這個(gè)數(shù)據(jù)的主要消費(fèi)方是 QA 同學(xué),他們利用這個(gè)數(shù)據(jù)可以提高測(cè)試效率,也能發(fā)現(xiàn)漏考慮的回歸點(diǎn)。

趨勢(shì)變化判斷

前面也提到過(guò),由于高德 APP 時(shí)間跨度很大,以及之前未進(jìn)行限制,所以我們有部分業(yè)務(wù)邏輯代碼仍然是通過(guò) Native 來(lái)實(shí)現(xiàn)的,我們希望逐漸遷移到 JS 或 C++ 層實(shí)現(xiàn),Native 僅作適配。

而要判斷這個(gè)治理的進(jìn)度和效果,需要從兩個(gè)方面的數(shù)據(jù)來(lái)支撐,一是各平臺(tái)代碼行數(shù),這個(gè)我們另有專門的服務(wù)做,暫且不提;二是接口趨勢(shì)。接口趨勢(shì)也分為調(diào)用側(cè)和聲明側(cè)兩種,按照我們治理的方向,我們期望的效果應(yīng)該是:一條 Native 業(yè)務(wù)切面 API 的調(diào)用量按版本/時(shí)間不斷減少的曲線,當(dāng)一些 API 的調(diào)用量為 0 后就可以把 API 下線掉,這樣就會(huì)隨之出現(xiàn)另一條曲線——Native 業(yè)務(wù)切面 API 的聲明量也不斷減少。

 

高德APP全鏈路源碼依賴分析工程

(從某版本開(kāi)始就不斷減少調(diào)用的切面 API)

 

 

高德APP全鏈路源碼依賴分析工程

(某版本未被使用的切面 API)

 

進(jìn)行架構(gòu)治理、切面 API 治理的同學(xué)是這些數(shù)據(jù)的主要消費(fèi)方,有了這些數(shù)據(jù)他們就能確定架構(gòu)治理的趨勢(shì)是否合理、是否能下線某切面 API 等。

包大小優(yōu)化——無(wú)用、重復(fù)文件查找

我們也為包大小優(yōu)化作了貢獻(xiàn)。根據(jù)依賴關(guān)系數(shù)據(jù),我們可以找出一些沒(méi)有被引用或者內(nèi)容完全一樣(md5 值相同)的文件,這些文件也占用了不少體積。

我們利用依賴分析工程找出了上千張這樣的圖片,@1x @2x @3x 文件是重災(zāi)區(qū),有很多假裝自己是另一個(gè)清晰度的圖片被我們揪出來(lái)了(我們甚至因此推動(dòng)了設(shè)計(jì)師出圖標(biāo)準(zhǔn)化和增加了檢驗(yàn)工具)。

六、寫在最后

以上便是高德全鏈路依賴分析工程的基本概述,在具體的實(shí)現(xiàn)當(dāng)中,會(huì)有無(wú)數(shù)的細(xì)節(jié)需要處理,如各種歷史遺留問(wèn)題、多級(jí)版本處理產(chǎn)生指數(shù)級(jí)的代碼快照、變動(dòng)分析產(chǎn)生指數(shù)級(jí)的分析結(jié)果等,其中也涉及到不少編譯原理、數(shù)據(jù)結(jié)構(gòu)與算法(尤其是圖結(jié)構(gòu))等知識(shí),非??简?yàn)編程能力和權(quán)衡能力,以及最重要的——韌性。歡迎大家一起討論,一起迸發(fā)新的想法、新的場(chǎng)景!

責(zé)任編輯:未麗燕 來(lái)源: segmentfault.com
相關(guān)推薦

2023-01-30 22:34:44

Node.js前端

2022-08-07 21:59:57

高可用架構(gòu)

2024-01-05 00:29:36

全鏈路灰度發(fā)布云原生

2023-10-16 23:43:52

云原生可觀測(cè)性

2023-11-13 10:41:44

Spring微服務(wù)

2023-07-20 15:46:24

2025-03-11 14:16:09

2024-03-13 08:56:17

全鏈路壓力測(cè)試

2022-04-27 10:53:34

web優(yōu)化性能

2023-11-14 09:04:15

用戶節(jié)點(diǎn)不可用

2022-01-04 17:08:02

全鏈路觀測(cè)平臺(tái)

2022-07-22 07:59:17

日志方案

2024-12-16 13:34:35

2025-03-04 08:53:10

2023-10-30 07:25:37

數(shù)據(jù)湖數(shù)據(jù)處理

2018-07-03 15:56:59

騰訊

2022-08-31 22:25:53

微服務(wù)架構(gòu)DevOPs

2024-10-23 12:50:13

數(shù)據(jù)飛輪數(shù)字化

2018-07-12 09:59:39

microServicmockautoTest
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)