欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

前車(chē)之覆,后車(chē)之鑒——開(kāi)源項(xiàng)目經(jīng)驗(yàn)談

系統(tǒng) 1777 0

前車(chē)之覆,后車(chē)之鑒

——開(kāi)源項(xiàng)目經(jīng)驗(yàn)談

(本文發(fā)表于《程序員》2005年第2期)

隨著開(kāi)源文化的日益普及,“參與開(kāi)源”似乎也變成了一種時(shí)尚。一時(shí)間,似乎大家都樂(lè)于把自己的代碼拿出來(lái)分享了。就在新年前夕,我的一位老朋友、一位向來(lái)對(duì)開(kāi)源嗤之以鼻的
J2EE 架構(gòu)師竟然也發(fā)布了一個(gè)開(kāi)源的 J2EE 應(yīng)用框架(姑且稱(chēng)之為“ X 框架”),不得不令我驚嘆開(kāi)源文化的影響力之強(qiáng)大。

可惜開(kāi)源并非免費(fèi)的午餐,把源碼公開(kāi)就意味著要承受眾目睽睽的審視。僅僅幾天之后,國(guó)內(nèi)幾位資深的 J2EE 架構(gòu)師就得出一個(gè)結(jié)論:細(xì)看之下, X 框架不管從哪個(gè)角度都只能算一個(gè)失敗的開(kāi)源項(xiàng)目。究竟是什么原因讓一個(gè)良好的愿望最終只能得到一個(gè)失敗的結(jié)果?本文便以 X 框架為例,點(diǎn)評(píng)初涉開(kāi)源的項(xiàng)目領(lǐng)導(dǎo)者常犯的一些錯(cuò)誤,指出投身開(kāi)源應(yīng)當(dāng)遵循的一些原則,為后來(lái)的開(kāi)源愛(ài)好者掃清些許障礙。

成熟度

打開(kāi) X 框架在 SourceForge 的項(xiàng)目站點(diǎn),我們立刻可以看到:在“ Development Status ”一欄赫然寫(xiě)著“ 5 – Production/Stable ”。也就是說(shuō),作者認(rèn)為 X 框架已經(jīng)成熟穩(wěn)定,可以交付用戶(hù)使用。那么,現(xiàn)在對(duì)其進(jìn)行評(píng)估便不應(yīng)該有為時(shí)過(guò)早之嫌。可是, X 框架真的已經(jīng)做好準(zhǔn)備了嗎?

打開(kāi)從 SourceForge 下載的 X 框架的源碼包,筆者不禁大吃一驚:壓縮包里真的 只有源碼 ——編譯、運(yùn)行整個(gè)項(xiàng)目所需的庫(kù)文件全都不在其中。從作者自己的論壇得知,該項(xiàng)目需要依賴(lài) JBoss 、 JDOM 、 Castor 、 Hibernate 等諸多開(kāi)源項(xiàng)目,筆者只好自己動(dòng)手下載了這些項(xiàng)目,好一番折騰總算是在 Eclipse 中成功編譯了整個(gè)項(xiàng)目。

不需要對(duì)開(kāi)源文化有多么深刻的了解,只要曾經(jīng)用過(guò)一些主流的開(kāi)源產(chǎn)品,你就應(yīng)該知道:一個(gè)開(kāi)源軟件至少應(yīng)該同時(shí)提供源碼發(fā)布包和二進(jìn)制發(fā)布包,源碼包中至少應(yīng)該有所有必需的依賴(lài)庫(kù)文件(或者把依賴(lài)庫(kù)單獨(dú)打包發(fā)布)、完整的單元測(cè)試用例(對(duì)于 Java 項(xiàng)目通常是 Junit 測(cè)試套件)、以及執(zhí)行編譯構(gòu)建的腳本(對(duì)于 Java 項(xiàng)目通常是 Ant 腳本或者 Maven 腳本),但這些內(nèi)容在 X 框架的發(fā)布包中全都不見(jiàn)蹤影。用戶(hù)如果想要使用這個(gè)框架,就必須像筆者一樣手工下載所有的依賴(lài)庫(kù),然后手工完成編譯和構(gòu)建,而且構(gòu)建完成之后也無(wú)從知曉其中是否有錯(cuò)誤存在(因?yàn)闆](méi)有單元測(cè)試)。這樣的發(fā)布形式,算得上是“ Production/Stable ”嗎?

開(kāi)源必讀:便捷構(gòu)建

