# 讓開發自動化: 文檔化一鍵通
_自動生成開發人員和用戶文檔_
項目的文檔化通常都是交付軟件產品時不可避免的難題。但是想象一下如果僅需單擊一個按鈕就能夠生成文檔呢?在本期的 [_讓開發自動化_](http://www.ibm.com/developerworks/cn/java/j-ap/)中,自動化專家 Paul Duvall 闡述了如何運用開源工具自動生成統一建模語言(Unified Modeling Language,UML)圖、構建圖、實體關系圖(entity-relationship diagram,ERD)乃至用戶文檔。
很少有軟件開發人員愿意為他們的軟件開發項目編寫文檔。然而,除非您永遠不想完成您的項目,或者您永遠獨立進行軟件開發,又或者您沒有用戶 —這對一個項目來說可不是一個好現象,否則您就需要用一種方式來向別人交待您的軟件的用途。有些開發者誤解了 Agile Manifesto 的 “可運行的軟件 _優于_全面的文檔” 的說法,以為根本不需要 _任何的_文檔資料(請參閱 [參考資料](#resources))。另一方面,多余的文檔對用戶或其他開發人員來說也是一個負擔。我通常尋找一種中間辦法。您猜對了:本文將向您展示如何運用 _自動化_來簡化項目文檔的生成過程,從而減輕這方面的負擔。
## 關于本系列
作為開發人員,我們致力于為用戶自動化流程;但許多開發人員疏忽了自動化我們自己的開發流程的機會。為此,我們編寫了 [_讓開發自動化_](http://www.ibm.com/developerworks/cn/java/j-ap/)系列文章,專門探討軟件開發流程自動化的實踐應用,為您介紹 _何時_以及 _如何_成功應用自動化。
按照我的經驗,有兩個關鍵性的問題制約著軟件開發的文檔化。第一個問題,似乎沒有人會去閱讀文檔。第二個常見問題就是幾乎是在編寫文檔的同時,它就已經過時了。這兩個問題是有著因果聯系的:如果文檔總是保持最新,那么人們就更有可能去閱讀它。自動化生成文檔便可以解決這兩個問題,它可以保持文檔的時效性,從而使它對您的軟件用戶更加有用。
自動化也可能對其他類型的文檔有利,但在本文中我將著重闡述如何讓那些令人痛苦的文檔化任務自動化(請參閱 [參考資料](#resources)查找下面列表中提到的工具的鏈接):
* 使用 UMLGraph 生成當前源代碼的 **UML**圖。
* 使用 SchemaSpy 創建 **實體關系圖(ERD)**,歸檔數據庫中的表格和關系。
* 使用 Grand 生成構建目標以及它們之間的關系的 Ant **構建圖**。
* 使用 Doxygen 生成 **源代碼文檔**。
* 使用 DocBook 制作 **用戶文檔**。
我將使用一般的方法闡述以下內容:
1. 描述手動執行每一項任務遇到的問題。
2. 呈現一個結合使用 Apache Ant 和相關的文檔 / 圖表生成工具實現自動化的例子。
3. 展示一個基于代碼示例的腳本生成文檔的圖象。
和本系列前面的文章一樣,文中所有示例都使用可免費獲得的開源工具,您可以在自己的項目中使用。有些工具(例如,UMLGraph 和 Grand)會使用一個附帶的 GraphViz 工具,該工具要用到一個由特定工具生成的 .dot 文件。
## 將代碼反向工程到 UML 中
我曾遇到過一些擁有十分美觀的 UML 圖的項目 —在項目的初始階段。問題是,在某種特殊情況下,技術負責人無法使模型與源代碼同步。或者需要將寶貴的時間浪費在將源代碼 _手動_反向工程到模型中。這兩種情況都不盡如人意。如果模型無法如實地展示簽入到版本控制庫中的代碼,那么這個 UML 圖構造的再美觀也毫無意義。如果您沒有根據實際的代碼制定決策,那么您可能就要面臨隨之而來的很多問題。
您可以在構建過程中生成圖示,并建立一個持續集成(Continuous Integration,CI)環境來即時地(或定期地)創建圖示。這樣您就能夠制作出有益于決策、易于創建且始終反映最新情況的圖示了。
清單 1 使用 Ant、UMLGraph 以及 Graphviz 對源代碼進行文檔化 :
##### 清單 1\. 使用 UMLGraph 文檔化工具的 Ant 腳本
```
<property name="reports.dir" value="${basedir}/reports"/>
<mkdir dir="${reports.dir}"/>
<path id="project.path">
<pathelement path="${basedir}/src"/>
<pathelement path="${basedir}/lib"/>
</path>
<javadoc sourcepath="${basedir}/src" destdir="${reports.dir}"
classpathref="project.path" access="private">
<doclet name="org.umlgraph.doclet.UmlGraphDoc"
path="UMLGraph.jar">
<param name="-attributes" />
<param name="-enumerations" />
<param name="-enumconstants" />
<param name="-operations" />
<param name="-qualify" />
<param name="-types" />
<param name="-visibility"/>
</doclet>
</javadoc>
<apply executable="dot" dest="${reports.dir}" parallel="false">
<arg value="-Tpng"/>
<arg value="-o"/>
<targetfile/>
<srcfile/>
<fileset dir="${reports.dir}" includes="*.dot"/>
<mapper type="glob" from="*.dot" to="*.png"/>
</apply>
```
清單 1 中,我結合使用 UMLGraph 和 Javadoc 在 Javadoc HTML 報告內部生成一些基本的 UML 類圖。為了自定義展示在每一個類圖中的信息,調用 `UmlGraphDoc`時,我傳遞了如下屬性:
## 使用 GraphViz 制圖
要正常使用 UMLGraph,您必須先安裝 Graphviz 工具(請參閱 [參考資料](#resources),并且計算機的系統路徑中必須包含 Graphviz .dot 文件。
* **`-attribute`**為類顯示字段。
* **`-enumeration`**展示不同的枚舉。
* **`-enumconstant`**為枚舉展示可能的值。
* **`-operation`**為類顯示 Java 方法。
* **`-qualify`**顯示完全限定類名。
* **`-type`**顯示參數數據類型和返回類型
* **`-visibility`**展示字段和方法修改語:`public`、`protected`、`private`或 `default`。
圖 1 展示了用 UMLGraphshows 生成到 HTML 中的 `LoginDaoImpl`類及其關系的 UML 圖例:
##### 圖 1\. 用 UMLGraph 生成的 UML 圖

請 [單擊此處](sidefile.html#fig1)查看完整圖形。
UMLGraph 能夠生成更復雜的關系和其他細節。但是,即便是這個簡單例子中極其基本的 UML 類圖,就已經提供了相當多的信息。它也可以根據當前的代碼庫快捷、形象地展示軟件。它防止了 “代碼 _應該_是這樣的” 這種陳述方式,并且有益于做出更好的決策(關于描述了多種可以自定義 UMLGraph 輸出的屬性的鏈接,請參閱 [參考資料](#resources))。
* * *
## 數據庫文檔化
自動創建最新的 UML 圖將使您獲益良多,同樣,自動地可視化表示數據庫也可以讓您受益匪淺。實體關系圖(ERD)是實現數據庫可視化的最流行的圖示類型。大多數創建 ERD 的工具(例如,ERWinfor)都需要手動生成 ERD。雖然我將要示范的工具 SchemaSpy 無法與現存的一些更復雜的工具媲美,但是它能夠提供數據庫的高級 ERD 視圖 —以及約束、關系等。而且,通過自動構建來運行它,您就可以輕松地從您的版本控制庫中檢查數據定義語言(Data Definition Language,DDL)的最新顯示。
清單 2 中的 Ant 腳本使用 SchemaSpy 工具來創建 Javadoc 格式的文件:
##### 清單 2\. 結合使用 SchemaSpy、Ant 和 Javadoc
```
<property name="reports.dir" value="${basedir}"/>
<java jar="schemaSpy_3.1.1.jar"
output="${reports.dir}/output.log"
error="${reports.dir}/error.log"
fork="true">
<arg line="-t mysql"/>
<arg line="-host localhost"/>
<arg line="-port 3306"/>
<arg line="-db brewery"/>
<arg line="-u root"/>
<arg line="-p sa"/>
<arg line="-cp mysql-connector-java-5.0.5-bin.jar"/>
<arg line="-o ${reports.dir}"/>
</java>
```
清單 2 使用 `java`Ant 任務調用 SchemaSpy,傳遞了很多屬性:
* **`-t`**為數據庫類型(有效值為 `mysql`、`ora`、`db2`,等等。)
* **`-host`**為托管數據庫的計算機名。
* **`-port`**為數據庫 URL 的端口數。
* **`-u`**為數據庫用戶名。
* **`-p`**為數據庫密碼。
* **`-cp`**為類路徑(用于指示數據庫驅動程序 JAR 文件的位置)。
* **`-o`**為輸出目錄的位置。
這些 SchemaSpy 的命令行屬性用于生成顯示 ERD 的 HTML 文件,如圖 2 所示:
##### 圖 2\. 用 SchemaSpy 和 Ant 創建的 ERD

通過結合使用多種工具、作為構建的一部分針對數據庫執行 ERD 生成腳本,并調度 ERD 生成,您就可以在開發過程中輕松、快速地做出很多數據庫決策。
* * *
## 圖解構建過程
通常,構建腳本在相關的目標之間有著復雜的關系。我曾見過許多構建腳本足有 1000 多行,含有大量多余的重復行。如果沒有自動構建的高級視圖,這些構建腳本會很難處理。要想快速確定一個構建過程正在處理的內容,一個有效的方法就是創建一個目標和關系圖。Ant 目標的一個可視模型能夠幫助您作出更有效、更明智的決策,以改進構建腳本的設計。
結合使用 Ant、Grand 和 Graphviz,您就可以創建出構建目標的精確的可視表示。有很多的工具都旨在可視化表示 Ant 目標。而 Grand 的一個優勢便在于它運用了 Ant API,這樣無論 Ant 腳本是否完全有效,它都可以創建圖示。
清單 3 中的 Ant 腳本展示了如何運用 Grand 工具來創建 Ant 腳本目標的可視表示,包括目標間的依賴性:
##### 清單 3\. 使用 Ant 和 Grand 創建 Ant 目標的圖示
```
<target name="create-ant-diagram">
<property name="file.type" value="pdf"/>
<typedef resource="net/ggtools/grand/antlib.xml"
classpath="grand-1.8.jar"/>
<grand output="build.dot" buildfile="${basedir}/build.xml"/>
<exec executable="dot">
<arg line="-T${file.type} -Gsize=11.69,8.27 -Grotate=90 -o build.${file.type}
${grand.output.file}"/>
</exec>
</target>
```
在清單 3 中,首先,我通過指向 `grand-1.8.jar`創建了任務。接著,我在 `buildfile`屬性中為正在分析的構建文件命名。`output`屬性是我正在創建的 Graphviz 文件(我將其命名為 `build.dot`)。 最后,我調用了 `dot`可執行文件生成 `buildfile`的構建目標的 PDF。圖 3 展示了這種文件的一個例子:
##### 圖 3\. 使用 Ant、Grand 和 GraphViz 生成 Ant 目標的圖示

我可以運用這些圖表分析已完成的項目,或者為開發中的項目優化構建過程。
* * *
## 代碼文檔化
如果我想記住為什么創建了一個新的 Java 類或方法,那么我會寫一個 Java 代碼注釋。但如果我想更全面地了解新建的類、方法和屬性,那么我就需要一個代碼文檔化的工具了。多年以來,Java 平臺都將 Javadoc 作為生成代碼文檔的方法,用于代碼庫中的所有類。事實上,`javadoc`任務已成了 Ant 中的標準,它也確實能夠生成代碼文檔。然而,它需要由開發人員負責將一些難看的 HTML 標記嵌入到 Java 源代碼注釋中。例如,清單 4 所示的運用 Javadoc 的代碼注釋:
##### 清單 4\. Javadoc 的代碼注釋
```
/**
This is <i>the</i> LoginServiceImpl class.
<p>
Refer to <a href="url.html">
LoginService overview</a> for more details.
<p>
There is one type of supported {@link LoginServiceImpl }:
<ul>
<li>{@link LoginServiceImpl } (this class)</li>
</ul>
*/
```
如果使用 Doxygen,代碼注釋就會更簡潔,省去了嵌入的 HTML 標記,如清單 5 所示:
##### 清單 5\. 使用 Doxygen 文檔化工具的 Ant 腳本
```
/**
This is <i>the</i> LoginServiceImpl class.
Refer to \ref LoginService for more details.
There is one type of supported LoginService:
- LoginServiceImpl (this class)
*/
```
Javadoc 和 Doxygen 都支持自動生成代碼文檔,但是使用 Doxygen 比較簡單,它提供了一種更直觀的方法來用注釋標注源代碼。清單 6 中的 Ant 代碼片斷展示了 Doxygen 最基本的使用方法:
##### 清單 6\. 使用 Doxygen 文檔化工具的 Ant 腳本
```
<target name="generate-doxygen">
<taskdef name="doxygen" classname="org.doxygen.tools.DoxygenTask"
classpath="ant-doxygen.jar" />
<doxygen configFilename="Doxyfile">
<property name="INPUT" value="${src.dir}" />
<property name="RECURSIVE" value="yes" />
</doxygen>
</target>
```
在清單 6 中,`Doxyfile`的 `configFilename`值是由 Doxygen 自動生成的配置文件的名稱;您可以重新定義。圖 4 展示了一個 `LoginDaoImpl`類的 HTML 報告的例子,它是由清單 6 中的 Doxygen 示例生成的:
##### 圖 4\. HTML Doxygen 文檔

請 [單擊此處](sidefile.html#fig4)查看完整圖形。
通過在自動構建中創建 Doxygen 文檔,您可以獲得有關某個 API 的最新的使用信息。
* * *
## 用戶文檔
到目前為止,您可能一直在想,自動生成技術文檔固然不錯,但是最頭疼的是創建 _用戶_文檔。在編寫自己的用戶文檔時,我發現大量的時間都浪費在文檔內部的復制、粘貼上。分析了該過程之后,我決定將諸如版本號、文件名等內容定義到單一源中,以此來實現這些內容的生成自動化。而且我可以運用 XML 和可擴展樣式語言(Extensible Stylesheet Language,XSL)將內容從格式化中分離出來,這樣我只要對一個樣式做一個簡單的修改就可以使文檔的觀感發生顯著的變化。
DocBook 工具已存在數年之久,它使您能夠用 XML 定義文檔,并能夠以包括 HTML 和 PDF 在內的多種格式生成文檔。DocBook 提供了一種為編寫者定義模板的模式。
清單 7 結合使用 Ant、一個 DocBook XSL 文件和 XSL Formatting Objects (XSL-FO) 來生成 PDF 格式的用戶文檔(請參閱 [參考資料](#resources)):
##### 清單 7\. 使用 Ant、DocBook 和 FO 創建 PDF
```
<target name="pdf" depends="init" description="Generates PDF files from DocBook XML">
<property name="fo.stylesheet" value="${docbook.xsl.dir}/fo/docbook.xsl" />
<xslt style="${fo.stylesheet}" extension=".fo" basedir="${src.dir}" destdir="${fo.dir}">
<classpath refid="xalan.classpath" />
<include name="${guide}.xml" />
</xslt>
<property name="fop.home" value="lib/fop-0.94" />
<taskdef name="fop" classname="org.apache.fop.tools.anttasks.Fop">
<classpath>
<fileset dir="${fop.home}/lib">
<include name="*.jar" />
</fileset>
<fileset dir="${fop.home}/build">
<include name="fop.jar" />
<include name="fop-hyph.jar" />
</fileset>
</classpath>
</taskdef>
<fop format="application/pdf" fofile="${fo.dir}/${guide}.fo"
outfile="${doc.dir}/${guide}.pdf" />
</target>
```
圖 5 展示了由清單 7 中的腳本生成的 PDF 的一部分:
##### 圖 5\. 用戶指南文檔的 PDF

由于我的全部內容都是用基于文本的 XML 定義的,所以我可以輕松地寫出令文檔發生顯著變化的腳本。此外,我可以將這些文檔做為構建過程的一部分生成,進而為定義諸如版本、定義、縮寫、文件名以及目錄之類的元素提供一個單一的標準源。
* * *
## 文檔化無需手動操作
希望閱讀本文之后,您能夠了解到可以通過有效的方法自動生成文檔。在我看來,文檔化最關鍵的地方就在于交流,而非生成文檔的過程。我向您描述的文檔化工具和技術能夠幫助您保持文檔的精確性和實效性,從而清除了文檔之所以被忽視的癥結所在 —信息過時。
- 讓開發自動化
- 讓開發自動化: 部署自動化模式,第 2 部分
- 讓開發自動化: 部署自動化模式,第 1 部分
- 讓開發自動化: 使用基于向導的安裝程序
- 讓開發自動化: 針對廣大開發人員的并行開發
- 讓開發自動化: 實現自動化數據庫遷移
- 讓開發自動化: 持續重構
- 讓開發自動化: 文檔化一鍵通
- 讓開發自動化: 利用 Ivy 管理依賴項
- 讓開發自動化: 自動負載測試
- 讓開發自動化: 使用自動化加速部署
- 讓開發自動化: 持續集成反模式
- 讓開發自動化: 斷言架構可靠性
- 讓開發自動化: 持續測試
- 讓開發自動化: 用 Eclipse 插件提高代碼質量
- 讓開發自動化: 除掉構建腳本中的氣味
- 讓開發自動化: 選擇持續集成服務器
- 讓開發自動化: 持續檢查