程式碼精簡執行過程
一、程式碼精簡背景
隨著業務需求的不斷增加和產品的逐步完善,我們應用對應的程式碼庫也在日益龐大,其中有用的、無用的、低頻使用的、灰度驗證的等各種型別的程式碼堆積在一起,給後續接手的同學增加了很多的維護和學習成本。有些程式碼邏輯缺乏文件說明,無人能看懂,更不敢隨意修改。當有新需求需要改動這些程式碼時,大多數選擇都是重新寫一套,老的程式碼還繼續保留,慢慢的系統中這種程式碼越來越多,程式碼工程也逐漸腐化起來,腐化到一定程度只能進行推倒重構。因此定期進行程式碼縮減,清理腐化的程式碼,對程式碼進行最佳化升級,提升程式碼工程的可維護性與可理解性,是十分有必要的。
我們後端的 java 程式碼工程一般和應用一一對應,根據應用的分層,程式碼工程也可以分為以下幾類:領域服務中心(領域服務)、業務聚合中心(業務系統)、多能力應用(前後端未分離、定時任務、訊息...)等種類。針對不同型別的程式碼庫,我們需要深入程式碼進行探查,掌握程式碼的腐化程度以及有效程式碼的佔比,判斷是進行程式碼縮減還是進行程式碼重構。如果進行程式碼縮減,哪些程式碼可以直接清理,哪些程式碼可以重用最佳化,識別過程是個需要花費精力去認真做的。
二、程式碼精簡步驟
三、程式碼精簡實施
1、靜態程式碼檢查
1)idea 自帶工具檢查
步驟 1:透過 idea 自帶的工具來檢查未使用的類、變數、方法。Preferences—>Analyze—>Inspections,執行:Run Inspection by Name
步驟 2:輸入:unused declaration(未使用的宣告)
步驟 3:輸入:unused import(未使用的引用)
步驟 4:重複程式碼檢查,專業版才能掃描,掃描之後,透過人工識別的方式,看是否能抽離公共方法
•使用 idea 自帶工具檢查的缺點如下:
◦spring 注入的引數值@value,會認為沒有賦值"Field is never assigned.",引數未被賦值,被檢測出來;
◦lombook 的@data註解物件,會認為"All constructor usages belong to the calls chain that has no members reachable from entry points",被檢測出來;
◦實體類中沒有初始化 new 過,會認為"Constructor is never used",建構函式沒有使用過,被檢測出來;
◦無效程式碼的誤判較多,識別需要要花費一定的時間;
◦重複程式碼檢查都能檢查出來,檢查到以後,都需要人工進行識別,進行抽象處理;
2)使用 PMD 外掛檢查
步驟 1:安裝外掛:IDEA 透過 File > Settings > Plugins > Marketplace
搜尋 “PMD
”,按照提示進行安裝,然後重啟即可
步驟 2:配置檢測規則:透過 File > Settings > Other Settings > PMD
可以開啟檢測規則的設定介面
執行 PMD:
使用預設的規則的話,比較多,我們關心的是哪些程式碼可以精簡,因此我們選擇自定義規則,定義 setting.xml 檔案,然後配置 PMD 檢查規則,選擇 setting.xml 檔案。
具體檔案內容如下:
<?xml version="1.0"?>
<ruleset name="myruleset"
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
<description>My ruleset</description>
<!-- 空的 catch 塊:發現空的 catch 塊沒做任何異常處理的事,在大多數情形下,這會吞噬一些應該被處理或報告的異常 -->
<rule ref="category/java/errorprone.xml/EmptyCatchBlock"/>
<!-- 空的 finally 塊:避免空的 finally 塊 - 這些是可以刪掉的 -->
<rule ref="category/java/errorprone.xml/EmptyFinallyBlock"/>
<!-- 空的 if 表示式:發現使用 if 進行了條件判斷,但是判斷之後沒做任何處理 -->
<rule ref="category/java/errorprone.xml/EmptyIfStmt"/>
<!-- 空的初始化塊:發現空的初始化塊 -->
<rule ref="category/java/errorprone.xml/EmptyInitializer"/>
<rule ref="category/java/errorprone.xml/EmptyStatementBlock"/>
<!-- 空的 switch 表示式:避免空的 switch 表示式 -->
<rule ref="category/java/errorprone.xml/EmptySwitchStatements"/>
<!-- 翻譯 空的 Synchronized 塊:避免空的 synchronized 塊 -->
<rule ref="category/java/errorprone.xml/EmptySynchronizedBlock"/>
<!-- 空的 try 塊:避免空的 try 塊 -->
<rule ref="category/java/errorprone.xml/EmptyTryBlock"/>
<!-- 空的 while 表示式:發現空的 while 表示式 -->
<rule ref="category/java/errorprone.xml/EmptyWhileStmt"/>
<!-- 未用的常規引數 -->
<!-- <rule ref="category/java/bestpractices.xml/UnusedFormalParameter"/>-->
<!-- 未用的本地變數 -->
<rule ref="category/java/bestpractices.xml/UnusedLocalVariable"/>
<!-- 未用的私有變數 -->
<rule ref="category/java/bestpractices.xml/UnusedPrivateField"/>
<!-- 未用的私有方法 -->
<rule ref="category/java/bestpractices.xml/UnusedPrivateMethod"/>
<!-- 不要引入java.lang:避免從’java.lang’包引入任何東西,它裡面的類是自動引入的 -->
<rule ref="category/java/codestyle.xml/DontImportJavaLang"/>
<!-- 避免重複引入 -->
<rule ref="category/java/codestyle.xml/DuplicateImports"/>
<!-- 未使用的imports:去掉不使用的import -->
<rule ref="category/java/bestpractices.xml/UnusedImports"/>
<!-- 從同一個包引入:不需要從同一包引入型別 -->
<rule ref="category/java/errorprone.xml/ImportFromSamePackage"/>
<!-- 太多的靜態引入:如果濫用靜態引入特性,會使你的程式不具有可讀性和可維護性,你引入的太多的靜態成員汙染 -->
<rule ref="category/java/codestyle.xml/TooManyStaticImports"/>
</ruleset>
檢測效果截圖:
步驟 3:重複程式碼檢查,下載 pmd 壓縮包,執行 cpdgui
•命令列執行:/Users/zhanglu7/Downloads/pmd-bin-6.39.0/bin/run.sh cpdgui
•選擇檢查的資料夾目錄,執行檢查,GO
使用 PMD 檢查工具缺點如下:
•缺少無引用的 public 方法檢查規則,目前都是私有方法的檢查,公有方法檢測規則需要自己實現,或者透過人工甄別的方式進行檢查;
•重複程式碼檢查需要額外使用 CPD,重複程式碼檢查都能檢查出來,檢查到以後,都需要人工進行識別,進行抽象處理;
3)靜態程式碼檢查結論
•建議使用 PMD 外掛 +CPD 的方式進行,靜態程式碼檢查,檢查包括:空邏輯控制程式碼塊,未用的本地\私有變數、未使用的私有方法,檢查出來的內容基本上都可以直接從程式碼庫中刪除。重複程式碼檢查,使用 CPD 檢查重複超過 ** 行的程式碼,檢查結果作為一個參考,幫助我們找到程式碼庫中疑似重複的程式碼,然後透過人工甄別,判斷該重複程式碼是否可以進一步抽象,抽象成公共的方法,供多處呼叫。
•test_code_reduce,demo 工程,程式碼行數 103 行,透過 pmd 檢查後,可刪除 10 行左右(包括未使用的私有方法、無效引用、未使用的本地變數),佔比 10% 左右。
•jdo-***,線上工程,程式碼行數 20005,透過 pmd 檢查後,可刪除 400 行左右(包括未使用的私有方法,未使用的私有變數、重複引入、無效引用、未使用的本地變數),佔比 2% 左右。透過 idea 掃描的重複程式碼,需要人工甄別,抽取出公共方法。另外需要人工檢查無用的 public 方法,以及類等,估計可以刪除 600 行左右,佔比 3%,可以完成整體縮減 5% 的目標。
2、動態程式碼檢查
1)京東 jacoco 流水線
步驟 1:配置流水線
步驟 2:行雲應用新增啟動引數
啟動前配置:
mkdir -p /export/home/jacoco
cd /export/home/jacoco && wget "http://storage.jd.local/bpp-quality-public/code_coverage_statistics/jacoco-0.8.7-20210115.151120-42.tar.gz"
tar -xzvf /export/home/jacoco/jacoco-0.8.7-20210115.151120-42.tar.gz
啟動配置:
ip=$(/sbin/ip a | grep "inet " |grep -v "169.254.95.120" |grep -v "127.0.0.1" | awk '{print $2}' | awk -F/ '{print $1}')
export JACOCO_AGENT="-javaagent:/export/home/jacoco/jacoco-0.8.7-20210115.151120-42/lib/jacocoagent.jar=includes=*,output=tcpserver,port=8840,address='${ip}' -Xverify:none"
export CATALINA_OPTS="${JACOCO_AGENT:-} ${CATALINA_OPTS}"
步驟 3:執行流水線
待執行一段時間後,再執行流水線,檢視動態程式碼覆蓋率
2)動態程式碼檢查結論
•建議使用京東 jacoco 流水線來進行動態程式碼檢查,但需要進行長時間的執行才能得到一個相對精準的程式碼執行記錄,該記錄也僅供參考,程式碼是否可以刪除,還需要人工進一步甄別。
相關文章
- 原始碼簡析Spring-Integration執行過程原始碼Spring
- Java 程式執行過程Java
- 精盡MyBatis原始碼分析 - SQL執行過程(一)之 ExecutorMyBatis原始碼SQL
- 精盡MyBatis原始碼分析 - SQL執行過程(二)之 StatementHandlerMyBatis原始碼SQL
- 精盡MyBatis原始碼分析 - SQL執行過程(三)之 ResultSetHandlerMyBatis原始碼SQL
- 一個簡單java程式的執行全過程Java
- crtmpserver 執行過程簡明分析Server
- 程式語言執行過程
- Spark程式碼在叢集上執行過程理解Spark
- 精盡MyBatis原始碼分析 - SQL執行過程(四)之延遲載入MyBatis原始碼SQL
- 原始碼簡析XXL-JOB的註冊和執行過程原始碼
- 原始碼分析OKHttp的執行過程原始碼HTTP
- 淺析Java程式的執行過程Java
- ELF PHP 可執行程式執行後載入重型指令碼的過程PHP行程指令碼
- 通過 HelloWorld 瞭解 Java 程式執行過程以及執行時記憶體Java記憶體
- 使用 ESLint + Prettier 簡化程式碼 Review 過程EsLintView
- jsp的執行過程JS
- 指令的執行過程
- [zebra原始碼]分片語句ShardPreparedStatement執行過程原始碼
- laravel 應用層執行過程原始碼分析Laravel原始碼
- 程式執行過程記憶體分析詳解記憶體
- 執行緒池建立執行緒的過程執行緒
- 走近原始碼:Redis命令執行過程(客戶端)原始碼Redis客戶端
- 線上定時指令碼執行慢,分析過程指令碼
- Tomcat執行web程式過程及server.xml配置TomcatWebServerXML
- Java程式從開發到執行經歷過程Java
- webpack loader 的執行過程Web
- Oracle ASM Rebalance執行過程OracleASM
- MapReduce 執行全過程解析
- Redis 命令的執行過程Redis
- 程式碼提交過程
- Go runtime 排程器精講(八):執行時間過長的搶佔Go
- 執行緒及視訊解碼過程6-16執行緒
- 一條Sql的執行過程SQL
- mysql執行sql語句過程MySql
- Javascript中new的執行過程JavaScript
- Informix 執行緒sleep 分析過程ORM執行緒
- javascript引擎執行的過程的理解--執行階段JavaScript