開(kāi)源軟件應(yīng)該提供最便捷的構(gòu)建方式,讓用戶(hù)可以只輸入一條命令就完成整個(gè)項(xiàng)目的編譯、構(gòu)建和測(cè)試,并得到可運(yùn)行的二進(jìn)制程序。對(duì)于 Java 項(xiàng)目,這通常意味著提供完整的 JUnit 測(cè)試套件和 Ant 腳本。你的潛在用戶(hù)可能會(huì)在一天之內(nèi)試用所有類(lèi)似的開(kāi)源軟件,如果一個(gè)軟件需要他用半天時(shí)間才能完成構(gòu)建、而且還無(wú)從驗(yàn)證正確性、無(wú)從著手編寫(xiě)他自己的測(cè)試用例,這個(gè)軟件很可能在第一時(shí)間被扔到墻角。

SourceForge 的項(xiàng)目頁(yè)面可以看到, X 框架的授權(quán)協(xié)議是 Apache License V2.0 APL )。然而在它的發(fā)布包中,筆者沒(méi)有看到任何形式的正式授權(quán)協(xié)議文本。眾所周知, SourceForge 的項(xiàng)目描述是可以隨時(shí)修改的( X 框架本身的授權(quán)協(xié)議就曾經(jīng)是 GPL ),如果發(fā)布包中沒(méi)有一份正式的授權(quán)協(xié)議文本,一旦作者修改了 SourceForge 的項(xiàng)目描述,用戶(hù)又該到哪里去尋找證據(jù)支持自己的合法使用呢?

X 框架的源碼中,大部分源文件在開(kāi)始處加上了 APL 的授權(quán)聲明,但有一部分源碼很是令人擔(dān)心。例如 UtilCache 這個(gè)類(lèi),開(kāi)始處沒(méi)有任何授權(quán)聲明,而 JavaDoc 中則這樣聲明作者信息:

@author ???? <a href="mailto:jonesde@ ofbiz.org ">David E. Jones</a>

也就是說(shuō),這個(gè)類(lèi)的源碼來(lái)自另一個(gè)開(kāi)源項(xiàng)目 Ofbiz 。值得一提的是, Ofbiz 一直是“商業(yè)開(kāi)源”的倡導(dǎo)者,它的授權(quán)協(xié)議相當(dāng)嚴(yán)格。凡是使用 Ofbiz 源碼,必須將它的授權(quán)協(xié)議一并全文復(fù)制。像 X 框架這樣復(fù)制 Ofbiz 源碼、卻刪掉了授權(quán)協(xié)議的行為,實(shí)際上已經(jīng)構(gòu)成了對(duì) Ofbiz 的侵權(quán)。

另外,作者打包用的壓縮格式是 RAR ,而這個(gè)壓縮格式對(duì)于商業(yè)用戶(hù)是收費(fèi)的。對(duì)于一個(gè)希望在商業(yè)項(xiàng)目中應(yīng)用的框架項(xiàng)目來(lái)說(shuō),選擇這樣一個(gè)壓縮格式實(shí)在算不得明智。而且筆者在源碼包中還看到了好幾個(gè) .jbx 文件,這是 JBuilder 的項(xiàng)目描述文件。把這些 JBuilder 專(zhuān)用的文件放在源碼包中,又怎能讓那些買(mǎi)不起或是不想買(mǎi) JBuilder 的用戶(hù)放心呢?更何況,出于朋友的關(guān)心,筆者還不得不擔(dān)心 X 框架的作者是否會(huì)收到 Borland 公司的律師信呢。

開(kāi)源必讀:授權(quán)先行

在啟動(dòng)一個(gè)開(kāi)源項(xiàng)目時(shí),第一件大事就是要確定自己的授權(quán)協(xié)議,并在最醒目的地方用最正式的方式向所有人聲明——當(dāng)然,在此之前你必須首先了解各種開(kāi)源授權(quán)協(xié)議。譬如說(shuō), GPL Linux 采用的授權(quán)協(xié)議)要求在軟件之上的擴(kuò)展和衍生也必須繼承 GPL ,因此這種協(xié)議對(duì)軟件的商業(yè)化應(yīng)用很不友好;相反, APL 則允許用戶(hù)將軟件的擴(kuò)展產(chǎn)物私有化,便于商業(yè)應(yīng)用,卻不利于開(kāi)發(fā)者社群的發(fā)展。作為一個(gè)開(kāi)源項(xiàng)目的領(lǐng)導(dǎo)者,對(duì)于各種授權(quán)協(xié)議的利弊是不可不知的。

