新聞中心
引言:如今的JavaScript已經(jīng)是Web上最流行的語(yǔ)言,沒(méi)有之一。從GitHub上的語(yǔ)言排行榜https://github.com/languages上即可看出,也是如今最為活躍的開(kāi)源社區(qū)。隨著Node的加入,JavaScript開(kāi)枝散葉進(jìn)入服務(wù)器領(lǐng)域,為這個(gè)語(yǔ)言榜的占比,也貢獻(xiàn)了幾分熱度。盡管經(jīng)歷了Web2.0的洗禮 ,但在國(guó)內(nèi)談及開(kāi)源,開(kāi)源人士似乎都當(dāng)這門(mén)語(yǔ)言并不存在,這也意味著國(guó)內(nèi)的開(kāi)發(fā)中堅(jiān)階層,并沒(méi)有改變JavaScript以及前端過(guò)去二流形象的認(rèn)識(shí),也沒(méi)意識(shí)到JavaScript如今真正的價(jià)值。歷史原因造就如今的局面,但是你并不能就此否認(rèn),一個(gè)出身不好,小時(shí)候還挺調(diào)皮的孩子,他長(zhǎng)大后就是沒(méi)有出息。本文將介紹一個(gè)優(yōu)秀的JavaScript模塊應(yīng)該是怎樣煉成的,以期望未來(lái)國(guó)內(nèi)的開(kāi)源社區(qū)能夠涌現(xiàn)出更多的優(yōu)秀模塊。

