透過Python指令碼支援OC程式碼重構實踐(二):資料項提供模組接入資料通路的程式碼生成

架構師修行手冊發表於2023-11-03

來源:百度Geek說
作者 | 劉俊啟

導讀 
introduction
在軟體開發中,經常會遇到一些程式碼問題,例如邏輯結構複雜、依賴關係混亂、程式碼冗餘、不易讀懂的命名等。這些問題可能導致程式碼的可維護性下降,增加維護成本,同時也會影響到開發效率。這時通常透過重構的方式對已有程式碼結構進行改進和最佳化。在重構的工作中,大部分的工作是人工的方式完成,是一個耗時且容易出錯的過程。對於研發人員來講,在不改變軟體的功能和行為的前提下,保證質量和效率完成對已有功能的重構,是一個極大的挑戰。本系列以Python實現自動化的工具,支援程式碼重構過程的實踐。

全文5529字,預計閱讀時間14分鐘。


在上一篇《透過Python指令碼支援OC程式碼重構實踐(一):模組呼叫關係分析》的內容中,重點介紹了使用Python實現模組呼叫關係的分析,並以.csv格式檔案輸出,匯入到excel中評估重構影響面及每個資料項重構方式,在重構編碼工作啟動前明確了具體的工作及重構之後的收益,這對於立項的人力投入的決策會起到很關鍵的作用,特別是當團隊資源稀缺時,把要做的事情講清楚是一件很重要的事情。

同時也在上篇內容中提到,技術層面先實現一個模組間資料項通訊的機制(本系列文章中以資料通路代指),支援資料項不需要公開,也可以被其它的元件中的模組讀寫。基於資料通路的實現,將XXXSetting模組接入資料通路,就可以解決因為XXXSetting模組中的資料項變更而帶來的介面不相容變更的問題,也會降低上層的依賴方元件二次的釋出次數,間接的提升XXXSetting模組資料項相關研發需求的研發效率。

在XXXSetting模組資料項接入到資料通路過程,以百為量級的資料項需要逐項的按照資料通路的標準進行重構,手工的重構方式成本高,出錯機率高,測試時需要逐項驗證成本高,我們使用的Python指令碼實現接入資料通路的這部分程式碼的生成,可精準的生成每一個資料項接入資料通路的程式碼段,實現了本次重構工作在測試及上線階段零Bug。

本篇的內容先簡單介紹資料通路的基礎功能,隨後再闡述如何利用Python編寫的自動化工具,XXXSetting模組作為資料項提供方整合到資料通中,程式碼自動的生成的實現思路。


GEEK TALK

01

資料通路技術實現與接入

基於本次配置資料項重構工作的目標和資料通路的複用,資料通路的實現目標為可支援不同模組接入,如圖-1所示,與資料通路相關的模組共為兩類。

透過Python指令碼支援OC程式碼重構實踐(二):資料項提供模組接入資料通路的程式碼生成

△圖-1


1.1 資料項互動模組定義及簡介

資料項按照供需關係,主要分為兩類,資料項提供模組和資料項使用模組。

1、資料項提供模組:資料的提供方(如本文中提到的XXXSetting),遵循系統中約定的資料讀寫協議,為系統提供互通的資料項支援。資料項與資料項提供模組是n:1的關係。資料通路支援多個資料項提供模組的接入,是 1:n 的關係。

2、資料項使用模組:資料的使用方(如上篇文章中的XXXLib中的模組),基於資料通路提供的能力,進行資料的讀寫呼叫,獲取及更新所依賴的資料項的值。資料通路與資料項使用模組是 1:n 的關係。

1.2 資料通路實現及模組簡介

資料通路的主體實現思路為,提供統一的介面,支援不同的資料項提供模組接入,在資料通路中管理接入資料項提供模組,當資料項使用模組需要讀寫資料時,根據資料通路提供的介面,進行資料項的資料同步。主要分為資料項提供模組介面層、資料項提供模組管理和資料項讀寫服務模組

1、資料項提供模組介面層:約定資料項提供方要實現的資料讀寫能力,只有按照該標準實現的模組,才可作為資料的提供模組接入。

2、資料項提供模組管理:管理系統中所有資料項提供模組,提供註冊的介面,資料項提供模組可呼叫註冊接入需要在資料通路中管理的資料項。同時在收到資料項讀寫請求時,對模組中所關聯的資料項的讀寫進行分發。