除了源碼本身的授權(quán)協(xié)議之外,軟件需要使用的類(lèi)庫(kù)、 IDE 、解壓工具等等都需要考慮授權(quán)問(wèn)題。開(kāi)源絕對(duì)不僅僅意味著“免費(fèi)使用”,開(kāi)源社群的人們有著更加強(qiáng)烈的版權(quán)意識(shí)和法律意識(shí)。如果你的開(kāi)源軟件會(huì)給用戶(hù)帶來(lái)潛在的法律麻煩,它離著被拋棄的命運(yùn)也就不遠(yuǎn)了。

可以看到,不管從法律的角度還是從發(fā)布形式的角度, X 框架都遠(yuǎn)夠不上“ Production/Stable ”的水準(zhǔn)——說(shuō)實(shí)在的,以它的成熟度,頂多只能算是一個(gè)尚未計(jì)劃周全的開(kāi)源項(xiàng)目。雖然作者在自己的網(wǎng)站上大肆宣傳,但作為一個(gè)潛在的用戶(hù),我不得不冷靜地說(shuō):即便 X 框架的技術(shù)真的能夠吸引我,但它遠(yuǎn)未成熟的項(xiàng)目形態(tài)決定了它根本無(wú)法在任何有實(shí)際意義的項(xiàng)目中運(yùn)用。要讓商業(yè)用戶(hù)對(duì)它產(chǎn)生興趣,作者需要做的工作還很多。

我剛才說(shuō)“即便 X 框架的技術(shù)真的能夠吸引我”,這算得上是一個(gè)合理的假設(shè)嗎?下面,就讓我們進(jìn)入這個(gè)被作者寄予厚望的框架內(nèi)部,看看它的技術(shù)水平吧。

整體架構(gòu)

X 框架的宣傳頁(yè)面上,我們看到了這樣的宣傳詞:

X 框架解決了以往 J2EE 開(kāi)發(fā)存在的諸多問(wèn)題: EJB 難用、 J2EE 層次復(fù)雜、 DTO 太亂、 Struts 繞人、緩存難做性能低等。 X 框架是 Aop/Ico [ 注:應(yīng)為“ IoC ”,此處疑似筆誤 ] 的實(shí)現(xiàn),優(yōu)異的緩存性能是其優(yōu)點(diǎn)。

下面是 X 框架的整體架構(gòu)圖:

前車(chē)之覆,后車(chē)之鑒——開(kāi)源項(xiàng)目經(jīng)驗(yàn)談

可以看到,在作者推薦的架構(gòu)中, EJB 被作為業(yè)務(wù)邏輯實(shí)現(xiàn)的場(chǎng)所,而 POJO 被用于實(shí)現(xiàn) Fa?ade 。這是一個(gè)好的技術(shù)架構(gòu)嗎?筆者曾在一篇 Blog 中這樣評(píng)價(jià)它 [1]

讓我們先回想一下,使用 EJB 的理由是什么?常見(jiàn)的答案有:可分布的業(yè)務(wù)對(duì)象;聲明性的基礎(chǔ)設(shè)施服務(wù)(例如事務(wù)管理)。那么,如果在 EJB 的上面再加上一 POJO Fa?ade ,顯然你不能再使用 EJB 的基礎(chǔ)設(shè)施了,因?yàn)橥暾臉I(yè)務(wù)操作(也就是事務(wù)邊界)將位于 POJO Fa?ade 的方法這里,所以你必須重新 —— 以聲明性的方式 —— 實(shí)現(xiàn)事務(wù)管理、安全性管理、 remoting 、緩存等基礎(chǔ)設(shè)施服務(wù)。換句話(huà)說(shuō),你失去了 session bean 的一半好處。另一方面,“可分布的業(yè)務(wù)對(duì)象”也不復(fù)存在,因?yàn)? POJO 本身是不能 —— EJB 那樣 —— 分布的,這樣你又失去了 session bean 的另一半好處。

