拯救Java Code Style強迫癥

MFYBernd 8年前發布 | 20K 次閱讀 Java Java開發

拯救Java Code Style強迫癥

文/周宇剛

擁有 10 年的 JAVA EE 開發經驗,在 ThoughtWorks 擔任高級咨詢師。在加入 ThoughtWorks 之前,在一家國內領先的航旅企業擔任架構師,專注于持續交付實踐和大型企業應用架構治理。

        這篇文章緣起于上一個持續交付的咨詢項目,當時正在指導客戶團隊的 Java 工程師做 Code Review,發現一個很有意思的現象:有一位工程師對 Code Style 特別在意,所以在 Code Review 的大部分時間中都是該工程師在指出哪里哪里的格式不對,但是團隊并沒有找到改進方法,每次的結論都是“下次我注意一點。”我挺欣賞這位工程師對 Code Style 的認真態度,所以就萌生了“怎么拯救 Code Style 強迫癥”的想法。

        要點

  • Code Style 不是個人喜好問題,它會影響工作效率,團隊應將其當做工程實踐予以重視。
  • Code Style 需要端到端的工具支持,盡早解決問題,避免技術債。
  • 以 Checkstyle 作為核心工具支撐 Java 項目的 Code Style 實施方案。

        Code Style 是一項工程實踐

拯救Java Code Style強迫癥

        我是右側風格的忠實擁躉,如果讓我在工作的項目中看到左側風格的代碼,你猜猜我的反應是什么。

拯救Java Code Style強迫癥

        嗯,可能我對代碼風格確實有些強迫癥,但事實上,Code Style 并不僅僅是代碼是否好看那么簡單,如果沒有按照慣例來編寫代碼,甚至會讓閱讀者產生疑惑。

private Listener listener = new Listener () 
// So Listener looks like a class? {}; // Oops, it is an interface

        如果代碼可讀性還不足以打動你,那么想象一下這個場景,你的同事說他修復了兩個空指針問題,請你幫忙 Code Review,你查看了這個文件的修訂歷史,乍看之下有許多改動,看來是個大動作。然而事實上,絕大部分改動是代碼格式調整,只有兩處改動與需要 Review 的問題相關。

拯救Java Code Style強迫癥

        (看來這位同事的 IDE 使用了不同的自動縮進設置,導致所有行都產生了縮進)

        之所以會產生以上這些影響工作效率的問題,是因為團隊沒有重視 Code Style,沒有把它當做一項工程實踐,既沒有對其達成一致,也沒有正確地使用工具幫助實施。

        那就按照工程實踐的標準來實施 Code Style

        本文將重點介紹 Java 項目中 Code Style 的工具支持,但在此之前,你的團隊需要一起做一些決定:

  1. 使用哪種 Code Style?

            每個人可能都有偏好的 style,但在團隊協作面前,需要一定的妥協。有些公司或組織有著統一的 Code Style 指導標準,蕭規曹隨是個不錯的選擇(但是要確保這類統一指導標準在制定時參考了開發人員的意見,是切實可行的),你的團隊也可以自己裁剪,但至少要保證項目(Repository)級別上使用同一種 Style。

  2. 如何處理不符合 Code Style 的提交?

            大家往往懈怠于事后補救的方式,我的建議是不要讓不符合約定的代碼流入代碼庫。對于遺留項目,尤其是大型項目,可以選擇一部分代碼作為實施范圍,集中修復 Style 問題后嚴格實施,切忌操之過急,最后團隊疲憊不堪只得放棄。

        我們都知道人工監督檢查的方式是不可持續和不可靠的,來看看有哪些工具可以提供幫助吧。

        懶惰是第一生產力

        工程實踐不能沒有自動化工具支持,在 Java 生態圈中,Code Style 工具最出名的應該是 Checkstyle 了,它可以通過 XML 形式的外部 DSL 來定義 Code Style 的檢查風格,比如你可以從這里找到 Google 的 Java Checkstyle 配置文件。這里我不會詳細介紹 Checkstyle 本身,相反,我會更多地探討如何工程化地使用 Checkstyle,在交付代碼的各個活動中,我們都可以用到 Checkstyle,進行 360°無死角的檢查。

拯救Java Code Style強迫癥

        (和 Code Style 相關的代碼交付生命周期)

        守住提交的質量關口

        為了貫徹不讓不符合約定的代碼流入代碼庫的決定,可以優先在服務端設置 Code Style 的檢查關卡。

拯救Java Code Style強迫癥

        (優先守住代碼提交時的服務端檢查,可以考慮使用 CI 服務器來實現)

        從實現層面上說,有兩種方式:

        一是在 SCM(Source Control Management,例如 Git/SVN)服務端設置檢查項,如果不達標則拒絕提交,但這種方式相對不容易實現,而且一般 SCM 服務端也不由開發團隊管理,設置起來不靈活也不方便。

        二是利用持續集成服務器,開發團隊的每一次提交都會觸發一次構建,我們可以在構建腳本中加入 Checkstyle 檢查,如果有不達標的代碼則讓構建失敗,以便告訴提交者立即修復 Style 問題。我更推薦這個方案,因為相關的工具支持都很成熟,實現簡單,而且構建過程可以在開發者的本地環境復制,以便在后續改進中將 Checkstyle 檢查前移,提供更快的反饋。如果團隊使用 Maven/Gradle 等構建工具,可以用插件的方式實現 Checkstyle 檢查并嵌入到整個構建過程中。這樣 CI 服務器只要調用構建腳本就行了。

        在開發者本地驗證 Style

