八個(gè)改善Java遺留系統(tǒng)的技巧摘要:該文作者精心挑選出來(lái)的八個(gè)技巧,都是易于采用,并風(fēng)險(xiǎn)相對(duì)較低。但還有很多其他的方式來(lái)改善遺留應(yīng)用,讓應(yīng)用改善后看起來(lái)就像是新的一樣。 你沒看錯(cuò),就是這個(gè)題目:即使是Java系統(tǒng)也會(huì)變成“遺留”系統(tǒng)。每當(dāng)我們想起遺留系統(tǒng)時(shí),我們就會(huì)想起那些存儲(chǔ)著大量文件數(shù)據(jù)并只能用COBOL訪問(wèn)的嘎吱嘎吱作響的大型主機(jī)。但事實(shí)是,Java已經(jīng)是一門具有15年歷史的開發(fā)語(yǔ)言,用Java寫就的成千上萬(wàn)的系統(tǒng)已經(jīng)成功運(yùn)行了十年甚至更久。 因此,考慮到許多讀者都會(huì)工作在某個(gè)遺留的Java系統(tǒng)上,我根據(jù)自己的經(jīng)驗(yàn)特地?cái)€了這八個(gè)技巧,來(lái)幫助團(tuán)隊(duì)更新和激活他們的遺留Java應(yīng)用。 技巧1:使用分析器分析器提供了任何其他工具無(wú)法提供的功能,從而能夠深入檢查你的應(yīng)用。如果你的應(yīng)用已經(jīng)有一年多時(shí)間沒有被分析過(guò)了,那么它肯定會(huì)有大塊大塊的低效代碼,潛伏在某個(gè)黑暗的角落。市面上有許多不同的或免費(fèi)或商業(yè)的分析器。對(duì)于CPU分析,我最喜歡的是JProfiler,因?yàn)樗銐驈?qiáng)大能分析出大多數(shù)問(wèn)題,同時(shí)易于設(shè)置,尤其當(dāng)你使用它內(nèi)建的設(shè)置向?qū)У臅r(shí)候。而診斷內(nèi)存問(wèn)題時(shí),我最親睞的工具是Eclipse Memory Analyzer,因?yàn)樗褂玫氖怯涗浽诖疟P上的索引,而不是把整個(gè)堆的快照放到內(nèi)存中。 通常來(lái)說(shuō),隱藏著的易耗盡CPU的代碼包括低效的hashCode()或者equals()方法(在卷動(dòng)JTable時(shí)以及使用Java collection類時(shí),它們會(huì)被調(diào)用上百萬(wàn)次),以及一些出人意料的出自Sun之手的低效類,比如SimpleDateFormat。 分析器可能會(huì)明顯地讓你的應(yīng)用變得很慢,所以你一定要在測(cè)試環(huán)境中使用它。 技巧2:監(jiān)控?cái)?shù)據(jù)庫(kù)使用狀況分析器除了可以顯示你的應(yīng)用過(guò)度占用CPU時(shí)鐘的細(xì)節(jié),它們也可以對(duì)你的應(yīng)用在哪些地方長(zhǎng)時(shí)間做了數(shù)據(jù)庫(kù)的操作給出提示。但更好的用來(lái)監(jiān)控?cái)?shù)據(jù)使用的工具,是像Proactive DBA或者HP Diagnostics,或者任何其他來(lái)自于你的數(shù)據(jù)庫(kù)產(chǎn)品廠商的工具。這些工具可以告訴你,哪些代碼做了長(zhǎng)時(shí)間的SQL調(diào)用,以及哪些代碼在短時(shí)間內(nèi)對(duì)同一行做了多次調(diào)用。來(lái)自數(shù)據(jù)庫(kù)廠商的工具還可以幫助發(fā)現(xiàn)那些阻塞了其他調(diào)用的查詢;雖然在我的經(jīng)驗(yàn)里,這樣的阻塞問(wèn)題基本不過(guò)是些簡(jiǎn)單的、低效的SQL用法。 我寫了一個(gè)新的工具叫做jdbcGrabber,它可以讓你以可視化的形式描述出哪些代碼正在訪問(wèn)哪些數(shù)據(jù)表。通過(guò)這種可視化呈現(xiàn),你可以很容易發(fā)現(xiàn)那些多次訪問(wèn)數(shù)據(jù)庫(kù)中不同部分信息的代碼,從而將其調(diào)整為一次合并的請(qǐng)求。 技巧3:構(gòu)建和部署自動(dòng)化許多遺留系統(tǒng)缺乏一種完全自動(dòng)化的方式,來(lái)構(gòu)建它們的代碼,更不用說(shuō)自動(dòng)部署了。自動(dòng)化構(gòu)建和部署對(duì)于提高遺留系統(tǒng)開發(fā)者的效率來(lái)說(shuō),是一種簡(jiǎn)單直接而又低風(fēng)險(xiǎn)的方式,而且通常不需要修改代碼。 沒有自動(dòng)化的構(gòu)建和部署過(guò)程,新的開發(fā)者不得不重新發(fā)明輪子,跟那些前輩們?cè)缇投窢?zhēng)過(guò)的同樣問(wèn)題重新來(lái)斗,而且每次重復(fù)的部署問(wèn)題發(fā)生,開發(fā)者都會(huì)發(fā)明出不同的解決方案。 雖然Maven是一款卓越的而且使用廣泛的構(gòu)建工具,但它對(duì)你的源碼樹結(jié)構(gòu)以及庫(kù)依賴有著固執(zhí)的要求,所以把它用在遺留應(yīng)用中會(huì)有點(diǎn)困難。但足夠優(yōu)秀的Ant應(yīng)該更易于使用,因?yàn)樗幚砥疬z留代碼結(jié)構(gòu)更加靈活,也更容易部分采用,而不是全盤采用。 技巧4:自動(dòng)化你的操作并使用JMX另外一種提高遺留應(yīng)用的效率但不會(huì)帶來(lái)修改代碼的風(fēng)險(xiǎn)的方式是,改善它的運(yùn)維。許多內(nèi)部開發(fā)的企業(yè)系統(tǒng),一般都需要大量出人意料的手把手指導(dǎo)和維護(hù),即使這樣是不應(yīng)該的。 既有的Java功能可以通過(guò)使用JMX很容易地暴露給負(fù)責(zé)運(yùn)營(yíng)的人們,而不會(huì)帶來(lái)負(fù)面影響。許多開發(fā)者對(duì)JMX比較熟悉是因?yàn)?,他們用JMX來(lái)跟JBoss和WebLogic這樣的應(yīng)用服務(wù)器進(jìn)行交互,但他們不清楚把JMX用在他們自己的應(yīng)用中是多么方便。任何Java class都可以通過(guò)JMX暴露出來(lái),幾乎沒什么負(fù)面效果,也沒有什么風(fēng)險(xiǎn)。 比如,如果你的應(yīng)用有一個(gè)本地的靜態(tài)HashMap作為cache,你就可以通過(guò)JMX來(lái)暴露功能,從而很容易地清除那個(gè)cache。 一旦應(yīng)用通過(guò)JMX暴露,運(yùn)維團(tuán)隊(duì)或者開發(fā)者就可以以良好的方式來(lái)操作應(yīng)用,無(wú)需直接訪問(wèn)運(yùn)行著應(yīng)用的機(jī)器。 技巧5:創(chuàng)建單元測(cè)試一旦你對(duì)遺留系統(tǒng)的修改破壞了某個(gè)功能,你所面臨的最大障礙之一就來(lái)到了。一些工具宣稱能對(duì)代碼進(jìn)行反向工程,并為其創(chuàng)建單元測(cè)試,但我對(duì)這些工具沒有太多的信心。要想有足夠的信心,你的單元測(cè)試的確覆蓋了你期望它們覆蓋的代碼,你就不得不親自創(chuàng)建它們。 很幸運(yùn),為遺留代碼創(chuàng)建單元測(cè)試并沒有一開始感覺上的那樣困難。我使用了Michale Feathers在Working Effectivelywith Legacy Code一書中講解的“遺留代碼修改算法”:
有效使用這個(gè)算法的竅門在于第3點(diǎn):打破依賴。有很多技術(shù)可以用來(lái)干這個(gè),但其中大多數(shù)都是關(guān)于移除靜態(tài)引用以及在接口和facade下隱藏外部引用和復(fù)雜代碼。一旦你具有這樣打破依賴的感覺了,接觸遺留代碼就不會(huì)是一件讓你提心吊膽的事情了。 技巧6:殺死無(wú)用代碼雖然無(wú)用代碼可能看起來(lái)無(wú)害,但它們實(shí)際上往往會(huì)是無(wú)聲的殺手。原因在于只要無(wú)用代碼還在代碼庫(kù)中,負(fù)責(zé)維護(hù)的程序員就不會(huì)非常確信,代碼是真的無(wú)用還是只是看起來(lái)無(wú)用。感受過(guò)前幾次修改所帶來(lái)的痛苦的維護(hù)者都知道,即使是靜態(tài)代碼分析也不能證明代碼是真的無(wú)用了。比如,十年前一些聰明的程序員可能會(huì)通過(guò)數(shù)據(jù)庫(kù)中的字符串值來(lái)驅(qū)動(dòng)Java reflection調(diào)用業(yè)務(wù)邏輯(別笑,我不止一次看到過(guò)這樣)。 因此,殺死無(wú)用代碼應(yīng)用是第一優(yōu)先級(jí)的任務(wù)。雖然Emma通常被認(rèn)為是一種單元測(cè)試覆蓋工具,但它可以用來(lái)偵測(cè)無(wú)用代碼。當(dāng)你把Emma注入到JVM中,它就可以追蹤到哪些代碼執(zhí)行了,哪些沒有。在你的開發(fā)環(huán)境中,把Emma和一個(gè)完整的測(cè)試周期相結(jié)合使用,你就會(huì)知道哪些代碼活著還是死了。 技巧7:采用一種“順從”方式構(gòu)建代碼遺留應(yīng)用不可能一次清理完畢。在現(xiàn)實(shí)中,開發(fā)團(tuán)隊(duì)必須利用任何一次機(jī)會(huì),來(lái)改善遺留代碼。但許多團(tuán)隊(duì)對(duì)目前代碼的情況都倍感失望,而無(wú)法考慮他們究竟該怎么做?!按a實(shí)在太糟糕了,”開發(fā)者說(shuō)。 冷漠是最大的錯(cuò)誤。遺留應(yīng)用之所以還存活著是因?yàn)?,它們依然有用,而且和所有有用的?yīng)用一樣,他們的用戶會(huì)繼續(xù)想要修改它們。如果團(tuán)隊(duì)抓住機(jī)會(huì)定義一個(gè)可以達(dá)到的愿景:希望應(yīng)用會(huì)是什么樣子,然后做出逐步增量的改變,他們就會(huì)離距離最終的愿景更進(jìn)一步。 沒有這樣的愿景,團(tuán)隊(duì)的每個(gè)成員就會(huì)做出任何他/她所認(rèn)為最正確的事情。一個(gè)人會(huì)使用Spring JdbcTemplate而另一個(gè)人會(huì)開始使用iBATIS/MyBatis。雖然每個(gè)人都真正期望改善這個(gè)應(yīng)用,但事實(shí)上他們會(huì)讓事情變得更糟,因?yàn)樗麄兪窃诓煌姆较蛏鲜沽?,使已?jīng)復(fù)雜的結(jié)構(gòu)更加混亂。 技巧8:升級(jí)你的JRE當(dāng)我告訴一些團(tuán)隊(duì)Sun(現(xiàn)在是Oracle)早在2009年11月就已經(jīng)宣稱不在繼續(xù)對(duì)JDK 1.5的支持時(shí),他們?nèi)匀挥X得驚訝不已。這不僅僅是立刻要升級(jí)JRE到1.6的事情。那些歷經(jīng)磨難的團(tuán)隊(duì),還記得從1.1升級(jí)到1.2或者1.4升級(jí)到1.5時(shí)所發(fā)生的一切,他們可能對(duì)這樣的升級(jí)還感到猶豫。但我的經(jīng)驗(yàn)是,這樣的升級(jí)會(huì)很平滑,而且會(huì)給應(yīng)用帶來(lái)一次顯著的免費(fèi)的性能飛躍。另外,JDK 1.6還帶來(lái)許多有用的、免費(fèi)的運(yùn)維和分析工具,來(lái)幫助診斷那些你這些年一直備受困擾的垃圾回收問(wèn)題。 八個(gè)技巧之外上面精心挑選出來(lái)的每個(gè)技巧,基本都是易于采用,并風(fēng)險(xiǎn)相對(duì)要低。但還有很多其他的方式來(lái)改善遺留應(yīng)用,讓應(yīng)用改善后看起來(lái)就像是新的一樣。 首先,現(xiàn)在的開放源代碼庫(kù)生態(tài)系統(tǒng)給過(guò)去大部分的遺留Java系統(tǒng)帶來(lái)了生機(jī)。許多遺留系統(tǒng)會(huì)有土生土長(zhǎng)、完全自定義的各種子系統(tǒng):工作流引擎、規(guī)則引擎、模板引擎、用戶接口框架以及對(duì)象關(guān)系映射層等等。這些土生土長(zhǎng)的組件中的任意一個(gè),都可以被一個(gè)免費(fèi)的開放源代碼庫(kù)替換掉,而且更加智能并足夠強(qiáng)壯。這樣一對(duì)一的替換可以很大程度上消除一次全部替換所帶來(lái)的維護(hù)上的困難。 其次,是時(shí)候好好看看你自己的遺留應(yīng)用的設(shè)計(jì)問(wèn)題了。雖然改變?cè)O(shè)計(jì)遠(yuǎn)比僅僅升級(jí)JRE要復(fù)雜得多,但它也會(huì)給你的投資帶來(lái)更大的回報(bào)。對(duì)于大量邏輯都存儲(chǔ)在數(shù)據(jù)庫(kù)存儲(chǔ)過(guò)程中的應(yīng)用,可以考慮把那些邏輯提高到應(yīng)用層,從而可以受益于集群服務(wù)器,并更容易進(jìn)行單元測(cè)試。如果一個(gè)設(shè)計(jì)把表示層跟業(yè)務(wù)邏輯層綁定得太緊,那你就可以把它們分開,這樣增加新潮的iPhone界面也會(huì)很容易實(shí)現(xiàn)。在各個(gè)子系統(tǒng)之間的同步調(diào)用也可以轉(zhuǎn)換成異步、基于消息的調(diào)用,這在彈性和性能上都會(huì)是重要的改善。 最后,為了讓你從Java遺留應(yīng)用中多活兩到四年,我建議你雇傭一個(gè)對(duì)這樣系統(tǒng)有經(jīng)驗(yàn)的專家。就像一個(gè)外科醫(yī)生做精妙的大腦手術(shù)一樣,有經(jīng)驗(yàn)的專家通??梢詾檫z留系統(tǒng)中的問(wèn)題找到更好的解決方案,從而帶來(lái)更多的好處以及低風(fēng)險(xiǎn)。 對(duì)于那些期望吸取更深內(nèi)容的讀者,我建議這本我讀過(guò)的最好的關(guān)于遺留系統(tǒng)的書:Michale Feather的Working Effectivelywith Legacy Code。任何工作在遺留系統(tǒng)上的開發(fā)者都會(huì)從這本書中受益。 關(guān)于作者 Tim Cull是一個(gè)有經(jīng)驗(yàn)的軟件開發(fā)人員和架構(gòu)師。作為Thedwick LLC(一家專注于高層次軟件開發(fā)的精品軟件咨詢公司)的創(chuàng)始人,他已經(jīng)幫助過(guò)很多客戶擴(kuò)展并增強(qiáng)他們的遺留Java系統(tǒng),并保護(hù)他們的技術(shù)投資。 |
|