perlmodstyle - Perl 模組樣式指南
本文件試圖描述 Perl 社群撰寫 Perl 模組的「最佳實務」。它擴充了 perlstyle 中的建議,在閱讀本文件之前,應將其視為必讀文件。
雖然本文件旨在對所有模組作者都有用,但它特別針對希望在 CPAN 上發布模組的作者。
重點在於模組使用者可見的樣式元素,而不是只有模組開發人員才能看到的那些部分。然而,本文件中提出的許多準則可以推廣並成功應用於模組的內部。
此文件與 perlnewmod 不同之處在於,它是一個風格指南,而不是一個關於如何建立 CPAN 模組的教學課程。它提供了一個檢查清單,可以根據此清單來比較模組,以確定它們是否符合最佳實務,而不一定詳細說明如何達成此目標。
此文件中的所有建議都是從與經驗豐富的 CPAN 作者和使用者廣泛討論中收集而來的。這裡提供的每則建議都是過去錯誤的結果。這些資訊有助於您避免犯下相同的錯誤,以及避免勢必需要修正這些錯誤的額外工作。
此文件的首節提供了一個分項檢查清單;後續各節提供清單中各項目的更詳細說明。最後一節「常見陷阱」說明 CPAN 作者最常犯的一些錯誤。
有關此檢查清單中各項目的更多詳細資訊,請參閱下方。
不要重複發明輪子
盡可能修補、延伸或建立現有模組的子類別
專注做好一件事
選擇一個適當的名稱
發布之前先取得回饋
API 應易於一般程式設計師理解
簡單的任務使用簡單的方法
將功能與輸出分開
子常式或方法的命名應一致
當有兩個以上的參數時,請使用命名參數(雜湊或雜湊參考)
確保您的模組在 use strict
和 -w
下運作
穩定的模組應維持向後相容性
使用 POD 編寫文件
說明目的、範圍和目標應用程式
說明每個公開存取的方法或子常式,包括參數和回傳值
在您的文件中提供使用範例
提供 README 檔案,並可能也提供版本說明、變更日誌等
提供進一步資訊的連結(網址、電子郵件)
在 Makefile.PL 或 Build.PL 中指定先決條件
使用 use
指定 Perl 版本需求
在您的模組中包含測試
選擇一個明智且一致的版本編號方案(X.YY 是常見的 Perl 模組編號方案)
無論多麼微小,每次變更都增加版本號碼
使用「make dist」封裝模組
選擇一個適當的授權(GPL/Artistic 是良好的預設值)
試著不要在不先花點時間思考的情況下,就急著開始開發您的模組。事先多加思考,可以為您在之後節省大量的精力。
你甚至可能不需要撰寫模組。檢查是否已在 Perl 中完成,除非你有充分的理由,否則請避免重複發明輪子。
尋找預先存在的模組的絕佳地點包括 MetaCPAN,並在 module-authors@perl.org
(https://lists.perl.org/list/module-authors.html) 上詢問。
如果現有的模組幾乎符合你的需求,請考慮撰寫修補程式、撰寫子類別,或以其他方式擴充現有模組,而不是重新撰寫它。
冒著陳述顯而易見的事實的風險,模組旨在成為模組化的。Perl 開發人員應該能夠使用模組來組合其應用程式的建構區塊。然而,重要的是區塊必須是正確的形狀,而且開發人員不應在只需要小區塊時使用大區塊。
你的模組應該有一個明確定義的範圍,不超過一個句子。你的模組可以細分為相關模組的系列嗎?
不良範例
「FooBar.pm 提供 FOO 協定的實作和相關的 BAR 標準。」
良好範例
「Foo.pm 提供 FOO 協定的實作。Bar.pm 實作相關的 BAR 協定。」
這表示如果開發人員只需要一個模組來符合 BAR 標準,他們就不應該被迫也安裝 FOO 的函式庫。
請務必在早期為你的模組選擇一個適當的名稱。這將有助於人們找到並記住你的模組,並讓使用你的模組進行程式設計更直觀。
在為你的模組命名時,請考慮下列事項
具描述性(即準確描述模組的目的)。
與現有模組保持一致。
反映模組的功能,而不是實作。
避免建立新的頂層階層,特別是如果已經存在你可以放置模組的適當階層。
如果你以前從未將模組上傳到 CPAN(即使你已經上傳過),強烈建議你從已經熟悉模組應用領域和 CPAN 命名系統的人員那裡取得回饋。類似模組或名稱相似的模組的作者可能是開始的好地方,例如 Perl Monks 等社群網站。
模組設計和編碼的考量因素
您的模組可能是物件導向 (OO) 或不是,或者它可能同時具備兩種介面的可用性。每種技術都有優缺點,在設計您的 API 時應予以考量。
在《Perl 最佳實務》(版權 2004 年,由 O'Reilly Media, Inc. 出版)中,Damian Conway 提供了一份準則清單,供您在決定 OO 是否適合您的問題時使用
所設計的系統很大,或可能會變大。
資料可以彙總成明顯的結構,特別是如果每個彙總中都有大量的資料。
各種資料彙總形成一個自然的階層,有助於使用繼承和多型。
您有一段資料,對其套用許多不同的運算。
您需要對相關資料類型執行相同的通用運算,但會根據運算套用到資料的特定類型而有細微的變化。
您很可能會在稍後新增新的資料類型。
資料片段之間的典型互動最適合由運算子表示。
系統各組成元件的實作很可能會隨著時間而改變。
系統設計已經是物件導向的。
大量的其他程式設計師將會使用您的程式碼模組。
仔細思考 OO 是否適合您的模組。免費的物件導向會導致複雜的 API,對於一般的模組使用者來說,很難理解或使用。
您的介面應該讓一般的 Perl 程式設計師可以理解。下列準則可以幫助您判斷您的 API 是否足夠直接
擁有大量的簡單常式會比少數幾個大型常式來得好。如果您的常式會根據其引數大幅改變其行為,這表示您應該要有兩個(或更多)個獨立的常式。
以最通用的形式回傳您的結果,並允許使用者選擇如何使用它們。最通用的形式通常是 Perl 資料結構,然後可使用它來產生文字報告、HTML、XML、資料庫查詢,或任何其他使用者所需的東西。
如果您的常式會反覆處理某種類型的清單(例如檔案清單或資料庫中的記錄),您可以考慮提供一個回呼,以便使用者可以依序處理清單中的每個元素。File::Find 提供了一個範例,其語法為 find(\&wanted, $dir)
。
不要要求每個模組使用者都跳過相同的步驟才能達成一個簡單的結果。您隨時可以包含選用參數或常式,以進行更複雜或非標準的行為。如果大多數使用者在開始使用您的模組時,必須輸入幾行幾乎相同的程式碼,這表示您應該將該行為設為預設值。另一個您應該使用預設值的良好指標是,如果大多數使用者都使用相同的引數呼叫您的常式。
您的命名應一致。例如,最好有
display_day();
display_week();
display_year();
而不是
display_day();
week_display();
show_year();
這同樣適用於方法名稱、參數名稱,以及對使用者可見的任何其他東西(以及大多數不可見的東西!)。
使用命名參數。使用像這樣的雜湊比較容易
$obj->do_something(
name => "wibble",
type => "text",
size => 1024,
);
... 而不是像這樣有一長串未命名的參數
$obj->do_something("wibble", "text", 1024);
雖然引數清單可能對一個、兩個甚至三個引數運作良好,但任何更多的引數都讓模組使用者難以記住,也讓模組作者難以管理。如果您想新增一個新參數,您必須將它新增到清單的結尾以維持向後相容性,而這可能會讓您的清單順序變得不直覺。此外,如果許多元素可能是未定義的,您可能會看到以下不吸引人的方法呼叫
$obj->do_something(undef, undef, undef, undef, undef, 1024);
為具有預設值的參數提供明智的預設值。不要讓您的使用者指定幾乎總是相同的參數。
是否將參數傳遞至雜湊或雜湊參考的問題,在很大程度上取決於個人風格。
使用以連字號開頭(-name
)或全部大寫(NAME
)的雜湊鍵,是較舊版本的 Perl 的遺留物,其中普通的小寫字串無法由 =>
算子正確處理。儘管某些模組基於歷史原因或個人風格而保留大寫或連字號參數鍵,但大多數新模組都應使用簡單的小寫鍵。無論您選擇哪一種,都要保持一致!
您的模組應在嚴謹實用範例中成功執行,並且應在不產生任何警告的情況下執行。您的模組還應在適當的情況下處理污染檢查,儘管在許多情況下這可能會造成困難。
「穩定」的模組不應破壞向後相容性,除非至少有很長的過渡階段和版本號的重大變更。
當您的模組遇到錯誤時,它應執行下列一項或多項操作
傳回未定義的值。
設定 $Module::errstr
或類似的(errstr
是 DBI 和其他熱門模組使用的常見名稱;如果您選擇其他名稱,請務必清楚地記錄它)。
warn()
或 carp()
將訊息傳遞至 STDERR。
僅在您的模組絕對無法找出該怎麼做時才 croak()
。(croak()
是 die()
的更好版本,可用於模組中,它會從呼叫者的角度報告其錯誤。有關 croak()
、carp()
和其他有用常式的詳細資訊,請參閱 Carp。)
作為上述方法的替代方案,您可能更喜歡使用 Error 模組引發例外。
可設定的錯誤處理對您的使用者來說非常有用。考慮提供警告和偵錯訊息的層級選擇、將訊息傳送到另一個檔案的選項、指定錯誤處理常式的途徑,或其他此類功能。請務必將所有這些選項預設為最常見的用法。
您的模組應包含針對 Perl 開發人員的說明文件。您應使用 Perl 的「純舊說明文件」(POD)作為您的通用技術說明文件,儘管您可能希望以其他格式撰寫其他說明文件(白皮書、教學課程等)。您需要涵蓋下列主題
模組常見用途的概要
模組的目的、範圍和目標應用程式
每個公開存取的方法或子常式的用途,包括參數和回傳值
使用範例
進一步資訊來源
作者/維護者的電子郵件聯絡地址
Perl 模組文件中的詳細程度通常從較不詳細到較詳細。您的 SYNOPSIS 區段應包含一個最小的使用範例(可能僅一行程式碼;略過不尋常的使用案例或大多數使用者不需要的任何內容);DESCRIPTION 應廣泛描述您的模組,通常僅需幾個段落;模組常式或方法的更多詳細資訊、冗長的程式碼範例或其他深入的資料應在後續的區段中提供。
理想情況下,稍微熟悉您的模組的人應該能夠在不按「向下捲動」的情況下更新他們的記憶。隨著讀者繼續瀏覽文件,他們應獲得越來越多的知識。
建議的 Perl 模組文件區段順序為
名稱
SYNOPSIS
DESCRIPTION
一個或多個區段或小節,提供可用方法和常式以及任何其他相關資訊的更多詳細資訊。
BUGS/CAVEATS/等
作者
另請參閱
COPYRIGHT 和 LICENSE
將您的文件放在它所記錄的程式碼附近(「內嵌」文件)。在給定方法的子常式上方包含 POD。這使得更容易保持文件是最新的,並避免必須兩次記錄每個程式碼片段(一次在 POD 中,一次在註解中)。
您的模組還應包含一個 README 檔案,描述模組並提供進一步資訊的指標(網站、作者電子郵件)。
應包含一個 INSTALL 檔案,其中應包含簡單的安裝說明。當使用 ExtUtils::MakeMaker 時,這通常會是
當使用 Module::Build 時,這通常會是
應為每個軟體版本製作發行說明或變更日誌,描述對模組的使用者可見變更,並以與使用者相關的術語說明。
除非您有充分的理由使用其他格式(例如,公司內部使用的格式),慣例是將您的變更日誌檔案命名為 Changes
,並遵循 CPAN::Changes::Spec 中所述的簡單格式。
版本號碼應至少表示主要和次要版本,並可能表示次次要版本。主要版本是其中大部分功能已變更,或其中新增主要新功能的版本。次要版本是其中新增或變更少量功能的版本。次次要版本號碼通常用於不影響功能的變更,例如文件補丁程式。
最常見的 CPAN 版本編號配置如下
1.00, 1.10, 1.11, 1.20, 1.30, 1.31, 1.32
正確的 CPAN 版本號碼是小數點後至少有 2 位數的浮點數。您可以使用下列方式測試是否符合 CPAN
perl -MExtUtils::MakeMaker -le 'print MM->parse_version(shift)' \
'Foo.pm'
如果您要發布模組的「測試版」或「開發版」,但不想讓 CPAN.pm 將其列為最新版本,請在一般版本號碼後使用「_」,後接至少 2 位數,例如 1.20_01。如果您這樣做,建議使用下列慣用語法
our $VERSION = "1.12_01"; # so CPAN distribution will have
# right filename
our $XS_VERSION = $VERSION; # only needed if you have XS code
$VERSION = eval $VERSION; # so "use Module 0.002" won't warn on
# underscore
使用此技巧,MakeMaker 將只讀取第一行,因此會讀取底線,而 Perl 詮釋器會評估 $VERSION 並將字串轉換為數字。稍後將 $VERSION 視為數字的運算,就能夠這樣做,而不會引發關於 $VERSION 不是數字的警告。
切勿發布任何內容(即使是一字的文件補丁程式),而不增加數字。即使是一字的文件補丁程式,也應導致次次要層級的版本變更。
一旦選定,堅持您的版本配置非常重要,不要減少數字位數。這是因為「下游」封裝程式,例如 FreeBSD 埠系統,會以各種方式詮釋版本號碼。如果您變更版本配置中的數字位數,可能會混淆這些系統,讓它們混淆模組的版本順序,這顯然很糟糕。
模組作者應仔細考慮是否依賴其他模組,以及依賴哪些模組。
最重要的是,選擇盡可能穩定的模組。依偏好順序
核心 Perl 模組
穩定的 CPAN 模組
不穩定的 CPAN 模組
無法從 CPAN 取得的模組
在 Makefile.PL 或 Build.PL 的先決條件中,指定其他 Perl 模組的版本需求。
務必在 Makefile.PL 或 Build.PL 中指定 Perl 版本需求,並使用 require 5.6.1
或類似的指令。有關詳細資訊,請參閱 use VERSION
的文件。
在發行前應測試所有模組(使用「make disttest」),而且安裝模組的人也應該可以使用測試(使用「make test」)。對於 Module::Build,您會使用 make test
等效的 perl Build test
。
這些測試的重要性與模組聲稱的穩定性成正比。宣稱穩定或希望廣泛使用的模組,應遵守盡可能嚴格的測試制度。
有助於撰寫測試(對您的開發流程或時間影響最小)的有用模組包括 Test::Simple、Carp::Assert 和 Test::Inline。對於更精密的測試套件,則有 Test::More 和 Test::MockObject。
應使用標準封裝工具之一封裝模組。目前您可以在 ExtUtils::MakeMaker 和更具平台獨立性的 Module::Build 之間進行選擇,讓模組能夠以一致的方式安裝。使用 ExtUtils::MakeMaker 時,您可以使用「make dist」建立您的套件。有工具可以協助您以符合 MakeMaker 的方式建立模組。這些工具包括 ExtUtils::ModuleMaker 和 h2xs。另請參閱 perlnewmod。
請確定您的模組有授權,且其全文包含在發行版中(除非它是常見的授權,且授權條款不要求您包含它)。
如果您不知道要使用哪種授權,建議採用 GPL 和 Artistic 授權(與 Perl 本身相同)的雙重授權。請參閱 perlgpl 和 perlartistic。
CPAN 已為特定應用程式空間提供了非常完善的服務。範例包括範本系統、日期和時間模組,還有許多其他範例。雖然撰寫這些事物的版本是種慣例,但請仔細考慮 Perl 世界是否真的需要你發布它。
你的模組將會是開發人員工具包的一部分。它本身不會形成完整的工具包。在你的程式碼變成單一系統,而不是一組模組化建構區塊之前,很容易會加入額外的功能。
不要陷入為錯誤的受眾撰寫文件的陷阱。你的主要受眾是對模組應用程式領域至少有中等程度了解的經驗豐富的開發人員,他們剛剛下載你的模組,並希望盡快開始使用它。
教學課程、終端使用者文件、研究論文、常見問題解答等不適合放在模組的主要說明文件中。如果你真的想撰寫這些內容,請將它們包含為子文件,例如 My::Module::Tutorial
或 My::Module::FAQ
,並在主要說明文件的另請參閱部分提供連結。
Perl 一般樣式指南
如何建立新的模組
POD 說明文件
驗證你的 POD 是否正確
Test::Simple、Test::Inline、Carp::Assert、Test::More、Test::MockObject
Perl 作者上傳伺服器。包含模組作者資訊的連結。
Kirrily "Skud" Robert <skud@cpan.org>