拯救Java Code Style強迫癥

        (在開發者本地實現驗證,反饋關口前移)

        在實現了 CI 驗證后,就可以著手實現開發者本地驗證了,這樣開發者就不用等到提交代碼到服務端后才會獲得反饋了。由于之前采用的是構建工具的插件方案,所以開發者在本地運行構建就能實現驗證了。比如 Gradle 提供了 Checkstyle 插件支持,你可以在這里找到 Gradle Checkstyle Plugin 的詳細配置文檔,如果你使用 Maven,則可以參考這里。現在只需要一條命令,開發者久能在本地驗證 Code style 了。

# build.gradle # omitted plugins apply plugin: 'checkstyle' checkstyle { configFile = file ("config/checkstyle.xml") //指定 checkstyle 配置文件 
    toolVersion = "7.4" //指定 checkstyle 工具的版本,部分 style 規則有版本要求 
} checkstyleTest.exclude "**/ContractVerifierTest**" // 忽略檢查生成代碼,這個鍋我們不背 // 如果出現 checkstyle warning 也使構建失敗,插件默認只支持 checkstyle error 失敗 // Fail build on Checkstyle Warning Violation · Issue #881 
tasks.withType (Checkstyle) .each { checkstyleTask -> checkstyleTask.doLast { reports.all { report -> def outputFile = report.destination if (outputFile.exists () && outputFile.text.contains ("<error ")) { throw new GradleException ("There were checkstyle warnings! For more info check $outputFile") } } } }

        現在只需要一條命令,每個開發者就能在本地驗證 Code Style 了。你可以在這里找到 Gradle Checkstyle Plugin 的詳細配置文檔,如果你使用 Maven,則可以參考這里

?  court-booking-backend (master) ? ./gradlew check Starting a Gradle Daemon (subsequent builds will be faster) :compileJava :processResources UP-TO-DATE :classes :checkstyleMain [ant:checkstyle] [WARN] /Users/twer/Workspace/restbucks/court-booking-backend/src/main/java/com/restbucks/courtbooking/http/CourtRestController.java:16: 'method def' child have incorrect indentation level 4, expected level should be 8. [Indentation] :checkstyleMain FAILED FAILURE: Build failed with an exception.

        本地驗證很不錯,但我有時候會忘記執行

拯救Java Code Style強迫癥

(讓機器代勞瑣事)

        有時候,開發者修改了代碼后會忘記執行本地檢查就提交代碼了,最好能夠在提交代碼前自動執行檢查。如果你使用 Git 的話,可能會想到 Git commit hook,比如這是我常用的 pre-commit hook

#!/bin/sh # From gist at https://gist.github.com/chadmaughan/5889802
 # stash any unstaged changes git stash -q --keep-index # run the tests with the gradle wrapper ./gradlew clean build # store the last exit code in a variable RESULT=$? # unstash the unstashed changes git stash pop -q # return the './gradlew build' exit code exit $RESULT

        將該腳本拷貝到.git/hooks/下,在執行git commit的時候就會自動觸發檢查了,如果檢查失敗則提交失敗。但問題是.git并不能提交到遠程代碼倉庫,那么除了人工分發和拷貝外,有沒有更好的方式在團隊中共享這個機制呢?

        可以曲線救國!把 pre-commit 納入版本控制(如下面的config/pre-commit),再使用構建工具的擴展機制來自動完成拷貝工作,這樣可以間接實現 git hooks 的團隊間共享。

# build.gradle task installGitHooks (type: Copy) { //將 pre-commit 拷貝到指定位置
    from new File (rootProject.rootDir, 'config/pre-commit') into { new File (rootProject.rootDir, '.git/hooks') } fileMode 0755 } build.dependsOn installGitHooks //設置執行 build 任務時會自動觸發 installGitHooks 任務

        關閉包圍圈,編輯時反饋

拯救Java Code Style強迫癥

(實時反饋)

        之前基于構建工具的方案都很好,但是對于開發者來說,最好能將反饋前移到編輯時,并且可視化。所幸的是,Checkstyle 的生態系統非常成熟,各主流 IDE 都有插件支持,以 Intellij Idea 為例,可以使用 checkstyle-idea 插件,讓團隊成員手工設置插件,使用項目的 checkstyle 配置文件即可(我目前還沒有找到自動化配置的方式,或許 gradle idea 插件可以?)

拯救Java Code Style強迫癥

拯救Java Code Style強迫癥

(checkstyle-idea 插件配置和效果)

        有了自動實時檢查,最好還能將 IDE 的自動格式化與 Checkstyle 配置文件掛鉤,否則自動格式化反倒給你添麻煩了。

拯救Java Code Style強迫癥

(為 IDE 導入 checkstyle 配置文件作為自動格式化的依據)

        如果你連自動格式化都懶得按,那可以試試 Save Actions 插件,它可以在 Intellij 保存文件時自動執行代碼格式化等動作。

拯救Java Code Style強迫癥

(這個插件目前對部分文件有些問題,可以通過 File path exclusion 忽略)

        總結

  1. Code Style 影響工作效率,團隊應將其當做工程實踐予以重視。
  2. Code Style 不能靠人工監督和檢查,應該提供端到端的工具支持
  3. 服務端檢查(推薦集成到 CI 的構建步驟中)
  4. 開發環境檢查(使用各構建工具的 Checkstyle 插件)
  5. 自動提交檢查(git pre-commit hook 與共享)
  6. IDE 增強(checkstyle 插件實時可視化反饋/自動的自動格式化!)
  7. 以上的工具都要依據為同一份 Checkstyle 配置文件,并納入版本控制

        希望以上這些招數可以解救 Java Code Style 強迫癥 :)

 

來自: insights.thoughtworkers.org

 

 

 本文由用戶 MFYBernd 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!