天天看點

跟ApacheBeam學品質控制之道Enforcer插件

在學習、開發apache beam源碼過程中,除了它精妙的設計(通過幾個簡單的概念抽象把實時和離線的計算邏輯模型統一了起來),龐大的代碼量(java 33萬行, python9萬行),還有一個比較大的感受是它的品質控制做得特别好,比之前參與過的其它一些開源項目都要好,這可能跟google的工程品質高于業界有關。但是這裡面也沒什麼什麼奇技淫巧,隻是善用了一些插件而已,我在這裡想把我在apache beam裡面看到、學到的一些品質實踐分享給大家。代碼品質提升其實沒有什麼太多的捷徑,這裡要分享的也不是多麼高大上的道理,每個小點都是很零碎的一個小技巧,但是所有這些<code>小技巧</code>組合起來,會讓你對代碼的品質更有信心。

事物的好壞是對比出來的,我們先來看看我們代碼裡面一些問題。

比如:

再比如:

我們代碼很多沒有javadoc, 或者好一點的有javadoc,但是不符合javadoc規範(用javadoc實際去生成會報格式不對)。

下面截取一段cap裡面的代碼:

比如這裡這行代碼長達138,與一般的推薦配置(80, 最多100)長多了,已經超出一屏了,看起來很難受。

用依賴分析工具分析一下cap的代碼依賴,可以發現,裡面有很多沒用的依賴以及用到了但是沒有聲明的依賴。

這些每個問題單個看起來都不是大問題,但是堆積起來會讓代碼看起來有點<code>髒</code>。

下面我介紹一下我在beam裡面看到的品質控制相關的一些小技巧,主要是一些maven插件的使用和一些測試庫的使用,以及一些思想上的意識。

dependency插件的作用是幫我們掃描項目的依賴問題,它可以把我們實際要到了,但是沒有聲明的依賴;或者實際沒用到,但是聲明了的依賴都給找出來,幫你保持代碼的純潔, 下面是一個掃描報錯的例子:

這裡我們聲明了一個沒有用到的,但是聲明了的<code>auto-value</code>的依賴,是以編譯失敗了。有了這個插件的保證,我們可以很有自信的知道我們引入的每個依賴都是有用的,有意義的。

checkstyle is a development tool to help programmers write java code that adheres to a coding standard. it automates the process of checking java code to spare humans of this boring (but important) task. this makes it ideal for projects that want to enforce a coding standard.

它能做的一些典型檢查包括:

fallthrough: 如果你的switch/case裡面沒有寫break,它會自動檢測出來。

customimportorder: 檢查import的順序符合指定樣式。

linelength: 檢查代碼行數不要超長。

methodlength: 檢查方法行數不要超長。

下面是我最近在寫beam代碼的時候編譯時候報的幾個checkstyle錯誤:

enforcer是另一比有意思的maven插件, 它可以幫你指定你代碼所需的運作環境,比如需要的maven版本(maven不同版本之間有時候行為差異還是很大的,比如我們采雲間的代碼基本都是用3.x版本編譯的,但是開發機上預設裝的是2.x的,這樣編譯的時候就會報很奇怪的錯誤,而enforcer插件則可以把這個需求明确化,如果你的maven的版本不對,它會明确告訴你maven版本不對,而不是其它的詭異錯誤)。它能做到的一些檢查包括:

maven的版本

jdk的版本

os的版本

檢查指定的屬性(property)是否存在

在我看來maven-enforcer-plugin有點像java語言裡面assert,assert如果失敗了,說明運作環境有問題,直接失敗。

下面是一個maven版本不對的錯誤:

最近這些年函數式程式設計的思維開始流行起來,很多非函數式的語言也開始在語言層面支援某些函數式的特征,比如java 8裡面的<code>lambda</code>, <code>stream</code>等等,google autovalue也是類似的目的,它的目的是讓你的pojo程式設計readonly的(隻有getter), 進而實作函數式語言裡面immutable的特性。

它最大的貢獻在于,它讓你隻需要定義你需要的字段:

這裡我們定義了我們需要兩個字段: <code>name</code>和<code>numberoflegs</code>以及一個用來建構<code>animal</code>對象的<code>create</code>方法,其它的則都由autovalue自動生成,其中<code>autovalue_animal</code>就是autovalue自動生成的類。在autovalue_animal裡面,它幫我們自動實作了<code>hashcode</code>, <code>equals</code>, <code>tostring</code>等等這些重要的方法。這些方法的特征是實作的過程基本都一樣,但是容易出錯(由于粗心), 那麼不如交給架構去自動産生。

如果你的類字段比較多,那麼autovalue還支援builder模式:

這樣我們就可以一步一步漸進地把對象構造出來了。

所謂的api surface是指我們一個系統暴露給另外一個系統一個sdk的時候,我們到底應該把哪些類,哪些package暴露給使用者,這個問題很重要,因為考慮向後相容性的話,暴露的package越少,将來修改的時候,破壞向後相容性的可能性就越小,sdk就越穩定。我們平常的時候對于這種事情可能都是通過人肉分析、review,在beam裡面它直接編寫成了一個單元測試:

這個測試表明,beam的sdk向外暴露的package就是上面列出的這些,下次來個新手貢獻的代碼如果破壞了這個約定,那麼這個單元測試就直接報錯,無法送出merge。還是那句話,凡是能自動化檢測的東西不要依靠人肉。這裡涉及到的主要技術是:

通過掃描classpath對指定包裡面所有類的方法,參數,傳回值進行檢查。

<code>hamcrest</code>這個支援<code>matcher</code>的單元測試的庫,它讓你不隻可以<code>asserttrue</code>, <code>assertfalse</code>, <code>assertequals</code>, 而是可以自由指定需要滿足的條件。

給beam貢獻代碼的時候最大感受在于,你不需要去問其它commiter或者看什麼文檔去确認你的代碼風格是否符合,是否用對了maven版本,jdk的版本對不對,javadoc需不需要寫等等,你隻要編譯下代碼,maven會告訴你的代碼是否ok。隻要通過了編譯,代碼風格、一些小的錯誤等等基本不會有了,那麼代碼review的時候主要就集中在代碼設計層面了。有用的maven插件還有很多,這裡隻是舉了幾個例子,我覺得比每個插件本身更重要的是:

對代碼品質的重視的意識。

使用工具/代碼(而不是文檔、流程)來解決保障代碼品質。