在現代開發工具的輔助下,大多數的編輯器或 IDE 都已經程式碼自動完成的功能,寫程式已經變得相對輕鬆些。不過我們還是得注意一個事實,就是程式寫完跟寫好還是有一段差距。程式碼自動完成只是讓我們能更有效率的把程式寫完,至於寫好,還得仰賴其他機制。
若您習慣使用的是強型別的語言(比如說在這個系列裡我們用的 Kotlin),編譯器本身已經能協助你找出一些錯誤;若您習慣使用的是 IDE(比如說在這個系列裡示範的 IntelliJ IDEA),通常能提供更多 Inspection 的輔助,讓您能提早發現可能有問題的程式碼。
但假如您用的不是強型別的程式語言,而團隊成員也不是每個人都使用 IDE 等級的工具時,該如何及早找出程式碼庫裡可能有潛在問題的程式碼?又如何確保品質能一直維持住呢?
在 Kotlin 生態系裡,detekt 是一個知名的靜態分析工具,其原理是從 Kotlin 編譯器取得語法樹後,依照內建的規則(Rule Set)進行分析並提供改善建議。其支援多種輸出格式(XML、HTML、TXT)、提供 Gradle Plugin 及 IntelliJ IDEA Plugin 方便整合,非常符合 Kotlin 開發者的需求。接著,我們將在示範專案裡導入 detekt 靜態分析工具。
首先打開 build.gradle.kts
,在 plugins
區段新增 detekt Plugin:
plugins {
// ...
id("io.gitlab.arturbosch.detekt") version "1.18.1"
}
記得 Reload Gradle,讓 IntelliJ IDEA 下載 detekt Plugin 至本機。完成後就會在 Gradle Tasks 的 verification
Group 底下發現新增了一系列 detekt 開頭的 Task。
為了讓我們看到 detekt 的檢查效果,照慣例我們得先把程式碼弄爛(咦?)。首先我們在 src/main/kotlin/io.kraftsman
底下建立一個新的資料夾叫 dtos
,接著把 Product
Data Class 搬進去。你會看到這時候 Product
的 package 就從原本的 io.kraftsman
變成 io.kraftsman.dtos
。然後我們打開 ShoppingCart
,會看到 IntelliJ IDEA 幫我們多加了一行 import io.kraftsman.dtos.Product
(原本不用是因為兩個 Class 在同一個 Package 裡,現在多了一層所以需要 Import)。在這邊我們故意把這一行變成 Wildcard Import,也就是說把 import io.kraftsman.dtos.Product
變成 import io.kraftsman.dtos.*
。
接著我們用 detekt 來進行靜態分析,直接在 IntelliJ IDEA 右邊的 Gradle 面板裡 verification 底下的 detekt Task 點兩下,或是在終端機裡執行以下指令:
$ ./gradlew detekt
> Task :detekt FAILED
style - 5min debt
WildcardImport - [ShoppingCart.kt] at .../ShoppingCart.kt:3:1
Overall debt: 5min
FAILURE: Build failed with an exception.
您可以看到 detekt 已經指出不允許使用 Wildcard Import 的警告,同時 detekt 也會把文字版的分析報告產生在 build/reports/detekt
裡,共有 XML、HTML、TXT 三種版本。
雖然透過 Gradle 執行 detekt 非常方便,但每次寫完程式才執行總覺得還是太後知後覺了一點。有沒有可能在寫程式的時候就讓 detekt 幫我們檢查呢?答案是有的,detekt 也有出 IntelliJ IDEA Plugin,讓這些規則可以直接整合到 IntelliJ IDEA 的 Exception 裡。
安裝方式很簡單,首先打開 IntelliJ IDEA 的 Plugin 設定頁。在 Marketplace 裡搜尋「detekt」,點擊 Install 下載安裝即可。
安裝好需要重開 IDE,完成後記得到偏好設定裡的 detekt 設定頁,確認 Enable Detekt 選項有勾起來(其他選項可以視需求自行決定是否勾選)。
再回到程式碼,你會發現 import io.kraftsman.dtos.*
這一行就被標記了顏色,當滑鼠移上去時,就會顯示 Detekt 的警告訊息。
就筆者的經驗,絕大多數 detekt 點出的問題,都能用 IntelliJ IDEA 快速修復功能來修正。以這個 Wildcard Import 為例,最快的修正方式,就是先把 import io.kraftsman.dtos.*
刪掉,這時 IntelliJ IDEA 就會提示找不到 Product
Class。我們先按 F2 就會讓游標跳到發生錯誤的位置,然後再按 Option+Enter 呼叫快速修復功能,IntelliJ IDEA 就會自動提示以補上 Import 來修正這個問題,這時按 Enter 套用,IntelliJ IDEA 就會補上 import io.kraftsman.dtos.Product
。
當然目前的練習專案相對簡單,不過這樣的快速修復策略可以用在很多地方,IntelliJ IDEA 非常聰明的知道在各種不同的情境下可以怎麼修正,我們只需要記得 Option+Enter 這個快速鍵就好。
還記得我們前兩天使用 ktlint 來檢查程式碼的排版風格嗎?detekt 其實也提供了跟 ktlint 的整合,只需要執行 $ ./gradlew detekt
就可以同時檢查排版風格以及靜態分析,將需要執行的 Gradle 指令縮減一些。
整合的方式很簡單,只需要在 build.gradle.kts
的 dependencies
區段加上相依套件即可:
dependencies {
// ...
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.18.1")
}
不過這邊要提醒一下,detekt 的 ktlint 整合,只能觸發排版風格檢查,並沒有整合重新排版程式碼的動作喔!換句話說,假如您需要重新排版程式碼的動作,還是得安裝 ktlint 取得該指令。在這邊筆者會建議大家在安裝 Gradle Plugin 的時候還是兩個都裝,在 CI 上面只需要執行 detekt 指令即可,發現有排版風格問題時,再本機由人工手動執行 ktlint 的排版指令。
今天跟大家討論了如何在專案裡導入 detekt 靜態分析檢查工具,方便我們在團隊合作時能及早發現一些潛在的錯誤,這個工具可以在本機 IntelliJ IDEA 上執行、也能在 TeamCity 上執行,相信可以滿足各種使用情境。若您使用的語言不是 Kotlin 也沒關係,同樣的觀念在各個程式語言都有類似的工具,只要用「static analysis <程式語言名字>」就大多能找到,再整合到 IDE 和 CI 主機即可。明天我們就來試著將 detekt 整合到 TeamCity 的 Build Step 裡。
今天這麼早就發布文章~
雙鐵不是開完笑的,先解決一個才有辦法專心對付另一個 XD
沒錯沒錯,我今天的也還沒寫,連假都沒時間看 ><