|
英文原文:Tips to Developers Starting on Large Applications
假如你是一名Java開(kāi)發(fā)者,正在開(kāi)發(fā)和維護(hù)包含2000個(gè)類并使用了很多框架的應(yīng)用程序。你要如何理解這些代碼呢?在典型的Java企業(yè)項(xiàng)目小組中,大部分能夠幫你的高級(jí)工程師看起來(lái)都很忙,文檔也很少。你需要盡快交付成果,并向項(xiàng)目組證明自己的能力。你會(huì)如何處理這種狀況呢?這篇文章為開(kāi)始開(kāi)發(fā)新項(xiàng)目的Java開(kāi)發(fā)者提供了一些建議。
1. 不要試圖一下子搞懂整個(gè)項(xiàng)目
仔細(xì)考慮一下,為什么你會(huì)想要先理解項(xiàng)目代碼呢?大部分情況是有人要求你修復(fù)一個(gè)bug,或者增強(qiáng)系統(tǒng)已有功能。你要做的第一件事情不是理解整個(gè)項(xiàng)目的架構(gòu)。當(dāng)對(duì)項(xiàng)目進(jìn)行維護(hù)時(shí),這樣做(理解整個(gè)項(xiàng)目架構(gòu))可能會(huì)對(duì)你造成巨大的壓力。
即便是有10年編程經(jīng)驗(yàn)的Java開(kāi)發(fā)者,也無(wú)法理解項(xiàng)目的核心工作機(jī)制,盡管他們可能已經(jīng)在這個(gè)項(xiàng)目工作超過(guò)一年(假設(shè)他們并非最初的開(kāi)發(fā)人員)。比如,對(duì)于認(rèn)證機(jī)制或事務(wù)管理機(jī)制還是缺乏確切的認(rèn)識(shí)。
他們是怎么做的呢?他們對(duì)于自己負(fù)責(zé)的部分非常了解,并且能夠交付價(jià)值給小組。每天的交付價(jià)值遠(yuǎn)比了解一些以后還不確定有沒(méi)有的東西重要的多。
2. 關(guān)注于盡快交付價(jià)值
那我是要打消你對(duì)于理解項(xiàng)目架構(gòu)的熱情嗎?完全不是。我只是要求你盡早地交付價(jià)值,一旦你開(kāi)始一個(gè)項(xiàng)目,搭建了開(kāi)發(fā)環(huán)境,你就不應(yīng)該花一兩周時(shí)間才交付內(nèi)容,無(wú)論它的規(guī)模大小如何。假如你是一位有經(jīng)驗(yàn)的程序員,卻兩周都沒(méi)有任何交付,你的經(jīng)理怎么會(huì)知道你是真的在工作,還是在看新聞呢?。
所以交付能夠?qū)⑹虑樽兊煤?jiǎn)單。不要認(rèn)為在做有價(jià)值的交付前,你必須理解整個(gè)項(xiàng)目。這是完全錯(cuò)誤的。加一段Javascript的驗(yàn)證代碼對(duì)業(yè)務(wù)就很有價(jià)值,經(jīng)理能夠通過(guò)你的交付對(duì)你更加信任。這樣能夠向上級(jí)領(lǐng)導(dǎo)證明你的貢獻(xiàn)以及員工價(jià)值。
日復(fù)一日,在不斷修復(fù)bug及增強(qiáng)功能之后,你就能夠慢慢開(kāi)始理解項(xiàng)目架構(gòu)。不要低估對(duì)系統(tǒng)方方面面理解時(shí)需要花費(fèi)的時(shí)間?;?到4天理解認(rèn)證機(jī)制,2到3天理解事務(wù)管理。這些都是依靠之前的相似項(xiàng)目的經(jīng)歷,但關(guān)鍵還是要花時(shí)間才能透徹的理解。要在日常工作中擠出時(shí)間,不要向經(jīng)理要求特定的時(shí)間來(lái)做這些。
找找項(xiàng)目是否有一些有效維護(hù)的單元測(cè)試用例。有效的單元測(cè)試用例是理解大型項(xiàng)目代碼很好的途徑。單元測(cè)試能夠幫助你理解代碼片段,包括一個(gè)單元的外部接口(單元如何被調(diào)用以及返回內(nèi)容)及其內(nèi)部實(shí)現(xiàn)(調(diào)試單元測(cè)試比調(diào)試整個(gè)實(shí)際用例簡(jiǎn)單許多)。
你如果能夠很好的理解一些內(nèi)容,那么就寫(xiě)些筆記,或者畫(huà)些類圖、時(shí)序圖、數(shù)據(jù)模型圖等,以便你或日后其他的開(kāi)發(fā)者可以進(jìn)行維護(hù)。
3. 維護(hù)大型項(xiàng)目所必須的技能
你能從事當(dāng)前的工作,必然已經(jīng)具有良好的Java技術(shù)。我們來(lái)談?wù)勀軌蜃屇阍谛马?xiàng)目中良好表現(xiàn)的其他技能。大部分時(shí)間里,你在項(xiàng)目中的任務(wù)是修復(fù)bug和增強(qiáng)功能。
有兩項(xiàng)很重要的技能能夠在你維護(hù)大型項(xiàng)目代碼起到幫助。
3. 1 能夠迅速發(fā)現(xiàn)需要的類
在任何維護(hù)活動(dòng)中,無(wú)論是修復(fù)bug或增強(qiáng)功能,第一件事情就是識(shí)別出當(dāng)前修復(fù)或增強(qiáng)的用例中調(diào)用的類。當(dāng)你定位到需要修復(fù)或增強(qiáng)的類/方法,就已經(jīng)完工了一半。
3. 2 能夠分析變更的影響
當(dāng)你在完成必要的修改或增強(qiáng)工作后,最重要的就是要確認(rèn)你的修改沒(méi)有破壞代碼的其他部分。你要用你的Java技術(shù)及對(duì)其他框架的理解找出變更可能影響的部分。下面兩個(gè)簡(jiǎn)單的例子詳細(xì)描述了最后提及的情況:
- 當(dāng)類A的equals()方法變更后,調(diào)用保存A實(shí)例的List的contains()方法時(shí)就會(huì)受到影響。若Java知識(shí)不夠,就很難考慮到這樣的影響。
- 在web項(xiàng)目中,我們假設(shè)“user id”保存在session中。新加入的程序員可能在“user id”中加入一些信息來(lái)修復(fù)bug,但是卻不知道那會(huì)影響到 與“user id”關(guān)聯(lián)的用例。
因此,既要深入了解Java語(yǔ)言,又要深入了解你在應(yīng)用中使用的框架,這樣才能分析出一個(gè)改變的影響。
當(dāng)你提高了如上兩個(gè)技能,盡管你對(duì)項(xiàng)目不是非常了解,但大部分的維護(hù)任務(wù)會(huì)變得簡(jiǎn)單很多。如果你想要修復(fù)一個(gè)bug,就會(huì)定位并修復(fù)這個(gè)bug,并且保證變更不會(huì)破壞項(xiàng)目的其他部分。如果你想要增強(qiáng)或加入特性,基本上你只需要模仿現(xiàn)有的特性,使用類似的設(shè)計(jì)。
在一個(gè)在線銀行項(xiàng)目中,為什么“查看賬戶摘要”和“查看交易歷史”的設(shè)計(jì)要有巨大的差別呢?如果你理解了“查看賬戶摘要”的設(shè)計(jì),完全可以模仿開(kāi)發(fā)出“查看交易歷史”的功能。
就修復(fù)bug和增強(qiáng)來(lái)說(shuō),你不必完全理解所有2000個(gè)類的工作內(nèi)容和代碼驅(qū)動(dòng)系統(tǒng)運(yùn)行的原理。只要有上面的技能,你就能很快定位需要修改的代碼,使用良好的Java和框架技能修復(fù),保證變更不會(huì)破壞項(xiàng)目的其他部分,然后交付,盡管你可能只知道一小部分項(xiàng)目的設(shè)計(jì)。
4. 使用工具找到所需變更內(nèi)容以及變更產(chǎn)生的影響
繼續(xù)我們盡快交付的主題,你應(yīng)該尋找工具作為輔助,只需要對(duì)項(xiàng)目又很少理解,就能幫助你盡快實(shí)施交付。
4. 1 迅速發(fā)現(xiàn)所需變更內(nèi)容的工具
無(wú)論是修復(fù)bug還是增強(qiáng)系統(tǒng),首先你都要找到該用例調(diào)用且需要修改的類及方法?;旧嫌袃煞N方式理解用例的工作方式,靜態(tài)代碼分析和運(yùn)行時(shí)分析。
源碼分析統(tǒng)計(jì)會(huì)掃描所有代碼并且展現(xiàn)類之間的關(guān)系。市場(chǎng)上有很多工具。比如:Architexa、AgileJ、UModel、Poseidon等。
所有靜態(tài)代碼分析工具的缺點(diǎn)在于,它們無(wú)法確切展現(xiàn)用例中類或方法的運(yùn)行時(shí)調(diào)用情況。因此Java新加入了一些特性,如回調(diào)機(jī)制(callback patterns)。比方說(shuō),靜態(tài)分析工具無(wú)法推斷出當(dāng)前頁(yè)面提交按鈕被點(diǎn)擊時(shí),會(huì)調(diào)用哪個(gè)Servlet。
運(yùn)行時(shí)分析工具能夠展現(xiàn)類和方法在用例運(yùn)行時(shí)的狀態(tài)。這樣的工具包括:MaintainJ、Diver、jSonde、Java Call Tracer等。這些工具可以捕獲運(yùn)行時(shí)的堆棧狀態(tài),并以此為用例生成序列圖和類圖。
序列圖會(huì)展現(xiàn)該用例在運(yùn)行時(shí)所有調(diào)用的方法。如果你在修復(fù)bug,那么這個(gè)bug很可能就是這些被調(diào)用的方法之一。
如果你在增強(qiáng)已有功能,可能是新增驗(yàn)證,修改DAO等,那么就可以利用序列圖理解調(diào)用流程然后再修改。
如果你在新增功能,那么就可以找到一些相似的特性,利用序列圖理解調(diào)用流程,然后模仿開(kāi)發(fā)新功能。
要仔細(xì)地挑選運(yùn)行時(shí)分析工具。信息過(guò)多是這類工具的主要問(wèn)題。選擇一些工具,能夠提供簡(jiǎn)單的信息,過(guò)濾掉無(wú)效信息,并能夠方便的查看各種視圖。
4. 2 迅速發(fā)現(xiàn)所需變更內(nèi)容的工具
若單元測(cè)試有效,你就可以通過(guò)運(yùn)行單元測(cè)試發(fā)現(xiàn)變更有沒(méi)有破壞其他測(cè)試用例。有效維護(hù)并且覆蓋大型企業(yè)應(yīng)用的單元測(cè)試還是比較少的。下面有一些針對(duì)該情況的工具。
在此,仍然是有兩種技術(shù)——靜態(tài)代碼分析和運(yùn)行時(shí)分析——可以使用。市場(chǎng)中有很多靜態(tài)代碼分析工具可用。如:Lattix、Structure101、Coverity、nWire和IntelliJ's DSM。
對(duì)于變更后的類,上述工具均可識(shí)別對(duì)該類存在依賴的類的集合。開(kāi)發(fā)者需要根據(jù)這些信息“猜測(cè)”可能產(chǎn)生影響的用例,因?yàn)檫@些工具無(wú)法展示運(yùn)行時(shí)類之間的調(diào)用關(guān)系。
市場(chǎng)上可以用于運(yùn)行時(shí)影響分析的工具并不多,可能只有MaintainJ。MaintainJ先會(huì)捕獲在用例中調(diào)用的所有類和方法。當(dāng)所有用例的上述信息都被捕獲之后,就很容易發(fā)現(xiàn)類的變更對(duì)用例的影響。MaintainJ能夠有效工作的前提條件就是項(xiàng)目的所有用例都應(yīng)當(dāng)先運(yùn)行一遍,以便能夠獲得運(yùn)行時(shí)的依賴關(guān)系。
總之,目前你在迅速準(zhǔn)確分析變更影響方面,還是可以從工具中獲得有限的幫助。首先根據(jù)需要實(shí)施一些影響分析,然后根據(jù)自己或小組其他高級(jí)成員評(píng)審來(lái)判斷變更的影響。你可能需要使用上述工具對(duì)你的判斷進(jìn)行反復(fù)確認(rèn)。
5. 對(duì)上述內(nèi)容的兩個(gè)忠告
5. 1 不要降低代碼質(zhì)量
為了快速交付,可以不全盤(pán)理解架構(gòu),但絕不能以降低代碼質(zhì)量為條件。下面是一些你可能因?yàn)橹豢紤]快速交付而引發(fā)的代碼質(zhì)量問(wèn)題。
因?yàn)樾薷拇a涉及到很多的依賴關(guān)系,所以新增代碼相對(duì)而言風(fēng)險(xiǎn)較小。例如,有五個(gè)用例都調(diào)用了某個(gè)方法。為了改進(jìn)某個(gè)用例,你需要修改這個(gè)方法的實(shí)現(xiàn)。最簡(jiǎn)單的做法就是復(fù)制這個(gè)方法,重命名,然后在改進(jìn)的用例中調(diào)用新方法。千萬(wàn)不要這么做。代碼冗余絕對(duì)是非常有害的。你要嘗試對(duì)方法進(jìn)行包裝或者重寫(xiě),甚至是直接修改,然后重新測(cè)試所有用例,通常停下來(lái)想一想,然后親手去實(shí)施,是一種不錯(cuò)的方式。
另一個(gè)例子是將“private”方法改為“public”,讓別的類也可以調(diào)用。盡量不要將非必須的部分暴露出來(lái)。假如是為了更好的設(shè)計(jì)而需要重構(gòu),那么就應(yīng)當(dāng)著手去做。
大部分應(yīng)用都有確定的結(jié)構(gòu)和模式來(lái)實(shí)施。修復(fù)或增強(qiáng)程序時(shí),你要確保不會(huì)偏離這樣的模式。如果對(duì)規(guī)約不確定,那么就請(qǐng)其他高級(jí)開(kāi)發(fā)者來(lái)審核你的變更。如果你必須做一些違背規(guī)約的動(dòng)作,那么就盡量放置于規(guī)模較小的類中(一個(gè)200行代碼的類中的私有函數(shù)應(yīng)當(dāng)不會(huì)影響應(yīng)用的整體設(shè)計(jì))
5. 2 不要停止深入理解項(xiàng)目架構(gòu)
按照文章列出的方式,假設(shè)你能夠在對(duì)項(xiàng)目了解較少的情況下進(jìn)行交付,并持續(xù)這樣下去,可能就會(huì)停止對(duì)項(xiàng)目架構(gòu)的深入了解。這從長(zhǎng)遠(yuǎn)角度來(lái)說(shuō)對(duì)你的職業(yè)生涯沒(méi)有幫助。當(dāng)你的經(jīng)驗(yàn)增加時(shí),就會(huì)承擔(dān)比較大的模塊任務(wù)。如構(gòu)建一個(gè)完整的新特性,或者修改項(xiàng)目的一些基礎(chǔ)設(shè)計(jì)等較大的改進(jìn)。當(dāng)能夠做這些改進(jìn)時(shí),你對(duì)項(xiàng)目的整體架構(gòu)應(yīng)該相當(dāng)了解。文中列舉的方法只是讓你在最短的時(shí)間內(nèi)提升自己,而不是阻止你完整理解整個(gè)項(xiàng)目。
6. 結(jié)論
整篇文章的重點(diǎn)在于,對(duì)項(xiàng)目進(jìn)行必要了解,然后進(jìn)行快速交付。你可以在不降低代碼質(zhì)量的前提下做到這一點(diǎn)。
如果要修復(fù)bug,那么迅速定位并修復(fù)。可以在必要的時(shí)候使用運(yùn)行時(shí)分析工具。如果要新增特性,那么就可以尋找類似特性,理解流程(在必要的時(shí)候使用工具)并編寫(xiě)。
或許這些聽(tīng)起來(lái)很簡(jiǎn)單,但是實(shí)用嗎?當(dāng)然。前提是你有良好的Java技術(shù),以及對(duì)框架足夠了解,然后才能先修改代碼,再分析變更所產(chǎn)生的影響。分析變更所產(chǎn)生的影響比實(shí)施變需要更多技巧。你可能需要高級(jí)開(kāi)發(fā)人員協(xié)助你分析變更影響。
大約有50%的IT可操作預(yù)算用于簡(jiǎn)單的bug修復(fù)和功能增強(qiáng)。文中的建議對(duì)于在維護(hù)活動(dòng)中節(jié)省經(jīng)費(fèi)應(yīng)當(dāng)還是很有幫助的。
作者Choudary Kothapalli 也是MaintainJ項(xiàng)目的創(chuàng)立者。
關(guān)于作者
Choudary Kothapalli 是 MaintainJ Inc.創(chuàng)始人。該公司提供的工具用于在維護(hù)大型Java項(xiàng)目時(shí)節(jié)省開(kāi)支。作者在開(kāi)發(fā)和維護(hù)企業(yè)級(jí)Java應(yīng)用方面已經(jīng)有15年的經(jīng)驗(yàn),并且具有Sun認(rèn)證的企業(yè)架構(gòu)師與Java開(kāi)發(fā)者資格。他目前和妻子以及2個(gè)兒子居住在加拿大多倫多。
關(guān)于譯者
陳晨, 長(zhǎng)期從事互聯(lián)網(wǎng)信息收集分析領(lǐng)域架構(gòu)研究。對(duì)海量數(shù)據(jù)處理,NoSQL等處理運(yùn)用有豐富經(jīng)驗(yàn),關(guān)注過(guò)程方法及其自動(dòng)化。他的新浪微博:一酌散千憂
it知識(shí)庫(kù):程序員開(kāi)發(fā)大型應(yīng)用程序的技巧,轉(zhuǎn)載需保留來(lái)源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。