繼續(xù)回想,使用基于 POJO 的輕量級(jí)架構(gòu)的理由是什么?常見(jiàn)的答案有:易于測(cè)試;便于移植;“開(kāi)發(fā) - 發(fā)布”周期短。而如果僅僅把 POJO 作為一層 Fa?ade ,把業(yè)務(wù)邏輯放在下面的 EJB ,那么你仍然無(wú)法輕易地測(cè)試業(yè)務(wù)邏輯,移植自然也無(wú)從談起了,并且每次修改 EJB 之后必須忍受漫長(zhǎng)的發(fā)布周期。 即便是僅僅把 EJB 作為 O/R mapping ,而不是業(yè)務(wù)邏輯的居所,你最多只能通過(guò) DAO 封裝獲得比較好的業(yè)務(wù)可測(cè)性,但“修改 - 發(fā)布”的周期仍然很長(zhǎng),因?yàn)槿匀挥? entity bean 存在。也就是說(shuō),即使是往最好的方面來(lái)說(shuō),這個(gè)架構(gòu)至少損失了輕量級(jí)架構(gòu)的一半優(yōu)點(diǎn)。

作為一個(gè)總結(jié), X 框架即便是在使用得最恰當(dāng)?shù)那闆r下,它仍然不具備輕量級(jí)架構(gòu)的全部?jī)?yōu)點(diǎn),至少會(huì)對(duì)小步前進(jìn)的敏捷開(kāi)發(fā)造成損害(因?yàn)? EJB 的存在),并且沒(méi)有 Spring 框架已經(jīng)實(shí)現(xiàn)的基礎(chǔ)設(shè)施(例如事務(wù)管理、 remoting 等),必須重新發(fā)明這些輪子;另一方面,它也不具備 EJB 的任何優(yōu)點(diǎn), EJB 的聲明性基礎(chǔ)設(shè)施、可分布業(yè)務(wù)對(duì)象等能力它全都不能利用。因此,可以簡(jiǎn)單地總結(jié)說(shuō), X 框架是一個(gè)這樣的架構(gòu): 它結(jié)合了 EJB 和輕量級(jí)架構(gòu)兩者各自的短處,卻拋棄了兩者各自的長(zhǎng)處

在不得不使用 EJB 的時(shí)候,一種常見(jiàn)的架構(gòu)模式是:用 session bean 作為 Fa?ade ,用 POJO 實(shí)現(xiàn)可移植、可測(cè)試的業(yè)務(wù)邏輯。這種模式可以結(jié)合 EJB POJO 兩者的長(zhǎng)處。而 X 框架推薦的架構(gòu)模式,雖然乍看起來(lái)也是依葫蘆畫(huà)瓢,效果卻恰恰相反,正可謂是“取其糟粕、去其精華”。

開(kāi)源必讀:架構(gòu)必須正確

在開(kāi)源軟件的初始階段,功能可以不完善,代碼可以不漂亮,但架構(gòu)思路必須是正確的。即使你沒(méi)有完美的實(shí)現(xiàn),參與開(kāi)源的其他人可以幫助你;但如果架構(gòu)思路有嚴(yán)重失誤,誰(shuí)都幫不了你。從近兩年容器項(xiàng)目的更迭就可以看出端倪: PicoContainer 本身只有 20 個(gè)類(lèi)、數(shù)百行代碼,但它有清晰而優(yōu)雅的架構(gòu),因此有很多人為它貢獻(xiàn)外圍的功能; Avalon 容器盡管提供了完備的功能,但架構(gòu)的落伍迫使 Apache 基金會(huì)只能將其全盤(pán)廢棄。

所以如果你有志于啟動(dòng)一個(gè)開(kāi)源項(xiàng)目(尤其是框架性的項(xiàng)目),務(wù)必先把架構(gòu)思路拿出來(lái)給整個(gè)社群討論。只要大家都認(rèn)可你的架構(gòu),你就有機(jī)會(huì)得到很多的幫助;反之,恐怕你就只能得到無(wú)盡的嘲諷了。

技術(shù)細(xì)節(jié)

既然整體架構(gòu)已經(jīng)無(wú)甚可取之處,那么 X 框架的實(shí)現(xiàn)是否又像它所宣稱(chēng)的那樣,能夠解決諸多問(wèn)題呢?既然 X 框架號(hào)稱(chēng)是“ AOP/IoC 的實(shí)現(xiàn)”,我們就選中這兩項(xiàng)技術(shù),看看它們?cè)? X 框架中的實(shí)現(xiàn)和應(yīng)用情況。

IoC

