https://github.com/apache/kafka/pull/17318
背景故事
今天來講講Gradle
的建置優化,大家手上有沒有肥嫩嫩到睡醒都還沒建置完的專案?如果有的話,我相信各位優秀的工程師一定想過要善用Gradle
提供的兩大加速建置的服務,分別是Compilation Avoidance
和Incremental Compilation
如果此時此刻你心裡的念頭是「阿糟糕,我現在才知道這些東西」,別擔心就算不知道你也已經在享受這兩個優秀機制的服務了。這兩個服務是Gradle
內建的機制,只要有符合條件就會啟用,所以我們現在就來稍微稍微講一些細節吧。
Compilation Avoidance
顧名思義就是要想辦法避免不必要的編譯,所以故事從什麼是不必要的編譯開始吧!當大家在寫Java
的時候都會特別留意APIs的相容性吧?我們常常說APIs相容性有幾種等級,從行為的相容、介面的相容到二進制的相容,這邊來個簡單的例子,假設你提供的函式庫有一個方法:
String fuckMe(String how)
行為的相容可以想像成你覺得這個名命不太行,打算改一個名稱,但是實作的行為是一樣的。
String screwMe(String how)
如此你的使用者只需要簡單的文字替換,然後重新編譯就好,不用擔心行為的差異產生問題。
可是好景不常,上頭說他討厭字串所以你必須把類型改成CharSequence
:
String screwMe(CharSequence how)
這個狀況就是介面的相容,你的使用者不需要改任何程式碼,但是需要重新編譯來獲得正確的方法連結。
最後在要上線前,你發現實作有個地方要修,但保持一樣的方法簽名:
String screwMe(CharSequence how)
這種就是二進制的相容,你的使用者不需要改任何程式碼也不需要重新建置。
講到這裡,大家可以想像Gradle
是巧妙運用上述哪個機制了嗎?沒錯,那就是二進制的相容,或者更準確的說是ABI application binary interface
!這是什麼意思?簡單來說Gradle
會根據這個模組的ABI來建立快取的索引,當Gradle
發現這個索引沒有變動時,就會認定是二進制相容,進而避免觸發任何後續相依的建置,也就是Compilation Avoidance
的效果
那麼什麼是Incremental Compilation
?其實故事很簡單,就是如果模組的建置避免不了,Gradle
則會檢查有哪些檔案被影響到然後只重新編譯該些檔案。
講到這裡,大家心裡可能會想說,「喔靠球都給Gradle
就好了啊,我們還需要做什麼?」,其實我們可以做的事情很多,但最重要的一件事情就是別給Gradle
添麻煩!
大家可以想像一下,如果你的專案結構很亂,導致Gradle
覺得每個都有關連該怎麼辦?那麼上述任何一種優化你可能都享受不到,只能每次建置專案就去睡覺或是茶水間弄咖啡,然後績效低落最後回家吃自己。所以進到今天的主題,Kafka
做了什麼事情阻擋了Gradle
的優化?其實答案很簡單就是剛剛講到的,混亂的專案結構!大家知道Kafka
的整合測試的模組結構是什麼嘛?就是通通給我依賴core
模組,這個代表什麼?那就是core
的修改只要不小心戳到二進制的不相容,那麼需要跑整合測試的模組通通都要重新建構!偏偏core
模組又是Kafka
養出來放各種伺服器端程式碼的龐大模組,這意味著core
的修改都非常非常非常容易發生,也等於非常非常非常容易觸發二進制上的不相容,所以你看看這就是把Gradle
當塑膠,完全不管人家真心為你準備的優化 ...
解決辦法
其實其他模組要撰寫整合測試真的需要直接依賴整個core
模組嘛?當然不用,其實只需要用到少數的API
就可以完成整合測試的開發,因此一個解決辦法也是常見的手法,就是在core
與其他需要整合測試的模組中間隔一個模組作為護城河,讓core
造成的二進制不相容只會擴散到作為護城河的模組,這樣重新編譯只會發生在護城河,同時護城河本身的程式碼沒有變動自然具備二進制的相容性,所以其他需要整合測試的模組就通通不需要重新編譯!除此之外,這樣也能讓Kafka
專案結構更清楚,通通依賴core
模組也容易引發互相依賴的循環。總之,一個好的專案結構能帶來許多好處,尤其在專案越長越大的時候 ... 希望大家在工作上都有機會坐下來好好思考這個問題
廣告
歡迎訂閱全臺最鬆散的開源社群源來適你,上面不定期會有各種開源的廢文。也歡迎參加全臺最鬆散的開源討論頻道,上面有一群網友一起在刷開源技術