3、資料項讀寫服務模組:提供穩定的資料讀寫的能力,全域性可訪問,根據key查詢資料項提供模組,並呼叫資料項提供模組的介面實現資料項的讀寫。


GEEK TALK

02

資料提供方接入資料通路的實現

2.1 資料項接入資料通路的主要工作

1、資料提供模組接入資料通路:按照資料項提供模組介面層約定,實現資料項的讀寫,主要分兩步:

  • 資料通路註冊可讀寫的資料項的資訊,是一個陣列,陣列中存放的是每個資料項的Key,Key的命名規則為資料項提供模組類名_資料項名,這部分程式碼使用Python指令碼自動生成。

  • 資料項的讀寫,由資料項提供模組實現讀寫數的介面,根據key匹配資料項,之後再對該資料項進行讀寫 ,這部分程式碼也使用Python指令碼自動生成。

2、資料項使用模組接入資料通路:由原直接呼叫方式,改為透過資料通路間接呼叫的方式,詳細實現在下一篇內容介紹,敬請關注。

2.2 需要重構的資料項整理

在上一篇透過Python指令碼支援OC程式碼重構實踐(一):模組呼叫關係分析的內容中,3.1.2 提取的是變數型別和變數的名稱小節中,經過預處理後,可提取所有資料項的型別及資料項名稱。

同時結合上篇3.3.2 資料項的預分析統計輸出小節中,取資料項被多個元件使用的資料項,確定為本次需要重構的資料項。

將這兩部分資料進行交集的計算,得出來需要重構的資料項型別及資料項名稱全集,為資料項讀寫程式碼生成時使用。下面為資料集的示例。






// 資料項型別 資料項名稱;NSString value1;NSString value2;BOOL value3;...

2.3 資料項提供模組的資料項列表生成

資料通路本身不產生資料,只作資料讀寫的橋接。資料項提供模組接入到資料通路時,需要知知資料通路支援那些資料項的讀寫。

具體的實現為,透過資料項提供模組介面層的約定告知資料通路,由資料通路呼叫,返回資料項提供模組支援的資料項列表,資料項列表的資料結構為陣列,陣列中為每個資料項的key,key的生成格式為資料項提供模組類名_資料項名。Python的轉換程式碼如下:








# 原始碼行示例 NSString value1; 參考2.2小節中的程式碼matchObj = re.match(r"(.*)\s+(.*);", line, re.M|re.I)if matchObj:    # value = matchObj.group(2) -- value1    key = '         @\"' + className + '_' + matchObj.group(2) + '\",\n'    # key = '         @"className_value1",\n'      # key 按OC的寫法,每一行一個key,按NSArray的方式初始化多個key

2.4 資料項讀取程式碼生成

註冊了可透過資料通路讀寫的資料項,當資料通路需要讀寫該資料項時,資料項提供方按照標準實現資料項的讀寫。


2.4.1 資料項讀取程式碼示例

資料通路支援基本的資料型別的讀取,每一種資料型別對應的不同的讀取介面,資料提供方根據資料項的型別,實現不同型別資料讀取,同一種資料型別中,資料提供方根據key返回的對應的資料項值,目標生成的OC程式碼如下:





















// 資料項是 NSString型別- (NSString *)stringForKey:(NSString *)key {    if ([key isEqual:@"className_value1"]) {        return self.value1;    }// 如有多個資料項,自動也合到同一個函式    if ([key isEqual:@"className_value2"]) {        return self.value2;    }    return nil;}
// 資料項是 BOOL型別- (BOOL)boolForKey:(NSString *)key {    if ([key isEqual:@"className_value3"]) {        return self.value3;    }    return NO;}// 其它...


2.4.2 資料項讀取實現生成

因資料項的型別不同,需要使用不同的介面讀取,故在程式碼轉換時,會根據資料項的型別,將轉換後的程式碼行,分別的儲存在不同的資料變數中,每個資料變數會在初始化時,增加函式頭,在轉換結束後增加函式尾。

  • 函式頭示例,以資料項為NSString型別為例



# NSString 型別的資料讀介面,函式頭字串由變數儲存funName = '- (NSString *)stringForKey:(NSString *)key {'

  • 函式體示例,每個資料項均生成對應的程式碼,依次的儲存每個資料項的讀取












