模塊化編程的優點與實現原理概述
原創【51CTO精選譯文】本文是《Rich Client Programming: Plugging into the NetBeans Platform》(中文版譯名為《NetBeans富客戶端編程權威教程》,Sun中國技術社區推薦的NetBeans學習用書)英文版公開章節,即第二章的節選譯文,章節名稱為“模塊化編程的好處”。通過閱讀這一章節,讀者們將對模塊化編程的起源和實現原理產生初步的了解,并了解到模塊化編程的優點。有關模塊化編程的實現部分,本文著重介紹了NetBeans的情況。
分布式開發
閉門造車的軟件開發時代早已過去。在嵌入式系統之外,幾乎每一位開發者都需要依賴別人寫的類庫或框架。這種借助并復用他人提供的基礎設施、框架以及類庫的好處在于使自己能夠專注于應用本身的邏輯當中。這樣縮短了軟件開發所需要的時間。
過去的幾十年間,開源軟件的興起令類庫的復用具有雙倍的吸引力。我們現在有針對多種程序中的各種問題而誕生的現成解決方案,而獲取這些解決方案不用花一文錢。開源產品起于UNIX內核,基礎C類庫和命令行工具,并通過Web服務器和Web瀏覽器延伸至Ant,Tomcat,JUnit,Javacc等Java工具領域——而這種情況還有無限制發展的趨勢。在編寫一個現代軟件的過程中,集成工作的部分和創新的部分大致是對半分的。將可用的碎片撿起來并組合到一起是現代應用開發的主要工序。人們不再從零開始編寫一切。人們在需要HTTP服務器的時候為他們的應用選擇Apache或者Tomcat,在需要數據庫的時候選擇MySQL或PostgreSQL。應用軟件將這些零碎部件粘連起來,并加入自己的邏輯。最終的成品是功能完備的、性能好的、并且在相當短的時間內開發出來的應用軟件。
看看Linux版本是如何發行的。紅帽的Fedora,Mandriva,SUSE,還有Debian,它們所包含的應用程序其實大致上差不多,而且都是同一群人寫的。發布者不過是簡單的將它們打包,并提供“膠水”用于統一的安裝。發行商往往只編寫中央管理軟件和安裝軟件,并提供一些質量保證,以確保所有選定的組件能夠協同工作。這個過程對于Linux的普及產生了相當理想的效果。有一個例子可以證明此模型的意義,那就是Mac OS X:它其實就是個安裝了一堆蘋果插件的FreeBSD Unix。對于這樣的軟件,需要注意的一個重點就是它創建的方式采用了一種分布式開發模型。軟件的開發者和發行者可能完全不認識對方,也沒有交流過,而他們往往也并不生活在同一個地域。
這種分布式開發有如下特征。第一,應用程序(或操作系統)的源代碼不再處于某一個開發者完全的掌控之中。源代碼被散布至世界各地。毫無疑問,構建這樣的軟件與傳統那種源代碼完全在你家中的代碼庫的應用構建是完全不同的。
#t#另外我們需要了解的是,也沒有一個人對整個項目的時間表有完全的掌控。不單單是源代碼,開發者們也遍布世界各地,并以他們自己的時間表工作。這種情況并不像聽起來的那樣不尋常或不靠譜。如果你曾經為超過五十人的項目制定過時間表,那么你一定會明白,對整個項目進程擁有“完全的掌控”最多只是一個安慰自己的幻想。你隨時需要準備好拋棄某個特性,或是發布這個或那個組件的一個老版本。同樣的模式也適用于分布式開發。
每個人都有這樣一個權利:使用一個新版本或舊版本類庫的自由。
使用外部庫并使用它們組建應用程序,這意味著人們能夠花費更少的時間和精力創造更復雜的軟件。代價則是,我們需要管理這些類庫,確保它們的兼容性。這不是一個簡單的任務。但是,對于如今高度復雜系統的組建,也沒有其他既實用、性價比又高的開發模式了。
你對Java模塊化規范有何看法?歡迎到Java頻道的后院參與討論!
#p#
模塊化應用程序
針對分布式開發的挑戰,其技術解決方案就是模塊化。在一大塊緊密耦合的代碼中,每個單元都可能與其他單元進行直接的接口。而模塊化應用則正相反,它由小塊的、分散的代碼塊組成,每一塊都是獨立的。于是,這些代碼塊可以由不同的團隊進行開發,而他們都有各自的生命周期和時間表。最終的成果則可以由另一個獨立的個體,即發行者,進行集成。
51CTO編輯推薦:OSGi,成熟的Java模塊化規范
對于Java而言,將一組類庫放在Java類路徑上并運行一個應用程序在很早以前就實現了。NetBeans平臺在類庫的管理方面已經走的相當遠:它積極的參與類庫的加載過程,并強制每一個類庫都滿足其他類庫對自己的最低版本需求。這樣的類庫被稱為模塊。NetBeans模塊系統是一個運行時容器,它確保了系統在運行時的完整性。
版本控制
將應用程序分解為獨立的類庫,這帶來了一個新的挑戰——我們需要確保這些互不依賴的零件們能夠在一起工作。這個問題有多種解決方案,而最流行的一種就是版本控制。每一塊模塊化應用都有一個版本號,常用杜威十進制格式表示,比如1.34.8這種數字組合。新版本的發布帶來增加的版本號,比如1.34.10,1.35.1,或者2.0。其實仔細想來,使用增長的版本號來代表兩個版本的復雜軟件之間的不同是挺荒謬的。不過這種方法解釋起來很簡單,而且它的流行也說明了這種方法是十分可行的。
一個模塊系統的另一個特點是外部依賴的聲明。很多組件對外部條件有一定需求。比如說,一個模塊系統中的組件可能需要一個XML解析器,或者需要安裝某種數據庫驅動,或者需要某種文本編輯器或者瀏覽器才能工作。對于每一個需求,另外一個模塊可以指定其接口的特定版本號。即使對外部類庫的依賴性極低,但每一個Java程序都對Java本身有版本要求。一個真正的模塊系統可以指定理想的最低JDK版本。一個模塊可能會有JDK>=1.5,xmlparser>=3.0,webbrowser>=1.5這樣的版本需求。在運行時,啟動應用的模塊代碼的依賴條件需要被滿足,即,XML解析器在3.0版或以上,瀏覽器在1.5版或以上,如此這般。NetBeans模塊系統正是這樣的。使用依賴模式來維持模塊系統中組件之間的依賴性有一個大前提,那就是我們必須遵循一系列的規則。第一個規則是向后兼容性:如果新版本發布,那么所有在之前版本下可建立的契約也必須能夠在新版本下工作。這一點說起來很容易,但實現起來沒那么容易。第二個規則是,系統中的組件需要準確的說明它們需要什么。當一個模塊的依賴性產生改變的時候,它必須要說出來,這樣系統才能夠準確的確認這些依賴性是否被滿足。因此,如果一個模塊系統產生了對新功能的依賴性,比如一個HTML編輯器,那么你便需要定義這個新的依賴性(比如,htmleditor>=1.0)。同時如果你開始使用一個新的HTML編輯器組件的接口,而這個接口在1.7版之后才有,那么你需要更新你的依賴型需求到這個組件的1.7版本:htmleditor>=1.7。在NetBeans模塊系統中,第二個規則在實踐當中是相對容易遵循的,因為一個模塊的編譯時類路徑僅僅包括有依賴性聲明的模塊,而沒有依賴性聲明的模塊是不會被編譯的。
二級版本信息
之前我們有關版本控制方法的討論針對的是類庫的規范版本。規范版本描述了該類庫當中的公共API的一個特定快照。
某些版本的類庫會不可避免的遭遇不得不修復的bug。因此,二級版本的識別也應該與組件關聯起來,那就是這個組件的實現版本。與規范版本不同,一個實現版本往往用“Build20050611”這樣的字符串進行標注,因此只能通過等式來判定。這就提供了一個二級識別機制,這個機制可以用來決定某個特定的代碼模塊是否有必須修復的bug。我們知道,在3.1規范版本中存在的bug未必會在3.2版本或者3.1版本的其他實現版本中存在,因此,出于bug修復或某些特殊處理的需求,將實現版本與類庫關聯起來是十分有用的。
依賴性管理
#t#版本和依賴性系統需要一個管理器,以確保這個系統中的每一部分的需求都得到滿足。這樣的一個管理器可以檢查每一塊組件的安裝時間,保持系統的一致性——Linux發行版的RPM或Debian包就是這樣工作的。描述依賴性的元數據在運行時非常重要。有些元數據可以讓應用進行動態類庫升級而無需關閉應用。元數據還能決定一個模塊動態加載的依賴性是否滿足。如果沒有滿足,元數據將向用戶解釋可能會遇到的問題。
NetBeans IDE是一個模塊化應用。它的模塊——即組成它的那些類庫——在運行時被查知并加載。它們可以安裝小塊小塊的功能,如組件,菜單項或服務等;它們可以在啟動時運行代碼,進行程序初始化;它們可以通過聲明式注冊機制把平臺和IDE提供的各個部分注冊為服務并在需要時將其初始化。NetBeans模塊系統使用安裝組件的聲明依賴性為每個模塊的類路徑進行父類路徑配置,并在模塊加載類的時候決定在哪些JAR文件當中搜索。這樣確保了模塊類路徑當中不存在任何不屬于其依賴樹的模塊JAR,并強制確保每個組件都有聲明式依賴性。一個沒有聲明依賴性的模塊將無法從其他模塊中呼叫代碼,而當依賴性沒有被全部滿足時,其他模塊將不會加載。
原文:The Benefits of Modular Programming
作者:Tim Boudreau,Jaroslav (Yarda) Tulach和Geertjan Wielenga