拯救 Java Code Style 強迫症

ThoughtWorks發表於2017-06-16

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

要點

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

Code Style是一項工程實踐

我是右側風格的忠實擁躉,如果讓我在工作的專案中看到左側風格的程式碼,你猜猜我的反應是什麼。

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

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

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

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

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

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

使用哪種Code Style?

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

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

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

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

懶惰是第一生產力

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

(和Code Style相關的程式碼交付生命週期)

守住提交的質量關口

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

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

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

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

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

在開發者本地驗證Style

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

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

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

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

(讓機器代勞瑣事)

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

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

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

關閉包圍圈,編輯時反饋

(實時反饋)

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

(checkstyle-idea外掛配置和效果)

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

(為IDE匯入checkstyle配置檔案作為自動格式化的依據)

如果你連自動格式化都懶得按,那可以試試Save Actions外掛,它可以在Intellij儲存檔案時自動執行程式碼格式化等動作。

(這個外掛目前對部分檔案有些問題,可以通過File path exclusion忽略)

總結

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

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

相關文章