# 原始碼行示例 NSString value1; 參考2.2小節中的程式碼matchObj = re.match(r"(.*)\s+(.*);", line, re.M|re.I)if matchObj:    funbody = '    if ([key isEqual:@\"'    funbody += 'className_' + matchObj.group(2) + '\"]) {\n'    funbody += '        return self.' + matchObj.group(2) + ';\n'    funbody += '    }\n\n'    # funbody 為轉換之後的讀取某個資料項的部分程式碼,匹配key,之後再返回對應的值,增加一些空格及換行,程式碼按規範對齊    #    if ([key isEqual:@"className_value1"]) {    #        return self.value1;    #    }

  • 函式尾示例,以NSString型別為例,所有資料項轉換完成之後,再增加



funEnd = '    return nil;\n'funEnd += '}\n\n'

不同的資料型別依次轉換,所有資料項轉換完成之後,依次的組合成為一個檔案,檔案的內容可以直接copy到專案工程中,可直接的使用。

2.5 資料項更新

2.5.1 資料項更新程式碼示例

資料通路支援基本的資料型別的更新,每一種資料型別對應的不同的更新介面,資料提供方使用根據資料項的型別,實現不同型別資料更新,同一種資料型別中,資料提供方根據key更新的對應的資料項值,目標生成的OC程式碼如下:























// 資料項是 NSString型別- (void)updateString:(NSString *)value forKey:(NSString *)key {    if ([key isEqual:@"className_value1"]) {        self.value1 = value;        return;    }// 如有多個資料項,自動也合到同一個函式    if ([key isEqual:@"className_value2"]) {        self.value2 = value;        return;    }}
// 資料項是 BOOL型別- (void)updateBool:(BOOL)value forKey:(NSString *)key {    if ([key isEqual:@"className_value3"]) {        self.value3 = value;        return;    }}
// 其它...


2.5.2 資料項更新實現生成

因資料項的型別不同,需要使用不同的介面更新資料項,故在程式碼轉換時,會根據資料項的型別,將轉換後的程式碼行,分別的儲存在不同的資料變數中,每個資料變數會在初始化時,增加函式頭,在轉換結束後增加函式尾。

  • 函式頭示例



# NSString 型別的資料讀介面,函式頭字串由變數儲存funName = '- (void)updateString:(NSString *)value forKey:(NSString *)key {'

  • 函式體示例,每個資料項均生成對應的程式碼,依次的儲存每個資料項的讀取














# 原始碼行示例 NSString value1; 參考2.2小節中的程式碼matchObj = re.match(r"(.*)\s+(.*);", line, re.M|re.I)if matchObj:    funbody = '    if ([key isEqual:@\"'    funbody += 'className_' + matchObj.group(2) + '\"]) {\n'    funbody += '        self.' + matchObj.group(2) + ' = value;\n'    funbody += '        return;\n'    funbody += '    }\n\n'    # funbody 為轉換之後的更新某個資料項的部分程式碼,匹配key,之後再返回對應的值,增加一些空格及換行,程式碼按規範對齊    #    if ([key isEqual:@"className_value1"]) {    #        self.value1 = value;    #        return;    #    }

  • 函式尾示例,所有資料項轉換完成之後,再增加


funEnd += '}\n\n'


GEEK TALK

03

小結

本篇的內容,基於上一篇內容的分析結論,將被多個元件使用的資料項接入到資料通路的程式碼,使用Python指令碼自動生成的實踐。

因涉及到的資料項較多,需要在所有的資料項中選出需要重構的資料項,生成資料項key列表,並跟據資料項的型別,接入到不同型別的讀寫介面中。使用人工書寫程式碼的方式很難保證資料項接入到資料通路過程的質量,同時也很難驗證資料項遷移的完整性。

而使用Python指令碼實現工具支援資料項接入資料通路的程式碼生成,可以自動的、精準的生成每一個資料項接入資料通路的程式碼,可減少研發及測試人力的投入,間接的提升了研發效率。

下一篇我們將介紹如何透過Python指令碼支援資料項使用模組接入資料通路的適配,感興趣的同學,可以持續關注。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70027824/viewspace-2992695/,如需轉載,請註明出處,否則將追究法律責任。

相關文章