寫出可複用程式碼的基本思想與實踐
引言
在 “程式碼可複用性問題兼談團隊協作 ” 一文中,談到難以寫出可複用程式碼的一些不好的習慣和阻礙因素。本文講講寫出可複用程式碼的基本技巧和實踐。
程式碼可複用性,關鍵在於發現業務邏輯裡的通用性部分。同時,能夠發現業務邏輯裡的通用部分,並能提取出來,有助於做出更好的設計,提升研發效率。
基本思想
寫出可複用程式碼的基本思想,簡而言之,就是邏輯拆分。拆分粒度越細,可複用的可能性越高。通過拆分成一系列有層次的、細粒度的函式或方法,就能建立一個可複用的程式碼基礎。
拆分是戰術層面的事情。“戰略”層面,則需要對邏輯共性和差異的思考和提煉。通常包括兩層:
-
業務無關的技術性邏輯:“將通用性的技術邏輯與差異性的業務邏輯相分離 ”
-
業務核心能力抽象:可複用的業務基礎設施和領域元件。
程式設計技巧
泛型和函數語言程式設計是一對強大的組合,有助於寫出精煉、可複用的程式碼。 可閱: “一次程式碼重構的思考及探索 ”。
實踐
工具類
工具類是不依賴外部服務的“輸入-輸出”型函式。工具類最適合於做成可複用的,也容易寫單測。
比如:“構造與使用分離:命中內容高亮及合併的展示問題解決實現”
比如:“精練程式碼:一次Java函數語言程式設計的重構之旅 ” 重構得到的一系列 Util。
業務輔助類
業務輔助類是不依賴於外部服務的業務輔助工具類。這種類一般很小,能夠涵蓋很多業務點。而正是業務點的串聯,構成了主體業務邏輯。比如:
/** * 從 agentDetection 獲取可疑指令碼資訊 */ public static ScriptDTO getScript(AgentDetection agentDetection) { if (AgentDetectionHelper.isInadequateAgentDetection(agentDetection)) { return null; } List<ScriptDTO> scripts = agentDetection.getAgentDetectionDetail().getDetail().getScripts(); if (CollectionUtils.isNotEmpty(scripts)) { return scripts.get(0); } return null; }
業務元件類
業務小元件類,依賴外部服務,提供單一的功能。 這種一般粒度比較小。封裝成小元件類很適合業務複用。這種業務小元件通常散落在各種 service 的 private 方法裡,而導致難以複用。
@Component
public class HostInfoHelper {
private static final Logger LOG = LogUtils.getLogger(HostInfoHelper.class);
private final HostProviderClient hostProviderClient;
@Autowired
public HostInfoHelper(HostProviderClient hostProviderClient) {
this.hostProviderClient = hostProviderClient;
}
public HostDto getHost(String agentId) {
if (agentId == null) {
LOG.error("agentId is empty");
return null;
}
HostDto host = hostProviderClient.getHost(agentId);
if (null == host) {
LOG.warn("No host found by agentId: {}", agentId);
return null;
}
return host;
}
}
統一機制的封裝
比如 ssdeep 檢測。 webshell 和 可疑指令碼的 ssdeep 檢測的邏輯基本相同。都是一段演算法 + 樣本檢測快取庫 + 樣本檢測記憶體快取 。 可以封裝成統一的。公司原始碼,就不便公開了。
統一機制需要指明呼叫來源,方便在必要的時候做差異處理。統一機制封裝有點類似微服務提供的外部介面。
有一定工作經驗的人是能夠理解我指的是什麼。
制訂標準資料格式
比如很多檢測能力都要用到檔案上傳。程序執行可疑指令碼檢測需要先上傳檔案,webshell 檢測也需要先上傳檔案。如果我要封裝一個業務功能,那麼首先要封裝出這個業務功能所需資訊的標準資料格式。然後根據這個資料格式來構建業務功能。
/**
* 檔案上傳所需資訊
* 目前檔案上傳下載主要依賴檔案的兩個資訊:
* 1. md5
* 2. fpath: 對於容器來說,fpath 是容器在宿主機裡的路徑
*
* Created by qinshu on 2022/1/11
*/
@Getter
@Setter
@Builder
public class IdsFileUploadInfo {
/** 檔案MD5 */
private String md5;
/** 檔案 sha256 值,未來會用這個值 */
private String sha256;
/** 檔案路徑 */
private String fpath;
/** 業務來源,用於檔案上傳回調 */
private String app;
/** 作業系統平臺,不同平臺使用不同上傳指令碼 */
private int osType;
/** 上傳優先順序 */
private int priority;
/** 檔案儲存天數,可選 */
private int keepDays;
/** 主機ID, 可選 */
private String agentId;
/** 客戶ID,可選 */
private String comId;
/** 業務物件ID,用於查詢關聯業務表, 可選 */
private String bizId;
/** 檔案上傳後是否需要回調,一般是需要回調,更改任務表狀態 */
private boolean callback = Boolean.TRUE;
}
共享庫封裝
更大層面複用的就是共享庫封裝。比如入侵檢測流程,基本可以看成是一系列元件的執行。每一個元件都可以是可複用的。
小結
本文提煉了寫出可複用程式碼的一些基本技巧及實踐。 要寫出可複用的程式碼,基本思想是邏輯拆分。泛型和函數語言程式設計是一對強大的組合,有助於寫出精煉、可複用的程式碼。具體的工程技術手段有:
- 工具類
- 業務輔助類
- 業務小元件
- 統一機制封裝
- 制訂標準資料格式
- 共享庫。