網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)!專(zhuān)注于網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、成都小程序開(kāi)發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶(hù)創(chuàng)新互聯(lián)還提供了蔚縣免費(fèi)建站歡迎大家使用!
引起我寫(xiě)這篇文章沖動(dòng)的是近期接觸到moment模塊時(shí)的震驚。用JavaScript寫(xiě)程序,通常要經(jīng)歷兩個(gè)階段:第一個(gè)階段是采用一些模塊來(lái)擦除JavaScript語(yǔ)言(跨平臺(tái))自身的問(wèn)題;第二個(gè)階段是自己寫(xiě)一些方法來(lái)擦除引入的模塊的問(wèn)題。第三個(gè)階段才會(huì)真正進(jìn)入業(yè)務(wù)開(kāi)發(fā)中,前兩個(gè)階段俗稱(chēng)“擦屁股”。時(shí)常在第三個(gè)階段時(shí),我會(huì)陷回到第二個(gè)階段,和各種模塊碰撞,往往會(huì)引起一些心情上的不舒爽。而在接觸到moment時(shí),這些煩惱瞬間消散,我在心底知道為何會(huì)如此釋?xiě)?,如碰到心儀的女神。這也讓我回頭反思過(guò)去在使用和寫(xiě)模塊過(guò)程中遇到的挫折和收獲,這落差讓我產(chǎn)生了如此的沖動(dòng),此文算是一個(gè)總結(jié),期望能在汲取優(yōu)秀模塊的經(jīng)驗(yàn)中,國(guó)內(nèi)開(kāi)源社區(qū)能夠成長(zhǎng)起來(lái)。
為什么是模塊,而不是庫(kù)或者框架
在過(guò)去幾年做前端的同學(xué)多半談?wù)摰氖菐?kù),或是框架,提及庫(kù)則是Prototypejs和jQuery,框架則是YUI3,Dojo、Extjs等。關(guān)于庫(kù)或者框架的,對(duì)應(yīng)的比喻則是大教堂和集市。在最早的時(shí)間,大教堂和集市的建設(shè)都在同步行進(jìn),具有代表意義的是YUI3和jQuery,前者Yahoo!投入許多精力,歷時(shí)兩代完成,后者則是集市建造的典范,由John Resig創(chuàng)建,社區(qū)參與。最后看看后續(xù)的反饋:
大教堂未必優(yōu)質(zhì)
大教堂模式產(chǎn)出的作品,讓享用者可以有一步到位的服務(wù),無(wú)需其他。但是由于大教堂的建設(shè)過(guò)程中承擔(dān)著解決所有問(wèn)題的使命,這導(dǎo)致它逐漸變得龐大,盡管它有著宏大而美妙的結(jié)構(gòu),像一首長(zhǎng)長(zhǎng)的贊美詩(shī),任何一段都可以被唱詩(shī)班演唱得動(dòng)聽(tīng)。但是,弱點(diǎn)依舊暴露出來(lái):
1、局部的優(yōu)良程度未必是最好的;
2、龐大的結(jié)構(gòu)導(dǎo)致靈活度下降,升級(jí)困難。
3、任何一條龍服務(wù),都不能保證每個(gè)環(huán)節(jié)都是優(yōu)異的。
小集市鉆石閃爍,沙礫良多
小集市的特點(diǎn)是開(kāi)放式建設(shè)、周期短、成本低。大多數(shù)創(chuàng)建出來(lái)的集市是功能簡(jiǎn)陋、品質(zhì)平庸的。jQuery是一個(gè)值得玩味的現(xiàn)象,品質(zhì)極高,但是它帶來(lái)的插件市場(chǎng),卻體現(xiàn)了小集市的另一面,大多數(shù)的jQuery插件的質(zhì)量卻十分低下。
可以說(shuō)小集市模式創(chuàng)建出來(lái)的作品,在單點(diǎn)上,是能夠超越教堂模式作品中對(duì)應(yīng)的那部分。前者缺乏一個(gè)宏偉的結(jié)構(gòu),但是在微觀上,它是完善的,可以隨意挪移的。后者雖然具備優(yōu)良的結(jié)構(gòu),但在單點(diǎn)上并非優(yōu)秀,這也容易讓人懷疑是否其他點(diǎn)上也并不優(yōu)秀,而且教堂式作品的一個(gè)特點(diǎn)則是,局部是不可移植的,非獨(dú)立性的,這在YUI3中表現(xiàn)十分明顯。
上述對(duì)比很容易讓人聯(lián)想到,如果一個(gè)架構(gòu)的特性具備單點(diǎn)可移植,可拆卸,自身極其輕量,汲取了大教堂和小集市的優(yōu)點(diǎn)。那必將是一個(gè)全新的時(shí)代,那是一個(gè)可以DIY的時(shí)代。原有的大教堂模式由于缺失了靈活性,在迭代迅速的開(kāi)發(fā)中,必將淘汰。而小集市盡管良莠不齊,好在預(yù)留了選擇權(quán)利給用戶(hù),并且他的開(kāi)放性也預(yù)示著它的可成長(zhǎng)性,所以還有未來(lái)可期。
沒(méi)錯(cuò),如今這個(gè)時(shí)代已經(jīng)到來(lái)。庫(kù)通常是一個(gè)比框架小一個(gè)粒度的單元,模塊則是比庫(kù)更小一個(gè)粒度的單元。一個(gè)庫(kù)可能由幾個(gè)模塊組成,框架則可能是在幾個(gè)庫(kù)的基礎(chǔ)上構(gòu)建。不再談?wù)搸?kù)和框架的原因是將庫(kù)和框架的架構(gòu)部分還給開(kāi)發(fā)者,以便開(kāi)發(fā)者可以根據(jù)實(shí)際業(yè)務(wù)去構(gòu)建合適的解決方案。任何框架或庫(kù)都只具備解決某一方面的能力,不具備普適性。當(dāng)粒度降低到模塊級(jí)別的時(shí)候,構(gòu)建任何上層業(yè)務(wù),可以實(shí)現(xiàn)按需使用。由于模塊的粒度更小,所以相對(duì)庫(kù)而言,更加專(zhuān)注,變優(yōu)秀的成本更低。類(lèi)比孩子在充滿(mǎn)沙礫的海邊奔跑,但很容易裝滿(mǎn)一口袋的貝殼。對(duì)于稍具慧眼的開(kāi)發(fā)者而言,挑選一堆適合的模塊來(lái)解決業(yè)務(wù)的問(wèn)題,比使用教堂式作品或者更高效。
這種方案因?yàn)镃ommonJS模塊規(guī)范的影響,已經(jīng)在既定事實(shí)中成型。在Node中,NPM平臺(tái)(https://npmjs.org/)上13000+的模塊數(shù)量可以說(shuō)明這個(gè)問(wèn)題。前端中由于受到歷史原因的影響,進(jìn)展較慢,國(guó)內(nèi)玉伯的SeaJS在推動(dòng)此事,Arale是在SeaJS基礎(chǔ)上創(chuàng)建了一些模塊,這類(lèi)模塊可以非常容易遷移到其他符合CommonJS模塊規(guī)范的環(huán)境中。除此之外騰訊的JX也具備SeaJS的特性,可以輕松將別的庫(kù)應(yīng)用到JX中,但是還不夠規(guī)范。
如果非得給這種模塊提供方式一個(gè)名稱(chēng),我覺(jué)得該叫做小教堂模式,具備小集市的小,意味著這個(gè)教堂可能只提供祈禱服務(wù),如果注冊(cè)結(jié)婚,則需要換另一家小教堂。但是這類(lèi)小教堂的服務(wù)是最優(yōu)質(zhì)的。創(chuàng)建這類(lèi)小教堂只比創(chuàng)建一個(gè)優(yōu)異的小集市略費(fèi)成本,換言之,優(yōu)異的小集市就是小教堂,它的創(chuàng)建方式是沿襲小集市的開(kāi)放、透明的、有既定目標(biāo)的成長(zhǎng)性的。
另一個(gè)考慮是,在大部分的情況下,我們是不需要大教堂的,現(xiàn)實(shí)中為了整體環(huán)境,我們寧愿在大教堂中祈禱,但是程序設(shè)計(jì)中,我們不會(huì)因?yàn)橄矚g一棵樹(shù)木,而買(mǎi)下整塊山頭,我們幾乎不喜歡任何看起來(lái)多余的部分。同時(shí)我們也不需要小集市,我們需要的是一個(gè)品質(zhì)優(yōu)良的商場(chǎng)。開(kāi)發(fā)者是采購(gòu)者,采購(gòu)模塊的過(guò)程既是架構(gòu)的設(shè)計(jì)的過(guò)程。
前文我也提到這種小教堂的模式依然存在不理想的功能重疊、功能多余、功能缺陷、功能沖撞等問(wèn)題??芍^說(shuō)完美的小教堂是可遇不可求的,但一旦它完美,將再難被替換。目前階段的JavaScript模塊開(kāi)發(fā)還存在著這些問(wèn)題。是故,如果開(kāi)發(fā)者了解如何去打造一個(gè)優(yōu)秀的JavaScript模塊,并樂(lè)于貢獻(xiàn)到開(kāi)源社區(qū),這將大幅提升社區(qū)JavaScript水平,后續(xù)的開(kāi)發(fā)者在做業(yè)務(wù)架構(gòu)時(shí),將具備更優(yōu)質(zhì)的材料來(lái)DIY更優(yōu)異的產(chǎn)品。
煉成優(yōu)秀模塊的最佳實(shí)踐
其實(shí)這并不算是精確的最佳實(shí)踐,只是從別的模塊哪里學(xué)習(xí)到的和自己過(guò)去的一些經(jīng)驗(yàn),僅做一定的總結(jié)。歡迎補(bǔ)充和討論。
模塊自身的素質(zhì)要求
要寫(xiě)出一個(gè)優(yōu)秀的模塊,模塊自身的素質(zhì)十分重要,如果自身?xiàng)l件太差,成為優(yōu)秀模塊的概率是極小的。這些自身素質(zhì)包括美好的愿景、專(zhuān)注的定位、名字、API設(shè)計(jì)、文檔、測(cè)試等。
合理的愿景:設(shè)定既定目標(biāo)
如果你打算寫(xiě)作一個(gè)模塊,并貢獻(xiàn)到開(kāi)源社區(qū)中,并期望它是優(yōu)異的,并被許多人使用的,那么為它設(shè)定一個(gè)既定目標(biāo)是首要的。如果這個(gè)目標(biāo)是沒(méi)有意義,沒(méi)有趣味的,那多半沒(méi)有人使用,甚至自己開(kāi)發(fā)到一半都沒(méi)有興趣繼續(xù)寫(xiě)下去。沒(méi)有理想的屌絲,注定不能成為高富帥。
對(duì)于具備眾多坑爹問(wèn)題的JavaScript語(yǔ)言而言,找到一個(gè)目標(biāo)并非難事。典型的例子如:jQuery專(zhuān)注解決DOM操作和Ajax、Underscore專(zhuān)注對(duì)象和集合的操作、QUnit和Jasmine專(zhuān)注BDD和TDD的單元測(cè)試、moment模塊專(zhuān)注解決從Java那里學(xué)過(guò)來(lái)的Date的問(wèn)題;拿近一些的例子,玉伯的SeaJS專(zhuān)注模塊加載,老趙的Wind.js專(zhuān)注異步編程同步化來(lái)解決流程控制問(wèn)題;拿一個(gè)有趣的例子,PNGDrivehttps://github.com/MadeInHaus/PNGDrive這個(gè)項(xiàng)目雖然沒(méi)有什么實(shí)際用處,但是將文件編碼為圖片顯示出來(lái)的方式足夠有趣。
另外這個(gè)目標(biāo)必須是既定的。也就意味著餅不用畫(huà)為無(wú)限的,這個(gè)目標(biāo)一定是可以完成的。如果目標(biāo)太大,也就意味著模塊自身會(huì)變復(fù)雜。jQuery兼容各種瀏覽器的DOM操作這個(gè)目標(biāo),在移動(dòng)平臺(tái)上變得沒(méi)有意義,所以存在著Zepto.js這樣的項(xiàng)目。更小的目標(biāo)意味著模塊自身簡(jiǎn)潔,且能夠更專(zhuān)注,目標(biāo)更容易抵達(dá)。一旦抵達(dá)目標(biāo),該模塊就是穩(wěn)定的,未來(lái)被替換的機(jī)會(huì)極小。
為模塊或項(xiàng)目起一個(gè)貼切的名字
模塊需要一個(gè)貼切而好記的名字。這個(gè)名字何以幫助用戶(hù)最直觀地感受模塊。SeaJS在起名上算是一個(gè)表率,讓人很容易有海納百川的聯(lián)想,這也正是SeaJS的行為。一個(gè)好的名字可以使得模塊的后期推廣事半功倍,而且一旦開(kāi)始推廣,盡量不要換名字。
不做逾越的事
并非每個(gè)使用者都喜歡買(mǎi)一送一的感覺(jué),因?yàn)楹竺孢@個(gè)一,對(duì)于使用者而言,并非是期望的,所以它的優(yōu)良無(wú)法直觀的判定好壞。無(wú)關(guān)的方法一定不要提供。評(píng)判一個(gè)模塊是否完美,不是可以添加API,而是無(wú)法再減少API了。
不污染公共環(huán)境
每個(gè)人都不喜歡公共環(huán)境被人污染。破窗效應(yīng)揭示,如果一輛汽車(chē)的門(mén)窗稍有損壞,不立即修復(fù),那么很快整輛車(chē)就會(huì)被破壞甚至偷走。 在JavaScript,公共環(huán)境包括全局變量,原型鏈等。jQuery和Underscore為了代碼的寫(xiě)作方便,占用了$和_兩個(gè)符號(hào),盡管他們都提供了noConflict方法來(lái)避免沖突,但是抱怨者還是大有人在。所幸這兩個(gè)庫(kù)太過(guò)于知名,幾乎沒(méi)有再有的庫(kù)來(lái)使用這兩個(gè)變量名。另一個(gè)例子是Prototype.js庫(kù)對(duì)對(duì)象進(jìn)行擴(kuò)展時(shí),直接在Array、Object等原生對(duì)象的原型鏈上添加方法,盡管它看起來(lái)不影響,但是總有沖突的一天,并且使用者并不一定知曉原型鏈被改動(dòng),在他的默認(rèn)上下文中,難保他也不去修改原型鏈。相比Prototype.js的做法,Underscore提供的方法則優(yōu)雅許多,另行提供API來(lái)處理操作,而不是修改共有的原型鏈。
在Node和瀏覽器中,global和window是全局對(duì)象,如果隨意放置變量到全局對(duì)象上,也容易遭到他人修改或者覆蓋你變量的事情。
CommonJS提供的require、exports則十分優(yōu)雅解決這個(gè)問(wèn)題。誰(shuí)使用,誰(shuí)引入。而不是通過(guò)全局變量。在前端沒(méi)有AMD或者CommonJS環(huán)境下,則是采用命名空間和閉包來(lái)解決這個(gè)問(wèn)題。
不污染公共環(huán)境是模塊與模塊之間互相不影響的基本保證。如果引入你的模塊,導(dǎo)致其他模塊失效的事情,多半是不招人待見(jiàn)的。
抵制墨菲效應(yīng)
有可能變?cè)愀獾氖虑椋冊(cè)愀獾目赡苄跃蜁?huì)變大。模塊在升級(jí),迭代的過(guò)程中,如何避免這種糟糕的事情發(fā)生呢?答案是單元測(cè)試。當(dāng)單元測(cè)試覆蓋了你認(rèn)為會(huì)出問(wèn)題的地方,可以避免相同的錯(cuò)誤再次發(fā)生。這是模塊穩(wěn)定迭代的基本保證。當(dāng)我發(fā)現(xiàn)一個(gè)僅僅為了解決日期操作的moment模塊,它為數(shù)不多的API竟然具有多達(dá)7000+的斷言時(shí),十分驚訝。
過(guò)去JavaScript只做簡(jiǎn)單的事情,地位低下,所以對(duì)于JavaScript的質(zhì)量保證也極少。這個(gè)思維需要改變,一個(gè)用戶(hù)在評(píng)估采用你的模塊時(shí),如果單元測(cè)試都無(wú)法看到,心里該是有多不踏實(shí)。
除此之外,還有性能測(cè)試,性能測(cè)試結(jié)果可以橫向比較,也可以縱向比較,有利于感知模塊的具體性能表現(xiàn)。
數(shù)據(jù)通常容易打動(dòng)理性的人。
保持簡(jiǎn)潔
對(duì)于任意看起來(lái)復(fù)雜的事物,用戶(hù)均會(huì)覺(jué)得它很復(fù)雜。老趙的Wind.js(前身是Jscex)是一個(gè)想法獨(dú)特的模塊,但在提供的API上由于eval,以及需要引入的模塊較多,讓它看起來(lái)比較復(fù)雜,讓用戶(hù)感覺(jué)潛意識(shí)里復(fù)雜,這種復(fù)雜的信號(hào)很容易變成它有問(wèn)題的信號(hào),讓人心生疏遠(yuǎn)。
將能不暴露給用戶(hù)看到的東西,盡量隱藏,過(guò)多的步驟只會(huì)讓用戶(hù)覺(jué)得麻煩和不靠譜。
職責(zé)單一
這里的反面例子來(lái)自于Require.js。如果你用過(guò)RequireJS,可以看到require方法是一個(gè)變態(tài)的設(shè)置,參數(shù)為’a’、[‘a(chǎn)’]、[‘a(chǎn).js’]、{}他們的行為都是不一致的。這種參數(shù)類(lèi)型可以隨意變化是JavaScript的靈活的地方,但是函數(shù)的行為如果也發(fā)生變化,這會(huì)讓人產(chǎn)生迷惑。適當(dāng)?shù)闹剌d并不意味這行為也要完全不同。
功能過(guò)多,帶來(lái)的問(wèn)題的可能性也會(huì)變大,使用者在調(diào)用過(guò)程中也會(huì)增加無(wú)形的壓力。分離功能可以保持方法職責(zé)單一會(huì)是你API優(yōu)秀的一部分。
編碼風(fēng)格
編碼風(fēng)格一定需要統(tǒng)一,而且編碼風(fēng)格一定不要顯得外行。如果你的用戶(hù)發(fā)現(xiàn)你的編碼風(fēng)格是PHP或者C#的,他們可能會(huì)產(chǎn)生你不是專(zhuān)業(yè)的這個(gè)感覺(jué)。推薦貼近JavaScript社區(qū),采用JSLint或JSHint來(lái)矯正編碼風(fēng)格。這有利于源代碼的閱讀,在不同的人之間傳遞不會(huì)有不換了一門(mén)語(yǔ)言的感覺(jué)。
API接口漂亮
API接口漂亮包含幾個(gè)方面:
命名
對(duì)外API的命名需要謹(jǐn)慎對(duì)待,方法名太長(zhǎng)、方法名不直觀、方法名大小寫(xiě)不對(duì)、方法名單詞太復(fù)雜都會(huì)影響到使用者的直觀感受。由于國(guó)內(nèi)的英文水平高低不一,使用者遇見(jiàn)不認(rèn)識(shí)的單詞,都會(huì)造成障礙。
jQuery在方法命名上十分優(yōu)秀。簡(jiǎn)短,直觀,優(yōu)雅。
調(diào)用
實(shí)參的傳入也是考驗(yàn)API設(shè)計(jì)者的地方。如果需要調(diào)用者傳入的參數(shù)較多,則該反思該API是否適合暴露給調(diào)用者。如果調(diào)用參數(shù)確實(shí)較多,并且支持可選項(xiàng),則傳入一個(gè)對(duì)象作為參數(shù)較為合適。由于對(duì)象帶有明確的key,獲取參數(shù)也無(wú)需一個(gè)一個(gè)檢測(cè)。
$.ajax()是一個(gè)典型的例子,它支持的參數(shù)非常多,并且大多可選。所以暴露的API為$.ajax(url, obj)或$.ajax(obj)。
在JavaScript中,鏈?zhǔn)秸{(diào)用也是讓用戶(hù)較為喜愛(ài)的一點(diǎn)。Underscore除了提供普通的API外,還支持包裝對(duì)象之后進(jìn)行鏈?zhǔn)秸{(diào)用。這讓熟悉函數(shù)式編程的人,頓生親切。
習(xí)慣
Zepto.js是一個(gè)經(jīng)典的案例,它提供了與jQuery幾乎完全兼容的API,為的是照顧用戶(hù)對(duì)于jQuery的熟悉。這讓它可以零成本被應(yīng)用到移動(dòng)瀏覽器上。
jQuery的另一件反面例子則是它的each方法,與原生數(shù)組的forEach方法的回調(diào)傳入值次序不同,這與習(xí)慣不同的接口,會(huì)造成一定反感心理。 在設(shè)計(jì)API的過(guò)程中,盡量尋找貼合用戶(hù)習(xí)慣的已有形式,這會(huì)讓用戶(hù)易于接受。
可擴(kuò)展性
模塊在開(kāi)發(fā)的過(guò)程中,可以包括有限的部分和無(wú)限的部分。有限的部分將會(huì)通過(guò)項(xiàng)目迭代,臻于完美。如果模塊存在無(wú)限的部分,并且在有限的部分留出擴(kuò)展來(lái)衍生無(wú)限,這對(duì)于模塊的成長(zhǎng),這是一個(gè)大大的加分項(xiàng)。
jQuery留出$.fn來(lái)供用戶(hù)擴(kuò)展它,形成的影響是大量的jQuery插件涌現(xiàn)了出來(lái)。盡管大多數(shù)情況沒(méi)有被正確使用,但不能掩蓋它是一個(gè)漂亮的設(shè)計(jì)。
moment模塊在它的lang部分,也提供了優(yōu)雅的擴(kuò)展它的部分。使得不同地區(qū)的用戶(hù)可以自定義語(yǔ)言的顯示。
擴(kuò)展性的存在,使得開(kāi)源社區(qū)能夠參與,能夠起到拋磚引玉的效果,反過(guò)來(lái)會(huì)增進(jìn)模塊的功能。
使用合適的設(shè)計(jì)模式
合適的設(shè)計(jì)模式可以讓模塊自身無(wú)瑕。不合適的設(shè)計(jì)模式則會(huì)適得其反。
這里的正反例子都與jQuery相關(guān)。正例子是Deferred的應(yīng)用。過(guò)去ajax操作success和fail回調(diào)都必須寫(xiě)到$.ajax(obj)的參數(shù)對(duì)象中,但是Deferred對(duì)象使得調(diào)用更加自然:
- $.get("test.php").done(function() {
- alert("$.get succeeded");
- });
LABjs的設(shè)計(jì)模式也十分優(yōu)秀,script和wait兩個(gè)用于加載和阻塞的API,通過(guò)鏈?zhǔn)秸{(diào)用,其樂(lè)融融:
反例子則是來(lái)自jQuery插件。jQuery.fn不失為一個(gè)好的擴(kuò)展點(diǎn),但是有大量的jQuery插件操作的并非DOM,卻生搬硬套將方法掛靠在jQuery.fn上。另一個(gè)例子則來(lái)自jQuery社區(qū)得意的UI組件。
- $(foo).dialog('open')
這類(lèi)通過(guò)傳入?yún)?shù),又不能得到期望的返回值的場(chǎng)景,并不適合操作這個(gè)組件對(duì)象,API的參數(shù)傳遞更是顯得不倫不類(lèi)。如果是直接操作組件對(duì)象,則更友好一些。相比jQuery UI,YUI3的組件則優(yōu)秀太多,API漂亮,組件的層次結(jié)構(gòu)分明,易于擴(kuò)展和自定義,jQuery UI通過(guò)插件方法的調(diào)用方式,自定義組件的代價(jià)極大。
#p#
合理的目錄結(jié)構(gòu)
開(kāi)發(fā)方式多半會(huì)影響到后續(xù)的使用方式。盡管前端腳本多半都是提供一個(gè)文件給用戶(hù),但是在開(kāi)發(fā)過(guò)程中,合理地組織自己項(xiàng)目的目錄結(jié)構(gòu)是值得注意的。jQuery的源代碼目錄中,各個(gè)功能點(diǎn)都分別寫(xiě)在各自的文件中,使得開(kāi)發(fā)過(guò)程中編寫(xiě)代碼方便。
另一方面,CommonJS的包規(guī)范還定義了以下目錄和文件:
- bin doc test lib package.json
分別用于存放二進(jìn)制文件、項(xiàng)目文檔、單元測(cè)試用例、源代碼。package.json文件則用于描述該包的一些包括包名、版本號(hào)、依賴(lài)等的信息,詳情見(jiàn)http://wiki.commonjs.org/wiki/Packages/1.0。遵循規(guī)范的目錄結(jié)構(gòu)通常更好一點(diǎn),因?yàn)榇蠹叶加型粋€(gè)準(zhǔn)則來(lái)參考,彼此更熟悉。
巨細(xì)的注解
通常用戶(hù)真正需要去閱讀你的代碼的時(shí)候,是出現(xiàn)問(wèn)題的時(shí)候。在開(kāi)源社區(qū),如何讓發(fā)現(xiàn)你問(wèn)題的人剛你改進(jìn)代碼,注釋的作用功不可沒(méi)。
另外,當(dāng)一個(gè)用戶(hù)真正是來(lái)欣賞你的代碼時(shí),如果看到Underscore這樣密度的注解時(shí)(http://documentcloud.github.com/underscore/docs/underscore.html),還有拒絕它的勇氣嗎?
清晰明了API的文檔
優(yōu)秀的模塊不僅僅體現(xiàn)在代碼寫(xiě)得好上,更多的體現(xiàn)在如何讓用戶(hù)使用時(shí)更舒適。API文檔必不可少。我心目中的API文檔應(yīng)該詳細(xì)描述方法作用、參數(shù)、返回值的。甚至還應(yīng)該有demo代碼伴隨。
API文檔可以通過(guò)jsdoc之類(lèi)的注解文檔來(lái)生成。也可以另起文檔來(lái)寫(xiě)。
API文檔的一個(gè)特點(diǎn)是應(yīng)該能方便查找,能在一個(gè)頁(yè)面中展現(xiàn)完成的,盡量不要頁(yè)面跳轉(zhuǎn)或翻頁(yè)。
API文檔最大的作用讓用戶(hù)精確理解API,使得不造成誤解,和清楚輸入輸出。
Underscore的API文檔(http://documentcloud.github.com/underscore/)借用模版生成了漂亮的頁(yè)面,使得查閱方便。
一見(jiàn)鐘情的demo
相比Node,前端JavaScript模塊更擅長(zhǎng)做這件事情,尤其是UI庫(kù)。男女之間首次見(jiàn)面的第一印象,很大程度可以決定某兩個(gè)人是否會(huì)談戀愛(ài)的概率。demo提供的形式可以影響到用戶(hù)的直觀體驗(yàn),一般而言,用戶(hù)覺(jué)得越炫,但是旁邊提示的示例代碼越簡(jiǎn)單,越會(huì)引發(fā)用戶(hù)的好奇心。如果只有代碼,或者只有demo,都會(huì)在表現(xiàn)性上打折扣。
對(duì)于Node的模塊而言,由于沒(méi)有l(wèi)ive demo的感覺(jué),盡量展示sample代碼,讓用戶(hù)了解到他的目標(biāo)是否與模塊的目標(biāo)一致。不要讓用戶(hù)錯(cuò)過(guò)你的模塊,也不要讓你的模塊錯(cuò)過(guò)了它的用戶(hù)。
README.md
README文件承擔(dān)的作用僅次于demo,無(wú)需讓用戶(hù)產(chǎn)生心動(dòng)的感覺(jué),但是一定要引導(dǎo)用戶(hù)更深度的了解你的模塊,詳細(xì)閱讀你README的人,多半是有興趣使用你的模塊的人在做實(shí)地考察了。一個(gè)geting start入門(mén)是必不可少的,到API文檔的鏈接也應(yīng)該有。如果空落落的README,會(huì)立馬有生疏感的。后期用戶(hù)的心得體會(huì)等相關(guān)文章,也記得更新到README中。
模塊的社區(qū)打造
話(huà)說(shuō)酒香也怕巷子深。在滿(mǎn)足成為優(yōu)秀模塊的基本素質(zhì)要求后的首要事情是如何將模塊推向開(kāi)源社區(qū),積極到社區(qū)中宣傳。
放到Github開(kāi)源:不僅僅是代碼
每一個(gè)程序員都應(yīng)該有屬于自己的Github帳號(hào)。如果你沒(méi)有,不是Github的遺憾,而是你的遺憾。關(guān)于Github有什么,可以參看這篇文章:如何高效利用GitHub (http://www.yangzhiping.com/tech/github.html)。 排除掉文化上帶來(lái)的好處。Github可以幫我們托管代碼,幫我們解決版本控制的問(wèn)題。它可以提供一個(gè)wiki,幫我們存放文檔。它提供Issues頁(yè)面,使得別人可以為模塊提出意見(jiàn)和反饋。提供Pull Requests頁(yè)面,使得別人可以幫我們修改代碼后,供我們合并修改。
交流平臺(tái)的創(chuàng)建
交流平臺(tái)主要用于討論、答疑,使得模塊作者和用戶(hù)之間可以產(chǎn)生思維的碰撞。交流過(guò)程可以不斷完善模塊自身的不足,形成文檔。主要的形式有如下:
郵件列表
國(guó)外的社區(qū)大多采用Google Groups的郵件列表來(lái)交流。郵件列表可以將討論發(fā)送到每一個(gè)關(guān)注它的人手中。
實(shí)時(shí)交流
國(guó)外多采用IRC頻道來(lái)進(jìn)行此事。國(guó)內(nèi)的情況,可以選擇合適的QQ群來(lái)進(jìn)行交流。
留言版
留言版的功能Github的issue具備了該功能。但是如果具備單獨(dú)的介紹頁(yè)面或者站點(diǎn),集成Disqus來(lái)收集用戶(hù)的反饋會(huì)是個(gè)不錯(cuò)的選擇,因?yàn)檫@更符合普通用戶(hù)的習(xí)慣。
版本控制
這里的版本控制不是git的版本控制。而是模塊的整體版本。標(biāo)注好模塊的版本是分場(chǎng)重要的,如果用戶(hù)需要升級(jí)模塊,它能夠得到明確的指導(dǎo)。前端模塊中通常是在文件名上,或者文件內(nèi)部寫(xiě)明版本。對(duì)于Node而言,寫(xiě)在package.json文件中。
最好能夠在大版本的發(fā)布時(shí),通過(guò)正式的新聞頁(yè)面,或是郵件列表發(fā)出新聞通知,以顯得版本發(fā)布的正式。
悠揚(yáng)的歷史:Change Log
不要小看Change log的作用,長(zhǎng)長(zhǎng)的,細(xì)碎的Change log可以給用戶(hù)該模塊歷史悠揚(yáng)的感覺(jué),也能讓用戶(hù)體會(huì)到寫(xiě)作該模塊的過(guò)程細(xì)節(jié)。每次迭代發(fā)布的過(guò)程中,展現(xiàn)給用戶(hù)看當(dāng)前的change log也能讓用戶(hù)知道改動(dòng)的影響范圍。如果碰巧發(fā)布了一個(gè)用戶(hù)需要的方法,他會(huì)有收到禮物的感覺(jué)。
選擇合適的License
國(guó)內(nèi)的環(huán)境中,也許大家不太關(guān)心License的問(wèn)題。事實(shí)上,License的選擇,會(huì)影響到用戶(hù)的評(píng)估。目前只有BSD和MIT兩種License可以讓人放心使用。對(duì)于商業(yè)公司而言,如果不是這兩種License,他們需要投入更多的精力和時(shí)間周期來(lái)評(píng)估這個(gè)模塊是否可用。
但是對(duì)于JavaScript社區(qū)而言,通常采用的是MIT,所以也基本沒(méi)有問(wèn)題。選好License,并在明顯且不重要的位置表明該模塊在什么License下發(fā)行。
發(fā)布到NPM中
在Node中,搞定代碼后,發(fā)布到NPM中是最應(yīng)該做的事。
易于獲得的感覺(jué)
npm install module或是一個(gè)顯眼又不失素雅的Download按鈕會(huì)在潛意識(shí)中讓用戶(hù)覺(jué)得易于獲得,容易集成到現(xiàn)有系統(tǒng)中。不要做了各種分享介紹之后,讓用戶(hù)找不到獲取模塊的地方。
持續(xù)集成
一個(gè)隨時(shí)都能拿出鑰匙,開(kāi)出跑車(chē)的青年,必將被認(rèn)為是高富帥。支支吾吾不能隨時(shí)給出結(jié)果的人,基本是屌絲無(wú)疑。
推薦注冊(cè)你的項(xiàng)目到travis-ci,并運(yùn)行它。綠色的Passing時(shí)刻昭示該項(xiàng)目的可靠指數(shù)、穩(wěn)定指數(shù)較高。這個(gè)小圖標(biāo)也能幫助你檢測(cè)迭代是否出現(xiàn)問(wèn)題。
漂亮的站點(diǎn)
注冊(cè)一個(gè)模塊名字的org域名,一套簡(jiǎn)潔明了的UI,清晰的導(dǎo)航,簡(jiǎn)單的demo等等。細(xì)節(jié)在前后的實(shí)踐中都有提及。
標(biāo)致的Logo
如果你沒(méi)有任何視覺(jué)設(shè)計(jì)的天賦,厚著臉皮找你的視覺(jué)設(shè)計(jì)師同事要一枚吧,盡管它是一個(gè)錦上添花的事情,但是Logo在品牌認(rèn)知上的功勞是不用質(zhì)疑的。
線(xiàn)下分享交流
開(kāi)發(fā)完模塊后,一定記得分享給團(tuán)隊(duì)的同事,他們應(yīng)該是模塊的首批用戶(hù),他們給予的反饋也是最寶貴的。
另外,還可以在線(xiàn)下社區(qū)分享,將你的模塊的推廣范圍從身邊延續(xù)到這個(gè)城市。盡管在線(xiàn)下社區(qū)分享模塊的機(jī)會(huì)不多,但是一旦有,不要忘記介紹自己得意的模塊給他人。
分享帶來(lái)的收益是明顯的,有利于自己梳理對(duì)模塊的認(rèn)識(shí),也能收到用戶(hù)的直觀反饋。
及時(shí)響應(yīng)反饋
也許你的模塊已經(jīng)很久沒(méi)有更新,但是用戶(hù)還是會(huì)發(fā)來(lái)反饋或提出問(wèn)題,甚至提交pull request,請(qǐng)及時(shí)響應(yīng)需求。如果是提出問(wèn)題,說(shuō)明你的文檔還不夠完善。如果是提出需求,則說(shuō)明你最初設(shè)定的目標(biāo)還沒(méi)有完成。
善意營(yíng)銷(xiāo):賞金獵人
如果有用戶(hù)指出你的低級(jí)bug,或是幫你寫(xiě)作了模塊的體驗(yàn)文章,這些事情都是值得模塊作者有所表示的時(shí)候,因?yàn)檫@些用戶(hù)是你的忠實(shí)用戶(hù),他們?cè)趲湍愕哪K成長(zhǎng)。有所表示并不意味著要給多少錢(qián),一些有意義的獎(jiǎng)品或紀(jì)念品更適合拉近這些用戶(hù)與你之間的距離。
與兄弟社區(qū)的互動(dòng)
一個(gè)社區(qū)如果過(guò)小,需要到隔壁的社區(qū)中發(fā)布一些信息讓大家知曉。如果可以,無(wú)論國(guó)內(nèi)還是國(guó)外的的兄弟社區(qū)的協(xié)助推廣,將會(huì)對(duì)社區(qū)運(yùn)作有很大的幫助。友情鏈接是一個(gè)典型的方式。
模塊開(kāi)發(fā)者的自我修煉
模塊自身的優(yōu)秀加上社區(qū)的打造可以保證模塊擁有不錯(cuò)質(zhì)量和口碑。但是決定模塊能否走得遠(yuǎn),模塊開(kāi)發(fā)者的自身素質(zhì)也十分重要,這其實(shí)模塊的另一個(gè)軟素質(zhì)。經(jīng)歷了開(kāi)發(fā)階段和社區(qū)運(yùn)作階段后,越發(fā)展到后期,開(kāi)發(fā)者的自身修煉的影響越會(huì)凸顯。
忍得住寂寞&持續(xù)堅(jiān)持
典型的例子是老趙對(duì)于Wind.js的堅(jiān)持。在對(duì)Wind.js的開(kāi)發(fā)和推廣上,可謂是寂寞的。略呈偏門(mén)的異步同步化、eval、編譯等工序,被誤解和排斥的多次。這是需要忍受的,如果沒(méi)有持續(xù)堅(jiān)持和忍住寂寞,模塊就沒(méi)有明天。作者的熱情一旦消散,用戶(hù)的熱情也必然消散。
簡(jiǎn)單專(zhuān)注
前文的愿景部分提及到了簡(jiǎn)單專(zhuān)注。簡(jiǎn)單專(zhuān)注,不僅僅是在項(xiàng)目初期保持,在長(zhǎng)久發(fā)展中,也應(yīng)當(dāng)如此,只有簡(jiǎn)單專(zhuān)注方能保證小教堂的服務(wù)質(zhì)量是最頂尖的。
奉獻(xiàn)精神
模塊開(kāi)發(fā)和推廣事實(shí)上是沒(méi)有直接的經(jīng)濟(jì)收入的,而且還會(huì)耗費(fèi)大量的時(shí)間和精力。但是開(kāi)源事業(yè)的收益,實(shí)際上是無(wú)法用金錢(qián)進(jìn)行衡量的。并且這個(gè)過(guò)程也是自愿自發(fā)的,沒(méi)有人會(huì)主動(dòng)來(lái)推動(dòng)你。
如果確實(shí)對(duì)經(jīng)濟(jì)造成影響,可以在頁(yè)面上加上donate的鏈接。優(yōu)秀的模塊不會(huì)讓這個(gè)donate鏈接的功能白費(fèi)的。
幸運(yùn)的是開(kāi)源社區(qū)中不會(huì)缺乏具有奉獻(xiàn)精神的人,是他們?cè)谕苿?dòng)社區(qū)和技術(shù)發(fā)展。
演講能力
前文提到線(xiàn)下分享,這對(duì)于開(kāi)發(fā)者的演講能力有更多的要求。演講能力的高低,是在另一個(gè)層面上提升模塊的表現(xiàn)力,盡管這種能力不需要運(yùn)行在CPU中。
文筆
模塊開(kāi)發(fā)者的文筆在文檔的影響上是能夠直觀反映的。除此之外在社區(qū)推廣中,文案的品質(zhì)也有一定的影響。如果開(kāi)發(fā)者文筆能夠好到用優(yōu)美的文章去傳遞模塊的思想,這是令人愉悅和容易接受的。
人格魅力
模塊的開(kāi)發(fā)者應(yīng)當(dāng)具備良好的人格魅力,這包括人際關(guān)系、交流能力等。一個(gè)具備人格魅力和一個(gè)并不為人所知需要進(jìn)一步了解的開(kāi)發(fā)者,他們展現(xiàn)在大家面前的收效是并不相同的。后者更容易吸引他人,為模塊帶來(lái)更多的用戶(hù),這些人是你的用戶(hù),也是你的合作者。他們的涌入,會(huì)幫助改進(jìn)模塊。 關(guān)于人格魅力這個(gè)軟素質(zhì),這里不再多說(shuō),相信都了解他的重要性的。
總結(jié)
通過(guò)對(duì)最佳實(shí)踐的羅列,我自己相當(dāng)于重溫了一遍JavaScript開(kāi)源的一系列文化。而這些最佳實(shí)踐部分其實(shí)都是必要條件,通過(guò)這些最佳實(shí)踐,未必保證會(huì)有優(yōu)秀的JavaScript模塊產(chǎn)出。但是觀察如今的那些優(yōu)秀模塊,他們基本上都具備這些特征。最后,JavaScript社區(qū)雖然活躍,佼佼者不在少數(shù),但是整體水平的提升,還需時(shí)日,希望此文能夠幫助到一些開(kāi)發(fā)者并歡迎討論。
關(guān)于作者
田永強(qiáng),新浪微博@樸靈,前端工程師,曾就職于SAP,現(xiàn)就職于淘寶,花名樸靈,致力于NodeJS和Mobile Web App方面的研發(fā)工作。雙修前后端JavaScript,寄望將NodeJS引薦給更多的工程師。興趣:讀萬(wàn)卷書(shū),行萬(wàn)里路。個(gè)人Github地址:http://github.com/JacksonTian。
網(wǎng)頁(yè)標(biāo)題:優(yōu)秀的JavaScript模塊是怎樣煉成的
鏈接URL:http://m.5511xx.com/article/djohsip.html


咨詢(xún)
建站咨詢(xún)