X 框架宣稱(chēng)自己是一個(gè)“基于 IoC 的應(yīng)用框架”。按照定義,框架本身就具有“業(yè)務(wù)代碼不調(diào)用框架,框架調(diào)用業(yè)務(wù)代碼”的特性,因此從廣義上來(lái)說(shuō),所有的框架必然是基于 IoC 模式的。所以,在框架這里,“基于 IoC ”通常是特指“對(duì)象依賴(lài)關(guān)系的管理和組裝基于 IoC ”,也就是 Martin Fowler 所說(shuō)的 Dependency Injection 模式 [2] :由容器統(tǒng)一管理組件的創(chuàng)建和組裝,組件本身不包含依賴(lài)查找的邏輯。那么, X 框架實(shí)現(xiàn) IoC 的情況又如何呢?

我們很快找到了 ContainerWrapper 這個(gè)接口,其中指定了一個(gè) POJO 容器核心應(yīng)該具備的主要功能:

public interface ContainerWrapper {

? public void registerChild(String name);

? public void register(String name, Class className);

? public void register(String name, Class className, Parameter[] parameters);

? public void register(String name, Object instance);

? public void start();

? public void stop();

? public Collection getAllInstances();

? public Object lookup(String name);

}

在這個(gè)接口的默認(rèn)實(shí)現(xiàn) DefaultContainerWrapper 中,這些功能被轉(zhuǎn)發(fā)給 PicoContainer 的對(duì)應(yīng)方法。也就是說(shuō), X 框架本身并沒(méi)有實(shí)現(xiàn)組件容器的功能,這部分功能將被轉(zhuǎn)發(fā)給其他的 IoC 組件容器(例如 PicoContainer 、 Spring HiveMind 等)來(lái)實(shí)現(xiàn)。在 ContainerWrapper 接口的注釋中,我們看到了一句頗可玩味的話(huà):

