編寫(xiě)可維護(hù)的JavaScript
技術(shù)支持服務(wù)電話:15308000360 【7x24提供運(yùn)維服務(wù),解決各類(lèi)系統(tǒng)/軟硬件疑難技術(shù)問(wèn)題】
在我的編程生涯中,曾遇到過(guò)各種各樣的開(kāi)發(fā)者,他們的編程風(fēng)格天馬行空,有時(shí)甚至讓人哭笑不得。有一種風(fēng)格被稱(chēng)為“霰彈槍編程”,例如某個(gè)方法調(diào)用出錯(cuò)了,我嘗試將參數(shù)0改為'0'、NaN甚至false,直到試出能“正確”運(yùn)行的參數(shù)為止。當(dāng)你和這種人組成團(tuán)隊(duì)一起編程時(shí),你會(huì)發(fā)現(xiàn)你的智商變得很低。
比“霰彈槍編程”更溫柔一點(diǎn)的編程方式是“撞大運(yùn)編程”,就是我根本看不懂程序到底在干嘛,但確實(shí)能正常運(yùn)行,這往往是因?yàn)檫@些程序中有很多錯(cuò)誤成對(duì)出現(xiàn),于是就負(fù)負(fù)得正,看起來(lái)就正確了,這種程序?qū)嵲谑?ldquo;動(dòng)彈不得”,只能重構(gòu)。當(dāng)你和這種人組成團(tuán)隊(duì)時(shí),上帝都會(huì)同情你。
當(dāng)然,當(dāng)漸漸意識(shí)到這類(lèi)隨意編程風(fēng)格帶來(lái)的危害時(shí),很多人開(kāi)始思考什么才是“好”的編程風(fēng)格。不少人開(kāi)始向高手學(xué)習(xí),盡管有時(shí)并不知道高手為什么要把代碼寫(xiě)成這個(gè)樣子。于是越來(lái)越多的hack代碼出現(xiàn)了,那些看起來(lái)晦澀難懂、短小精悍卻又暫時(shí)行之有效的代碼片段越來(lái)越流行,尤其是在處理瀏覽器兼容性問(wèn)題時(shí),這種情況更甚。有些人會(huì)在這些hack代碼片段旁邊打上記號(hào),以便以后有問(wèn)題時(shí)能留意到此。這時(shí),問(wèn)題又出現(xiàn)了,不同人做記號(hào)的方法又不一樣,我的天哪!
如果你自詡為一名有能力有良知的程序員,遇到這種“爛”代碼時(shí)往往將之重構(gòu),為了修改幾個(gè)拼寫(xiě)錯(cuò)誤的bug,而修改10個(gè)類(lèi),并且重構(gòu)與這10個(gè)類(lèi)有關(guān)聯(lián)的另外20個(gè)類(lèi),甚至修改了打包腳本以及部署配置文件。這就是一種有著代碼潔癖的人很“青睞”的編程風(fēng)格—“屠宰式編程”。
霰彈槍式、撞大運(yùn)式、不求甚解式、屠宰式……
編程是一項(xiàng)復(fù)雜的工程,卻又如此充滿喜感,讓人又愛(ài)又恨。但有一點(diǎn)確定無(wú)疑,即這些風(fēng)格因?yàn)槿鄙倩镜募s束,會(huì)導(dǎo)致團(tuán)隊(duì)協(xié)作效率低下,甚至影響產(chǎn)品的存亡。而對(duì)于Web開(kāi)發(fā)領(lǐng)域最為流行卻有著先天設(shè)計(jì)缺陷的語(yǔ)言JavaScript來(lái)說(shuō),情況更加糟糕。一直以來(lái)都缺少宏觀的設(shè)計(jì)模式和微觀的編程風(fēng)格的指導(dǎo),從而導(dǎo)致JavaScript編程始終沒(méi)有權(quán)威和統(tǒng)一的指導(dǎo)思想和方法論。因此,大部分Web前端團(tuán)隊(duì)依然將很大精力放在解決注入代碼沖突、命名規(guī)范性、代碼復(fù)用模式等團(tuán)隊(duì)編程最基本的問(wèn)題上。遲遲走不上創(chuàng)新、高效的快車(chē)道。
我們很欣喜地看到,在設(shè)計(jì)模式領(lǐng)域,《JavaScript設(shè)計(jì)模式》(JavaScript Design Patterns)和《JavaScript編程模式》(JavaScript Patterns)兩本書(shū)填補(bǔ)了這方面的空白,而在編程風(fēng)格領(lǐng)域,這本《編寫(xiě)可維護(hù)的JavaScript》(Maintainable JavaScript)真可謂姍姍來(lái)遲。
本書(shū)正是向開(kāi)發(fā)人員闡述如何在團(tuán)隊(duì)開(kāi)發(fā)中編寫(xiě)高可維護(hù)的JavaScript代碼,涵蓋了編碼風(fēng)格、編程技巧、自動(dòng)化、測(cè)試等幾方面,不過(guò),同樣的原則也適用于其他任何語(yǔ)言。本書(shū)作者是大名鼎鼎的Nicholas C. Zakas。他曾是Yahoo!的首席前端開(kāi)發(fā)工程師,在完成了從一名獨(dú)行俠到團(tuán)隊(duì)精英的蛻變后,他站在前端工程師的角度為我們提煉出許多的最佳編程實(shí)踐,其中包括很多來(lái)自工業(yè)生產(chǎn)的最佳法則。應(yīng)用這些技巧和技術(shù),可以使你的團(tuán)隊(duì)編程從俠義的個(gè)人偏好的陰霾走出來(lái),走向真正的高效和高水準(zhǔn)。
本書(shū)由淘寶北京前端團(tuán)隊(duì)翻譯,在翻譯過(guò)程中,我們始終保持一種學(xué)習(xí)的心態(tài),因?yàn)檎袂懊嫣岬降模髡呓o出的很多經(jīng)驗(yàn)正是我們手頭工作中不在意卻又至關(guān)重要的,這種學(xué)習(xí)心態(tài)也讓我們?cè)谶@次翻譯過(guò)程收獲頗豐。我們盡最大的努力,力求翻譯后的表述在還原作者原意的同時(shí)又不失中文的流暢。但難免由于譯者水平有限而有所紕漏,還請(qǐng)各位高手多多批評(píng)指正。
序言
由于前端工程師的成長(zhǎng)道路自成軌跡,這讓?zhuān)╓eb前端技術(shù))這個(gè)專(zhuān)業(yè)看起來(lái)是如此的與眾不同,甚至諸如Yahoo!這種大公司里的很多前端工程師也多是靠自身野蠻生長(zhǎng),我行我素地寫(xiě)著各種hack! ?;蛟S你曾經(jīng)也是一名小公司里的“頁(yè)面仔”(the web guy),那時(shí)的你幾乎什么都干。當(dāng)大公司開(kāi)始利用這些之前未被發(fā)掘的資源時(shí) ,團(tuán)隊(duì)協(xié)作的環(huán)境短時(shí)間內(nèi)吸納了很多“hacker” ,這時(shí)這些hacker碰到了各種條條框框。單兵作戰(zhàn)再也沒(méi)了優(yōu)勢(shì),所有那些自學(xué)成才和以自我為中心的人都不得不開(kāi)始思考如何才能在團(tuán)隊(duì)環(huán)境中生存下來(lái)。
我是在20世紀(jì)90年代末開(kāi)始學(xué)習(xí)JavaScript的:靠的是自學(xué)。因?yàn)楫?dāng)時(shí)的JavaScript還很新潮,學(xué)習(xí)資料很少。和其他很多開(kāi)發(fā)者一樣,我通過(guò)不斷鉆研IE和Netscape Navigator來(lái)自學(xué)。我做各種嘗試、梳理我所掌握的知識(shí),我一遍遍反復(fù)試驗(yàn),直到搞清楚其工作原理。幸運(yùn)的是,這份好奇和勤勉為我?guī)?lái)了第一份工作。
在我職業(yè)生涯的第一個(gè)五年中,我是一個(gè)“腳本仔”。在我最早呆過(guò)的兩家公司里,沒(méi)有人比我更了解JavaScript和Web開(kāi)發(fā)。所有問(wèn)題,不管是非常簡(jiǎn)單的還是非常復(fù)雜的,我都能搞定。我剛剛從學(xué)校畢業(yè),是一名初出茅廬的小伙子,卻有著一種危機(jī)感。因?yàn)槲艺也怀瞿芎臀耶a(chǎn)生思想碰撞的人,并且在我遇到問(wèn)題時(shí)也沒(méi)有人能為我解難。我力爭(zhēng)做到最好,因?yàn)槲抑牢沂俏ㄒ荒茏龅竭@樣的人。
在這五年之中,我不斷磨煉我的技能。我讓我的做事方式和工作流程更為合理。我不用擔(dān)心其他人去研究我的代碼,因?yàn)閯e人都沒(méi)有能力給我做代碼評(píng)審(review)或?yàn)槲业拇a提交bug修復(fù)。我是一個(gè)純粹意義上的hacker:我行我素地寫(xiě)著代碼,而且不用擔(dān)心它會(huì)被修改。
在我職業(yè)生涯的第六年,我換了工作,加入了一個(gè)團(tuán)隊(duì),在這個(gè)團(tuán)隊(duì)中,每個(gè)人都會(huì)為項(xiàng)目的各個(gè)方面貢獻(xiàn)代碼。我的主要精力不再是JavaScript和Web開(kāi)發(fā),而是大部分時(shí)間在寫(xiě)后端代碼和SQL。同時(shí),傳統(tǒng)的后端工程師卻開(kāi)始被迫寫(xiě)前端(頁(yè)面)代碼。這種體驗(yàn)真正讓我大開(kāi)眼界:我之前寫(xiě)代碼的方式和團(tuán)隊(duì)其他人實(shí)在是格格不入,這是一個(gè)大問(wèn)題。
我很快意識(shí)到要想更高效地參與團(tuán)隊(duì)開(kāi)發(fā),我寫(xiě)代碼的方式必須和團(tuán)隊(duì)保持一致。后臺(tái)代碼和SQL對(duì)我來(lái)說(shuō)有點(diǎn)陌生,因此我采納了身邊一些有頭腦的人寫(xiě)代碼的模式。與此同時(shí),我開(kāi)始與其他工程師討論我們應(yīng)當(dāng)采納何種HTML、CSS和JavaScript的編程模式。我甚至在編譯階段加入了JavaScirpt語(yǔ)法檢查來(lái)強(qiáng)制推行標(biāo)準(zhǔn)—這也是我第一次在公司做 Web 代碼的檢查。不久以后,這個(gè)團(tuán)隊(duì)就像上了潤(rùn)滑油的機(jī)器一樣高效。
我在2006年加入了Yahoo!。我一到Y(jié)ahoo!就發(fā)現(xiàn)幾乎所有工作都和相互協(xié)作有關(guān)。整個(gè)團(tuán)隊(duì)就像把不同的動(dòng)物糾集在一起。我所加入的第一個(gè)團(tuán)隊(duì)是My Yahoo!團(tuán)隊(duì),這個(gè)團(tuán)隊(duì)非常龐大,比我之前工作過(guò)的任何團(tuán)隊(duì)都要大。團(tuán)隊(duì)里也有很多成型的編程指南,我有很多需要學(xué)習(xí)的東西。新技術(shù)、新流程以及新工具一股腦地展現(xiàn)在我面前。我花了大量的時(shí)間來(lái)學(xué)習(xí)這些新環(huán)境,吸收新知識(shí),而這些知識(shí)是我從大學(xué)里接觸不到的。在這里我完全沉浸在知識(shí)的海洋里,感覺(jué)自己像被重塑了一般。
幾個(gè)月后,我開(kāi)始遇到一些問(wèn)題。我所習(xí)慣的開(kāi)發(fā)流程并不是總能好好工作。有不少人以不同的方式來(lái)做事,這導(dǎo)致了很多bug。我的主管發(fā)現(xiàn)了這一苗頭,一天他把我叫到一邊,告訴我他希望我來(lái)負(fù)責(zé)梳理我們的開(kāi)發(fā)?,F(xiàn)在回想起他的話依然是那么鼓舞人心:“你寫(xiě)的代碼都可以運(yùn)行得很好,很少出bug。我希望其他人都像你一樣寫(xiě)代碼。”就這樣,我打算著手為My Yahoo!前端開(kāi)發(fā)團(tuán)隊(duì)注入一些結(jié)構(gòu)和規(guī)范。
我為My Yahoo!團(tuán)隊(duì)做的工作非常成功,最終我被遴選為2008年Yahoo!新版首頁(yè)的首席前端工程師。這次委任讓我有機(jī)會(huì)將代碼組織和測(cè)試高質(zhì)量代碼的技巧,應(yīng)用于一個(gè)擁有20名前端工程師的團(tuán)隊(duì),讓這20名工程師只開(kāi)發(fā)一種(風(fēng)格的)代碼。通過(guò)幾個(gè)月的學(xué)習(xí)和調(diào)整,這個(gè)團(tuán)隊(duì)的生產(chǎn)效率和產(chǎn)品質(zhì)量達(dá)到了一個(gè)很高的水平,讓很多人嘆為觀止。不管是誰(shuí)寫(xiě)的代碼,它們都看起來(lái)像出自一個(gè)人之手,此外,多數(shù)工程師都可以快速地接手別人的工作來(lái)修復(fù)bug或開(kāi)發(fā)新功能。在此期間,作為一個(gè)工程師團(tuán)隊(duì)所產(chǎn)出的業(yè)績(jī),在過(guò)去的幾年里一直是我職業(yè)生涯的最大亮點(diǎn)。
我在Yahoo!的這段時(shí)間都是在參與大型的團(tuán)隊(duì)開(kāi)發(fā),我將在此期間積累的所有經(jīng)驗(yàn)和方法整理出來(lái)成書(shū)于此。所討論的主題也體現(xiàn)了我的這種蛻變,我從一名我行我素的獨(dú)行俠,蛻變?yōu)橐幻浖こ處?,一名團(tuán)隊(duì)協(xié)作者,我放棄了我身上固有的俠氣和個(gè)性,來(lái)讓整個(gè)團(tuán)隊(duì)以更高的水準(zhǔn)運(yùn)作。這正是這本書(shū)的內(nèi)容:如何站在團(tuán)隊(duì)的角度去寫(xiě)JavaScript代碼。
開(kāi)發(fā)者最不容易理解的事情是,我們?yōu)楹涡枰ㄟ@么多時(shí)間來(lái)“維護(hù)”代碼。很少有人會(huì)打開(kāi)一個(gè)文本編輯器從頭開(kāi)始寫(xiě)代碼。大多數(shù)時(shí)間里,你面對(duì)的都是已經(jīng)寫(xiě)好的代碼。以一種可維護(hù)的方式來(lái)寫(xiě)代碼,可以讓你和協(xié)作者很容易就知道上段代碼寫(xiě)到什么地方什么程度。正如我在Yahoo!時(shí)常說(shuō)的:“當(dāng)你開(kāi)始工作時(shí),你不是在給你自己寫(xiě)代碼,而是為后來(lái)人寫(xiě)代碼。”
本書(shū)收集了很多關(guān)于JavaScript編程規(guī)范的討論。“Java語(yǔ)言編碼規(guī)范”(Code Conventions for the Java Programming Language) 是當(dāng)前最流行的關(guān)于編碼規(guī)范的文檔之一,它指出編碼規(guī)范如此重要的幾個(gè)原因。
軟件生命周期中80%的成本消耗在了維護(hù)上。
幾乎所有的軟件維護(hù)者都不是它的最初作者。
編碼規(guī)范提高了軟件的可讀性,它讓工程師能夠快速且充分地理解新的代碼。
如果你將源碼作為產(chǎn)品來(lái)發(fā)布,你需要確保它是可完整打包的,且像你創(chuàng)建的其他產(chǎn)品一樣整潔。
這些原因在今天看來(lái)依然適用。本書(shū)所討論的編程規(guī)范也是著眼于幫助你和你的團(tuán)隊(duì)寫(xiě)出高效的JavaScript代碼。
因?yàn)槟阏陂喿x這本書(shū),你需要對(duì)本書(shū)提到的一些建議保持開(kāi)放的心態(tài)。要知道這里說(shuō)的很多技術(shù),真正的目標(biāo)是解決多人開(kāi)發(fā)的環(huán)境中很多工程師如何書(shū)寫(xiě)統(tǒng)一風(fēng)格的代碼的問(wèn)題。作為團(tuán)隊(duì)的一員,意味著做出這種決策不僅對(duì)個(gè)人有好處,對(duì)于團(tuán)隊(duì)也同樣有好處。對(duì)于個(gè)人來(lái)說(shuō),需要在一定程度上犧牲個(gè)人偏好、個(gè)人觀點(diǎn)甚至個(gè)人英雄主義。你所收獲的是一個(gè)能做大事的高效的團(tuán)隊(duì),我希望這本書(shū)可以幫助你做到這一點(diǎn)。