Maven實戰(二)——POM重構之增還是刪

重構是廣大開發者再熟悉不過的技術,在Martin Fowler的《重構——改善既有代碼的設計》一書中,其定義爲“重構(名詞):對軟件內部結構的一種調整,目的是在不改變軟件之可察行爲前提下,提高其可理解性,降低其修改成本.”以及“重構(動詞):使用一系列重構準則(手法),在不改變軟件之可察行爲前提下,調整其結構.”。重構能夠改善軟件設計,使代碼更易讀,更容易找出bug,並幫助你更快速地編碼。較之於一般的代碼來說,Maven的POM簡單很多,不過隨着項目的成長,模塊的增多,POM的內容也會變多,這個時候,我們可以對POM進行重構,在保持構建成功的前提下,簡化POM內容,使其更簡潔易懂。

前提

大家都知道,如果沒有單元測試爲前提,對代碼進行重構是非常危險的。同樣,在重構POM之前,項目應該有足夠的自動化測試保證POM重構不會破壞構建。例如,重構POM的時候可能會刪除或添加依賴,造成依賴版本變化,依賴範圍變化,插件版本變化等等,這些變化可能會導致項目編譯失敗,或者測試失敗。在自動化測試及構建的基礎上,最好能夠有持續集成環境,以保證POM的修改可能造成的問題能夠及時的被發現和修復。筆者目前工作的項目有一個對應的持續集成任務,該任務基於Hudson,每10分鐘檢查一次SCM,如果發現變更則構建項目,並反饋結果。這樣,我就不用擔心自己修改POM會引入潛在的問題。

增還是刪

有時候這個答案是很顯然的,當你的POM中存在一些依賴或者插件配置,但實際代碼沒有用到這些配置的時候,應該儘早刪掉它們以免給人帶來困惑。

還有一種常見的情況,我們可以刪掉一些POM的元素,例如POM中配置了繼承,當前模塊與父模塊使用同樣的groupId和version時,就可以將<groupId>和<version>元素刪除,因爲它們可以從父模塊繼承而來,重複配置沒有什麼意義。

<project>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.juvenxu.sample</groupId>
    <artifactId>sample-parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>sample-foo</artifactId>
  <packaging>jar</packaging>
...
</project>

上述配置就sample-foo就沒有groupId和version,需要注意的是,artifactId是不能被刪除的,因爲該元素不能也不應該被繼承,父子模塊應當使用不同的artifactId值。

除了刪之外,有些時候我們還需要在POM中增加一些XML元素,目的是爲了讓POM更清晰易讀,且保證Maven構建的穩定性。考慮如下的插件配置:

<plugin>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <source>1.5</source>
    <target>1.5</target>
  </configuration>
</plugin>

雖然沒有groupId及version,但這段配置是完全合法的。當插件沒有groupId配置的時候,Maven會認爲它是官方插件而自動使用org.apache.maven.plugins作爲groupId,當插件沒有version配置的時候,Maven則會使用最新的版本(Maven 2會使用最新的版本,包括SNAPSHOT,而Maven 3則只使用最新的非SNAPSHOT版本)。這段配置有兩個問題,首先,如果讓一個不熟悉Maven的開發者來看這段配置,他會感到費解,groupId和version究竟是什麼呢?這與不清晰的代碼是一個意思,有時候一些程序員爲了讓代碼更短,會採用一些奇怪的語法和變量名,雖然代碼量是少了,但溝通成本增加了,得不償失。其次,讓Maven猜測版本會有潛在的風險,因爲插件的最新版本可能會變化,而這種變化對於Maven使用者來說通常是隱藏的,特別是在Maven 2中,甚至可能引入SNAPSHOT版本的插件,這是非常危險的。基於這兩個原因,使用插件的時候,我們應當配置清楚groupId和version,如:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>2.3.2</version>
  <configuration>
    <source>1.5</source>
    <target>1.5</target>
  </configuration>
</plugin>

基於類似的原因,在配置項目依賴的時候,我們也應當一直顯式地寫明依賴版本,以避免Maven在不同的時刻引入不同版本的依賴而導致項目構建的不穩定。

除了上面提到的增刪點之外,Maven官方還提供了一個非常有用的Maven Dependency Plugin來幫助我們分析項目中哪些依賴配置應該刪除,那些依賴配置應該增加。Maven Dependency Plugin的analyze目標能夠幫助分析項目依賴,例如運行命令 mvn dependency:analyze ,可以看到如下輸出:

[INFO] --- maven-dependency-plugin:2.1:analyze (default-cli) @ sample-bar ---
[WARNING] Used undeclared dependencies found:
[WARNING]    org.springframework:spring-context:jar:2.5.6:compile
[WARNING] Unused declared dependencies found:
[WARNING]    org.springframework:spring-core:jar:2.5.6:compile
[WARNING]    org.springframework:spring-beans:jar:2.5.6:compile
[INFO] ------------------------------------------------------------------------

這裏的 Used undeclared dependencies 是指那些在項目中直接使用到的,但沒有在POM中配置的依賴。例如該例中可能項目中的一些類有關於spring-context的Java import聲明,但spring-context這個依賴實際是通過傳遞性依賴進入classpath的,這就意味者潛在的風險。一般來說我們對直接依賴的版本變化會比較清楚,因爲那是我們自己直接配置的,但對於傳遞性依賴的版本變化,就會比較模糊,當這種變化造成構建失敗的時候,就很難找到原因。因此我們應當增加這些 Used undeclared dependencies 。

依賴分析還提供了 Unused declared dependencies 供我們參考,這表示那些我們配置了,但並未直接使用的依賴。需要注意的時,對於這些依賴,我們不該直接簡單地刪除。由於dependency:analyze只分析編譯主代碼和測試代碼使用的依賴,一些執行測試和運行時的依賴它發現不了,因此還需要人工分析。通常情況,Unused declared dependencies 還是能幫助我們發現一些無用的依賴配置。

最後,還一些重要的POM內容通常被大多數項目所忽略,這些內容不會影響項目的構建,但能方便信息的溝通,它們包括項目URL,開發者信息,SCM信息,持續集成服務器信息等等,這些信息對於開源項目來說尤其重要。對於那些想了解項目的人來說,這些信息能他們幫助找到想要的信息,基於這些信息生成的Maven站點也更有價值。相關的POM配置很簡單,如:

<project>
  <description>...</description>
  <url>...</url>
  <licenses>...</licenses>
  <organization>...</organization>
  <developers>...</developers>
  <issueManagement>...</issueManagement>
  <ciManagement>...</ciManagement>
  <mailingLists>...</mailingLists>
  <scm>...</scm>
</project>

小結

無論是對POM內容進行增還是刪,其目的都是一樣的,就是爲了讓POM更清晰易懂且讓構建更穩定。從這點來說,POM重構與一般的代碼重構是類似的。需要謹記的是,重構的前提是完善的自動化測試和持續集成。本文介紹的單個POM規模的重構,下篇文章筆者會介紹多模塊項目的POM重構等內容。


文章出處:http://www.infoq.com/cn/news/2010/12/xxb-maven-2-pom

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章