/**

? * 封裝了 Container ,解耦具體應(yīng)用系統(tǒng)和 PicoContainer 關(guān)系。

了解 IoC 容器的讀者應(yīng)該知道,在使用 PicoContainer Spring 等容器時(shí),絕大多數(shù) POJO 組件并不需要對(duì)容器有任何依賴(lài):它們只需要是最普通的 JavaBean ,只需要實(shí)現(xiàn)自己的業(yè)務(wù)接口。既然對(duì)容器沒(méi)有依賴(lài),自然也不需要“解耦”。至于極少數(shù)需要獲得生命周期回調(diào)、因此不得不依賴(lài)容器的組件,讓它們依賴(lài) PicoContainer 和依賴(lài) X 框架難道有什么區(qū)別嗎?更何況, PicoContainer 是一個(gè)比 X 框架更成熟、更流行的框架,為什么用戶(hù)應(yīng)該選擇 X 框架這么一個(gè)不那么成熟、不那么流行的框架夾在中間來(lái)“解耦”呢?

不管怎么說(shuō),至少我們可以看到: X 框架提供了組件容器的核心功能。那么, IoC (或者說(shuō), Dependency Injection )在 X 框架中的應(yīng)用又怎么樣呢?眾所周知,引入 IoC 容器的目標(biāo)就是要消除應(yīng)用程序中泛濫的工廠(包括 Service Locator ),由容器統(tǒng)一管理組件的創(chuàng)建和組裝。遺憾的是,不論在框架內(nèi)部還是在示例應(yīng)用中,我們?nèi)匀豢吹搅舜罅康墓S和 Service Locator 。例如作者引以為傲的緩存部分,具體的緩存策略(即 Cache 接口的實(shí)現(xiàn)對(duì)象)就是由 CacheFactory 負(fù)責(zé)創(chuàng)建的,并且使用的實(shí)現(xiàn)類(lèi)還是硬編碼在工廠內(nèi)部:

? public ? CacheFactory() {

cache = new LRUCache();

也就是說(shuō),如果用戶(hù)需要改變緩存策略,就必須修改 CacheFactory 的源代碼——請(qǐng)注意,這是一個(gè) X 框架內(nèi)部的類(lèi),用戶(hù)不應(yīng)該、也沒(méi)有能力去修改它。換句話(huà)說(shuō),用戶(hù)實(shí)際上根本無(wú)法改變緩存策略。既然如此,那這個(gè) CacheFactory 又有什么用呢?

開(kāi)源必讀:開(kāi)放 -封閉原則

開(kāi)源軟件應(yīng)該遵守開(kāi)放 - 封閉原則( Open-Close Principle OCP ):對(duì) 擴(kuò)展 開(kāi)放,對(duì) 修改 封閉。如果你希望為用戶(hù)提供任何靈活性,必須讓用戶(hù)以擴(kuò)展(例如派生子類(lèi)或配置文件)的方式使用,不能要求(甚至不能允許)用戶(hù)修改源代碼。如果一項(xiàng)靈活性必須通過(guò)修改源碼才能獲得,那么它對(duì)于用戶(hù)就毫無(wú)意義。

在示例應(yīng)用中,我們同樣沒(méi)有看到 IoC 的身影。例如 JdbcDAO 需要使用數(shù)據(jù)源(即 DataSource 對(duì)象),它就在構(gòu)造子中通過(guò) Service Locator 主動(dòng)獲取這個(gè)對(duì)象:

? public JdbcDAO() {

????? ServiceLocator sl = new ServiceLocator();

????? dataSource = (DataSource) sl.getDataSource(JNDINames.DATASOURCE);

同樣的情況也出現(xiàn)在 JdbcDAO 的使用者那里。也就是說(shuō),雖然 X 框架提供了組件容器的功能,卻沒(méi)有(至少是目前沒(méi)有)利用它的依賴(lài)注入能力,僅僅把它作為一個(gè)“大工廠”來(lái)使用。這是對(duì) IoC 容器的一種典型的誤用:用這種方式使用容器,不僅沒(méi)有獲得“自動(dòng)管理依賴(lài)關(guān)系”的能力,而且也失去了普通 Service Locator “強(qiáng)類(lèi)型檢查”的優(yōu)點(diǎn),又是一個(gè)“取其糟粕、去其精華”的設(shè)計(jì)。

開(kāi)源必讀:了解你自己

當(dāng)你決定要在開(kāi)源軟件中使用某項(xiàng)技術(shù)時(shí),請(qǐng)確定你了解它的利弊和用法。如果僅僅為了給自己的軟件貼上“基于 xx 技術(shù)”的標(biāo)簽而使用一種自己不熟悉的技術(shù),往往只會(huì)給你的項(xiàng)目帶來(lái)負(fù)面的影響。

AOP

X 框架的源碼包中,我們找到了符合 AOP-Alliance API 的一些攔截器,例如用于實(shí)現(xiàn)緩存的 CacheInterceptor 。盡管——毫不意外地——沒(méi)有找到如何將這些攔截器織入( weave in )的邏輯或配置文件,但我們畢竟可以相信:這里的確有 AOP 的身影??墒?,甫一深入這個(gè)“基于 AOP 的緩存機(jī)制”內(nèi)部,筆者卻又發(fā)現(xiàn)了更多的問(wèn)題。

單從 CacheInterceptor 的實(shí)現(xiàn)來(lái)看,這是一個(gè)最簡(jiǎn)單、也最常見(jiàn)的緩存攔截器。它攔截所有業(yè)務(wù)方法的調(diào)用,并針對(duì)每次方法調(diào)用執(zhí)行下列邏輯:

??? IF 需要緩存

?????? key = ( 根據(jù)方法簽名生成 key);

?????? IF (cache.get(key) == null)

??? ?????? value = ( 實(shí)際調(diào)用被攔截方法 );

??? ??? ??? cache.put(key, value);

?????? RETURN (cache.get(key));

??? ELSE

?????? RETURN ( 實(shí)際調(diào)用被攔截方法 );

看上去很好,基于 AOP 的緩存實(shí)現(xiàn)就應(yīng)該這么做……可是,清除緩存的邏輯在哪里?如果我們把業(yè)務(wù)方法分為“讀方法”和“寫(xiě)方法”兩種,那么這個(gè)攔截器實(shí)際上只照顧了“讀方法”的情況。而“寫(xiě)方法”被調(diào)用時(shí)會(huì)改變業(yè)務(wù)對(duì)象的狀態(tài),因此必須將其操作的業(yè)務(wù)對(duì)象從緩存中清除出去,但這部分邏輯在 CacheInterceptor 中壓根不見(jiàn)蹤影。如果緩存內(nèi)容不能及時(shí)清理的話(huà),用戶(hù)從緩存中取出的信息豈不是完全錯(cuò)誤的嗎?

被驚出一身冷汗之后,筆者好歹還是從幾個(gè) Struts action (也就是調(diào)用 POJO Fa?ade client 代碼)中找到了清除緩存的邏輯。原來(lái) X 框架所謂“基于 AOP 的緩存機(jī)制”只實(shí)現(xiàn)了一條腿:“把數(shù)據(jù)放入緩存”和“從緩存中取數(shù)據(jù)”的邏輯確實(shí)用攔截器實(shí)現(xiàn)了,但“如何清除失效數(shù)據(jù)”的邏輯還得散布在所有的客戶(hù)代碼中。 AOP 原本就是為了把緩存這類(lèi)橫切性( crosscutting )的基礎(chǔ)設(shè)施邏輯集中到一個(gè)模塊管理,像 X 框架的這個(gè)緩存實(shí)現(xiàn),不僅橫切性的代碼仍然四下散布,連緩存邏輯的相關(guān)性和概念完整性都被打破了,豈不是弄巧成拙么?

開(kāi)源必讀:言而有信

如果你在宣傳詞中承諾了一項(xiàng)特性,請(qǐng)務(wù)必在你的軟件中完整地實(shí)現(xiàn)它。不要僅僅提供一個(gè)半吊子的實(shí)現(xiàn),更不要讓你的任何承諾放空。如果你沒(méi)有把握做好一件事,就不要承諾它。不僅對(duì)于開(kāi)源軟件,對(duì)于任何軟件開(kāi)發(fā),這都是應(yīng)該記住的原則。

更有趣的是, X 框架的作者要求領(lǐng)域模型對(duì)象繼承 Model 基類(lèi),并聲稱(chēng)這是為了緩存的需要——事實(shí)也的確如此: CacheInterceptor 只能處理 Model 的子對(duì)象。但只要對(duì)緩存部分的實(shí)現(xiàn)稍加分析就會(huì)發(fā)現(xiàn),這一要求完全是作者憑空加上的:用于緩存對(duì)象的 Cache 接口允許放入任何 Object ;而 Model 盡管提供了 setModified() 、 setCacheable() 等用于管理緩存邏輯的方法,卻沒(méi)有任何代碼調(diào)用它們。換句話(huà)說(shuō),即便我們修改 CacheInterceptor ,使其可以緩存任何 Object ,對(duì) X 框架目前的功能也不會(huì)有任何影響。既然如此,又為什么要給用戶(hù)憑空加上這一層限制呢?

退一萬(wàn)步說(shuō),即使我們認(rèn)為 X 框架今后會(huì)用 Model 的方法來(lái)管理緩存邏輯,這個(gè)限制仍然是理由不足的。畢竟,目前 X 框架還僅僅提供了緩存這一項(xiàng)基礎(chǔ)設(shè)施( infrastructure )而已。如果所有基礎(chǔ)設(shè)施都用“繼承一個(gè)基類(lèi)”的套路來(lái)實(shí)現(xiàn),當(dāng)它真正提供企業(yè)級(jí)應(yīng)用所需的所有基礎(chǔ)設(shè)施時(shí), Model 類(lèi)豈不是要變得碩大無(wú)朋?用戶(hù)的領(lǐng)域?qū)ο筘M不是再也無(wú)法移植到這個(gè)框架之外?況且,“由領(lǐng)域?qū)ο笈袛嘧约菏欠裥枰彺妗钡乃悸繁旧硪彩清e(cuò)誤的:如果不僅要緩存領(lǐng)域?qū)ο螅€要緩存 String 、 Integer 等簡(jiǎn)單對(duì)象,該怎么辦?如果同一個(gè)領(lǐng)域?qū)ο笤诓煌姆椒ㄖ行枰煌木彺娌呗裕衷撛趺崔k? X 框架的設(shè)計(jì)讓領(lǐng)域?qū)ο蟊池?fù)了太多的責(zé)任,而這些責(zé)任原本應(yīng)該是通過(guò) AOP 轉(zhuǎn)移到 aspect 中的。在 X 框架這里, AOP 根本沒(méi)有發(fā)揮它應(yīng)有的效用。

開(kāi)源必讀:避免綁定

開(kāi)源軟件(尤其是框架類(lèi)軟件)應(yīng)該盡量避免對(duì)你的用戶(hù)造成綁定。能夠在 POJO 上實(shí)現(xiàn)的功能,就不要強(qiáng)迫用戶(hù)實(shí)現(xiàn)你的接口;能夠通過(guò)接口實(shí)現(xiàn)的功能,就不要強(qiáng)迫用戶(hù)繼承你的基類(lèi)。尤其是 Java 語(yǔ)言只允許單根繼承,一旦要求用戶(hù)的類(lèi)繼承框架基類(lèi),那么前者就無(wú)法再繼承其他任何基類(lèi),這是一種非常嚴(yán)重的綁定,不論用戶(hù)和框架設(shè)計(jì)者都應(yīng)當(dāng)極力避免。

寫(xiě)在最后

看完這篇多少有些尖刻的批評(píng),恐怕讀者難免要怪責(zé)我“不厚道”——畢竟,糟糕的開(kāi)源軟件堪比恒河沙數(shù),為什么偏要選中 X 框架大加撻伐呢?在此,我要給各位讀者、各位有志于開(kāi)源的程序員一個(gè)最后、卻是最重要的建議:

開(kāi)源必讀:切忌好大喜功

開(kāi)源是一件長(zhǎng)期而艱巨的工作,對(duì)于只能用業(yè)余時(shí)間參與的我們更是如此。做開(kāi)源務(wù)必腳踏實(shí)地,做出產(chǎn)品首先在小圈子里內(nèi)部討論,然后逐漸擴(kuò)大宣傳的圈子。切勿吹大牛、放衛(wèi)星,把“未來(lái)的愿景”當(dāng)作“今天的承諾”來(lái)說(shuō)——因?yàn)橐坏┕ぷ髅ζ饋?lái),誰(shuí)都不敢保證這個(gè)愿景到哪天才能實(shí)現(xiàn)。

國(guó)人還有個(gè)愛(ài)好:凡事喜歡趕個(gè)年節(jié)“獻(xiàn)禮”,或是給自己綁上個(gè)“民族軟件”的旗號(hào),這更是開(kāi)源的大忌。凡是做過(guò)政府項(xiàng)目的程序員,想必都對(duì)“國(guó)慶獻(xiàn)禮”、“新年獻(xiàn)禮”之類(lèi)事情煩不勝煩,輪到自己做開(kāi)源項(xiàng)目時(shí),又何苦把自己套進(jìn)這個(gè)怪圈里呢?當(dāng)然,如果你的開(kāi)源項(xiàng)目原本就是做給某些官老爺看的,那又另當(dāng)別論。

所以,我的這位朋友怕也不能怪我刻?。阂皇撬o趕著拿出個(gè)遠(yuǎn)未完善的版本“新年獻(xiàn)禮”,要不是他提前放出“ AOP/IoC ”的衛(wèi)星,要不是他妄稱(chēng)這個(gè)框架“代表民族軟件水平”,或許我還會(huì)夸他的代碼頗有可看之處呢。有一句大家都熟悉的老話(huà),筆者私以為所有投身開(kāi)源者頗可借鑒,在此與諸位共勉:

長(zhǎng)得丑不是你的錯(cuò)……



[1] 這篇 Blog 的原文請(qǐng)看: http://gigix.blogdriver.com/gigix/474041.html 。

[2] 關(guān)于 IoC 模式和 Dependency Injection 模式,詳見(jiàn) Martin Fowler 的《Dependency Injection與模式IoC容器》 一文。(中譯本發(fā)表于《程序員》 2004 年第3 期。



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=276486


前車(chē)之覆,后車(chē)之鑒——開(kāi)源項(xiàng)目經(jīng)驗(yàn)談


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦?。?!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 国产资源网站 | 九九99久久| 成人免费一区二区三区视频软件 | 18性夜影院午夜寂寞影院免费 | jizzjizz日本护士视频 | 久久久久久免费播放一级毛片 | 黄色中文字幕 | 亚洲一区播放 | 国产大片免费观看中文字幕 | 九草在线 | 先锋资源站 | 久久99综合国产精品亚洲首页 | 久久只有这里有精品 | 亚洲精品国产网红在线 | 国产精品成人不卡在线观看 | 天天艹夜夜艹 | 欧美6一10sex性hd | 免费很黄很色裸乳在线观看 | 国产在线精品一区二区三区 | 啪视频免费 | 久久精品a | 最新精品在线 | 久草在线视频网 | 久久久精彩视频 | 黄色资源在线 | 国产激情一级毛片久久久 | 国产精品亚洲综合一区在线观看 | 亚洲欧洲精品一区二区 | 亚洲精品一区二区三区精华液 | 欧美日韩国产精品一区二区 | 99这里只有精品66视频 | 午夜在线小视频 | 久久亚洲综合 | 波多野结衣在线观看一区 | 日本一区二区三区四区在线观看 | 国产扩阴视频 | 国产精品一区二 | 三级斤 | 国产熟妇久久777777 | 亚洲天堂中文字幕 | 亚洲视频在线网站 |