當我們在寫函式庫或框架的時候,通常表示這段邏輯很常用到,希望藉由抽取成函式庫或框架來重複使用,減少重造輪子、也更好維護。而身為函式庫或框架的作者,當然會希望有愈多使用者愈好,讓自己的作品能發揮更大的價值與影響力。不過現實狀況是,要吸引愈多人用,文件是最基本的條件,畢竟至少要讓別人知道怎麼用吧?
以函式庫或框架來說,文件有兩種:一種是指南的型式,比較像教學文件,以情境導向的型式,向使用者說明要怎麼使用;另一種是 API 文件,型式比較像規格說明,會明確地把函式庫或框架裡的每一個類、方式都詳細的列表,清楚說明其可接受的輸入及輸出等規格細節。兩種文件型式及用途各有不同,開發者可依情境選擇使用。指南通常都是在初學時入門上手用,主要的目標是學會常見的用法;API 文件的用法比較像目錄或食譜,通常會依照想要了解的類別及方法直接查詢其規格,不會一頁一頁地翻。
不過同樣身為開發者的我們都知道,工程師都討厭別人不寫文件,但其實自己也不喜歡寫文件。所以若文件可以在程式碼寫好的時候就自動產生,是不是就太美妙了?或者說,就算沒時間好好寫教學指南型的文件,至少也要提供 API 這種規格說明書的文件吧?
其實在程式碼裡以註解的型式描述規格,再用工具產生 API 文件的這種作法已經行之有年,各個程式語言也都多有這種工具。以 Java 來說,JavaDoc 就是標準的例子。而 Kotlin 當然也有對應的設計,寫在程式碼裡的語法就叫 KDoc,而依據 KDoc 產生 API 文件的工具就叫 Dokka。
KDoc 的在區塊標記上基本上與 JavaDoc 相同,多支援了一些 Kotlin 獨有的語法設計,並新增支援 Markdown 語法的行內標記。KDoc 將文件內容放在註解內,其以 /**
開頭並以 */
結尾,每一行註解都以 *
開頭。一般照慣例,註解的第一行文字是摘要,空一行後的第二段則是詳細描述。再空一行後才開始用 @
字元開頭來標記類別或方法的型別和說明。
以我們的 ShoppingCart
類別為例,可以標記成這樣:
/**
* ShoppingCart class
*
* A simple shopping cart class that could add product, count the number of products, sum for total price
*
* @property products A mutable list that contain all products
* @constructor Create an empty cart
*/
class ShoppingCart {
private val products = mutableListOf<Product>()
/**
* Add a [product] in shopping cart
*
* @param product
* @return unit
*/
fun add(product: Product) {
products.add(product)
}
/**
* Calculate products' price
*
* @return The sum of [products] prices
*/
fun totalPrice(): Int {
return products.sumOf { it.price }
}
/**
* Calculate the quantity of products
*
* @return The quantity of [products]
*/
fun count(): Int {
return products.count()
}
/**
* Dummy integer generator
*
* @return Random integer
*/
fun dummyInt(): Int {
return Random.nextInt()
}
/**
* Dummy boolean generator
*
* @return Random boolean
*/
fun dummyBoolean(): Boolean {
return Random.nextBoolean()
}
}
在這邊介紹幾個常用的 @
標記:
@constructor
:描述類別主要建構子@property name
:描述類別屬性,其格式為 @property 屬性名 描述
@throws class
、@exception class
:描述方法會拋出的例外@return name
:描述方法回傳值當我們用 KDoc 語法在程式碼上紀錄文件後,接著我們就可以用 Dokka 這個工具來爬取這些文件標記,然後產生可借閱覽的文件。Dokka 支援同時混合 Java 及 Kotlin 的專案,也就是說它會用 JavaDoc 來分析 Java 檔、用 KDoc 來分析 Kotlin 檔。Dokka 也支援多種格式的輸出,包括:
html
:HTML 網頁是預設的輸出格式javadoc
:輸出成 JDK 的 Javadoc 的型式,Kotlin 的類別會被轉譯成 Javagfm
:GitHub 風格的 Markdownjekyll
:Jekyll 相容的 Markdown我們接下來會示範如何產生 HTML 格式的文件。
因為 Dokka 預設就提供 CLI、Gradle、Maven 等多種使用方式,所以要在 Kotlin 專案裡安裝 Dokka 引擎很簡單,只需打開 build.gradle.kts
套用 Dokka Plugin 即可。
plugins {
// ...
id("org.jetbrains.dokka") version "1.5.30"
}
老樣子,設定好 Plugin 後別忘了 Reload,讓 IntelliJ IDEA 幫我們把 Dokka 引擎載入進 Gradle,完成後就會在 documentation 群組底下看到多了 dokkaHtml
、dokkaJavadoc
、dokkaGfm
、dokkaJekyll
等指令可以使用。
有了 Dokka Plugin 後要產生文件就變得非常簡單,直接點選 Gradle 面板裡 dokkaHtml
Task 即可!(依據輸出需求的不同可以選擇不同的格式指令)
指令跑完後,HTML 版的文件就會被產生在 ./build/dokka/html
,我們可以直接把網頁用瀏覽器打開來,就看會到像下圖這樣的文件網頁:
今天我們介紹了 KDoc 及 Dokka 這兩個跟產生文件有關的語法及文件引擎,像這樣使用文件引擎產生文件提供給使用者查閱幾乎已經是開放原始碼圈的起手式,身為開發者就算懶得寫文件,至少也要懂得如何自動產生文件,體貼使用者也是作者負責任的表現。雖然這兩個都是 Kotlin 開發生態系的工具,但同樣的概念也可以應用到不同的程式語言,讀者可以用「程式語言的名稱」+「文件引擎」等關鍵字做搜尋,應該就會找到適合自己的工具,希望看完今天的教學後對您有幫助。
當然,在本機產生文件只是整個 DevOps 流程的第一步,接下來我們就要透過 TeamCity 讓這個環節自動在 CI 流程裡發生,敬請期待!