一区二区久久-一区二区三区www-一区二区三区久久-一区二区三区久久精品-麻豆国产一区二区在线观看-麻豆国产视频

遺留系統(tǒng)的技術(shù)棧遷移

  什么是遺留系統(tǒng)(Legacy System)?根據(jù)維基百科的定義,遺留系統(tǒng)是一種舊的方法、舊的技術(shù)、舊的計(jì)算機(jī)系統(tǒng)或應(yīng)用程序[1]。這一定義事實(shí)上并沒有很好地揭露遺留系統(tǒng)的本質(zhì)。我認(rèn)為,遺留系統(tǒng)首先是一個(gè)還在運(yùn)行和使用,但已步入軟件生命周期衰老期的軟件系統(tǒng)。它符合所謂的“奶牛規(guī)則”:奶牛逐漸衰老,最終無奶可擠;然而與此同時(shí),飼養(yǎng)成本卻在上升。這意味著遺留系統(tǒng)會(huì)逐漸隨著時(shí)間的推移,不斷地增加維護(hù)成本。

  維護(hù)一個(gè)軟件系統(tǒng),就需要了解該軟件系統(tǒng)的知識(shí)。若知識(shí)缺失,就意味著這會(huì)給維護(hù)人員帶來極大的障礙和困難。從這個(gè)角度講,所謂“遺留系統(tǒng)”,就是缺少了一部分重要知識(shí),使得維護(hù)人員“知其然而不知其所以然”的軟件系統(tǒng)。

  若要讓遺留系統(tǒng)煥發(fā)青春,最徹底的做法自然是推倒重來,但這樣付出的代價(jià)太高;而且,即使對(duì)系統(tǒng)重新設(shè)計(jì)和開發(fā),仍然免不了會(huì)重蹈遺留系統(tǒng)的覆轍?;蛘撸梢詫?duì)遺留系統(tǒng)進(jìn)行重構(gòu),在不修改系統(tǒng)功能的情況下改善系統(tǒng)設(shè)計(jì)。只是這種重構(gòu)常常是對(duì)系統(tǒng)進(jìn)行重大擴(kuò)展或修改的前奏,如無絕對(duì)必要,并不推薦這種償還“技術(shù)債務(wù)(Technical Debt)”的方式。重構(gòu)應(yīng)與開發(fā)同時(shí)進(jìn)行,而不應(yīng)將其作為債務(wù)推遲到最后,以至于支付高昂的利息。最后,還有一種方式,則是對(duì)遺留系統(tǒng)進(jìn)行技術(shù)棧遷移。

  一、決策技術(shù)棧遷移的因素

  那么,為何要進(jìn)行技術(shù)棧遷移呢?是否是原有技術(shù)無法滿足新的業(yè)務(wù)需求?對(duì)于遺留系統(tǒng)而言,這種情況總是存在,即需要擴(kuò)展舊有系統(tǒng)的功能來滿足新的業(yè)務(wù)。然而,這一原因并不足以支持做出技術(shù)棧遷移的決策。因?yàn)椋瑥募夹g(shù)實(shí)現(xiàn)的角度來看,無論采取何種技術(shù),都可以實(shí)現(xiàn)各種業(yè)務(wù)功能,無非是付出的成本不同而已 。基本上,這種成本一定會(huì)低于技術(shù)棧遷移的成本。此外,當(dāng)今的軟件開發(fā),常常會(huì)將一個(gè)軟件系統(tǒng)看做是完整的生態(tài)系統(tǒng),在這個(gè)生態(tài)系統(tǒng)圈中,完全允許有多種技術(shù)平臺(tái)(包括多種語言,甚至多種數(shù)據(jù)庫范式)存在,只要我們能夠合理地劃定各個(gè)功能(或服務(wù))的邊界。

  牽涉到架構(gòu)中的任何一個(gè)重大決策,都需要綜合考量和權(quán)衡,只有充分地識(shí)別了風(fēng)險(xiǎn),才能制訂有效的設(shè)計(jì)決策。個(gè)人認(rèn)為,只有在如下幾種情形出現(xiàn)時(shí),才值得進(jìn)行技術(shù)棧遷移。

  · 原有技術(shù)不能保證新的質(zhì)量需求

  在一個(gè)系統(tǒng)的完整生命周期內(nèi),系統(tǒng)從誕生到發(fā)展,衰老和死亡,與人一樣,是不可規(guī)避的過程。對(duì)遺留系統(tǒng)進(jìn)行技術(shù)棧遷移,無非是希望通過新的技術(shù)給舊有系統(tǒng)注入活力,就像器官移植一般,對(duì)腐朽的部分進(jìn)行切除與替換。系統(tǒng)之所以會(huì)衰老,會(huì)腐朽,原因還在于需求的變化,從而導(dǎo)致系統(tǒng)結(jié)構(gòu)變得龐大而混亂。我們?cè)谶M(jìn)行技術(shù)決策時(shí),常常是根據(jù)當(dāng)下的需求以及目前現(xiàn)有的技術(shù),結(jié)合團(tuán)隊(duì)技術(shù)能力做出的最符合當(dāng)時(shí)場景的合理決策。因而,技術(shù)棧遷移的原因常常是是因?yàn)?ldquo;此一時(shí)彼一時(shí)”。在當(dāng)時(shí)場景下做出的明智決策,隨著時(shí)間的推移,會(huì)顯得不合時(shí)宜。這一點(diǎn)在質(zhì)量需求的滿足上,體現(xiàn)得尤為明顯。例如,系統(tǒng)對(duì)可伸縮性、性能、安全的要求,都可能因?yàn)樾碌馁|(zhì)量需求的提出發(fā)生變化。而這些質(zhì)量屬性往往靠舊有技術(shù)無法解決。RackSpace對(duì)日志處理的案例就屬于這一場景[2] 。RackSpace的架構(gòu)對(duì)日志的支持,先后經(jīng)歷了三個(gè)大版本的演化,從文件服務(wù)器到中心數(shù)據(jù)庫,再到MapReduce,每次技術(shù)棧的遷移都是質(zhì)量屬性的驅(qū)動(dòng),不得不為之。

  · 出于戰(zhàn)略的考慮

  這常常是因?yàn)槠髽I(yè)架構(gòu)的因素。對(duì)于一個(gè)企業(yè)而言,應(yīng)該將其IT系統(tǒng)看作是一個(gè)整體的生態(tài)系統(tǒng)。對(duì)于一個(gè)正在成長中的企業(yè)而言,必然會(huì)隨著整個(gè)企業(yè)組織結(jié)構(gòu)、業(yè)務(wù)體系的變化而影響到IT系統(tǒng)。一般而言,企業(yè)IT系統(tǒng)的架構(gòu)會(huì)存在兩種情況。第一種情況是從無到有,根據(jù)企業(yè)架構(gòu)師與業(yè)務(wù)架構(gòu)師的設(shè)計(jì),嚴(yán)格按照設(shè)計(jì)藍(lán)圖來規(guī)劃所有的IT系統(tǒng)。第二種情況則可能是多種不同的系統(tǒng)并存(可能是因?yàn)槠髽I(yè)采用了并購等方式兼并其他公司業(yè)務(wù),也可能是因?yàn)椴煌臉I(yè)務(wù)需要,購買了不同的軟件系統(tǒng))。第一種情況看似美好,但仍有可能發(fā)生規(guī)劃藍(lán)圖不能滿足需求的可能。第二種情況則處于龍蛇混雜的局面,最后可能導(dǎo)致所謂的“煙囪系統(tǒng)(Stovepipe System)[3]”,需要花大力氣對(duì)各種系統(tǒng)進(jìn)行整合。

  無論是哪一種情況,一旦做出技術(shù)棧遷移的決定,都必然是企業(yè)戰(zhàn)略上的考慮。當(dāng)然這種戰(zhàn)略指的是IT戰(zhàn)略,也可能是企業(yè)的整體戰(zhàn)略對(duì)IT系統(tǒng)產(chǎn)生影響。

  我們的一個(gè)客戶是一家大型的金融企業(yè),提供了多種品牌的保險(xiǎn)與銀行業(yè)務(wù)。企業(yè)的戰(zhàn)略目標(biāo)是在體現(xiàn)品牌價(jià)值的同時(shí),整體展現(xiàn)企業(yè)的平臺(tái)作用。這對(duì)于IT系統(tǒng)而言,就意味著需要對(duì)各種業(yè)務(wù)系統(tǒng)進(jìn)行整合、遷移。整個(gè)系統(tǒng)的主要核心是對(duì)客戶數(shù)據(jù)的管理,這些數(shù)據(jù)的管理會(huì)影響到整個(gè)企業(yè)的服務(wù)質(zhì)量、市場推廣與產(chǎn)品維護(hù)。由于該企業(yè)在銀行業(yè)與保險(xiǎn)業(yè)的發(fā)展壯大,是通過不斷的合并與兼并來促進(jìn)自身的發(fā)展。因而在其IT系統(tǒng)中,事實(shí)上存在多種不同的系統(tǒng)??蛻粜畔⑸⒙湓诓煌到y(tǒng)的數(shù)據(jù)庫中??蛻魯?shù)據(jù)的整合,不僅有利于對(duì)這些信息的管理,保證數(shù)據(jù)的一致性,還在于從市場營銷角度考慮,可以通過一致的客戶信息對(duì)客戶的情況做出全面了解,制定更好的推廣策略。

  · 原有的技術(shù)提供者不再提供支持

  這種情形最是無奈,卻時(shí)有發(fā)生。一種情況是使用的技術(shù)(平臺(tái)、框架)不再被供應(yīng)商維護(hù),這一點(diǎn)體現(xiàn)在開源項(xiàng)目上更為明顯。另一種情況則是所選的技術(shù)平臺(tái)進(jìn)行了升級(jí),卻沒有很好地提供向前兼容,使得系統(tǒng)難以隨之而升級(jí)。在架構(gòu)設(shè)計(jì)中,這種綁定具體平臺(tái)與技術(shù)的做法,實(shí)際上是反模式的一種,即“供應(yīng)商鎖定(Vendor Lock-In)[4]”。

  · 使用舊有技術(shù)的成本太高

  IT技術(shù)并非一定是新技術(shù)成本高于舊技術(shù),事實(shí)上,隨著技術(shù)的創(chuàng)新和發(fā)展,技術(shù)越新,成本越能得到更好的控制。當(dāng)新舊技術(shù)的成本之差,遠(yuǎn)遠(yuǎn)高于技術(shù)棧遷移的成本,就值得做出遷移的決策了。例如,我們的一個(gè)項(xiàng)目需要處理的遺留系統(tǒng),使用了某軟件公司的產(chǎn)品,該產(chǎn)品必須運(yùn)行在大型服務(wù)器上。該產(chǎn)品主要提供客戶信息的處理。這是一個(gè)存在超過十年以上的產(chǎn)品,之后加入的子系統(tǒng)并未再使用該產(chǎn)品。如今,該產(chǎn)品所支持的客戶數(shù)量并不多,而每年的產(chǎn)品許可費(fèi)用以及大型服務(wù)器的維護(hù)成本都非常高。最后,我們對(duì)該產(chǎn)品提供的功能進(jìn)行了遷移,以漸進(jìn)地方式逐漸替換了該產(chǎn)品,降低了系統(tǒng)成本。

  二、引入風(fēng)險(xiǎn)驅(qū)動(dòng)模型

  George Fairbanks提出的風(fēng)險(xiǎn)驅(qū)動(dòng)模型(Risk-Driven Model)非常適合遺留系統(tǒng)的技術(shù)棧遷移。所謂“風(fēng)險(xiǎn)驅(qū)動(dòng)模型”,就是通過識(shí)別風(fēng)險(xiǎn),對(duì)風(fēng)險(xiǎn)排定優(yōu)先級(jí);然后根據(jù)風(fēng)險(xiǎn)選定相關(guān)技術(shù),再對(duì)風(fēng)險(xiǎn)是否得到緩解進(jìn)行評(píng)估的一種架構(gòu)方法[5] 。在對(duì)遺留系統(tǒng)進(jìn)行技術(shù)棧遷移時(shí),如果未能事先對(duì)遷移過程的風(fēng)險(xiǎn)進(jìn)行有效識(shí)別,就可能為系統(tǒng)引入新的問題,降低系統(tǒng)質(zhì)量,或者導(dǎo)致遷移的成本過高。

  根據(jù)我的經(jīng)驗(yàn),在對(duì)遺留系統(tǒng)進(jìn)行技術(shù)棧遷移時(shí),可以識(shí)別的主要風(fēng)險(xiǎn)包括:

  • 遺留系統(tǒng)本身存在的質(zhì)量問題,例如緊耦合、缺乏足夠的測試、系統(tǒng)可維護(hù)性差;
  • 缺乏足夠的知識(shí)來幫助我們理解整個(gè)遺留系統(tǒng);
  • 成本、時(shí)間與人力的風(fēng)險(xiǎn);
  • 對(duì)遷移的新技術(shù)缺乏充分認(rèn)識(shí);
  • 遷移能力的不足。

  三、選擇緩解風(fēng)險(xiǎn)的技術(shù)

  一旦識(shí)別出遷移過程中可能存在的風(fēng)險(xiǎn),我們就可以有的放矢地選擇相關(guān)技術(shù),制訂降低風(fēng)險(xiǎn)的解決方案。

  · 尋找丟失的知識(shí)

  只有體驗(yàn)過去,才能謀劃未來。如果缺乏對(duì)遺留系統(tǒng)的足夠認(rèn)識(shí),這種技術(shù)棧的遷移就很難取得成功。通常來講,一個(gè)軟件系統(tǒng)的知識(shí),主要體現(xiàn)在如下三個(gè)方面,如下圖所示:

  在這三個(gè)方面中,團(tuán)隊(duì)成員擁有的知識(shí)無疑是最值得寄予厚望的。在遷移過程中,若有了解該系統(tǒng)的團(tuán)隊(duì)成員參與,無疑可以做到事半功倍??上?,這部分知識(shí)又是最為脆弱的,它就好似存儲(chǔ)在內(nèi)存中的數(shù)據(jù)一般,一旦斷電就會(huì)全盤丟失。遺留系統(tǒng)的問題恰在于此,由于系統(tǒng)過于陳舊,而人員的流動(dòng)總是比較頻繁,在對(duì)系統(tǒng)進(jìn)行遷移時(shí),可能許多當(dāng)年參與系統(tǒng)開發(fā)的成員,已經(jīng)很難找到。

  缺乏團(tuán)隊(duì)成員在知識(shí)方面的傳承,就只能寄希望于文檔與代碼。文檔的問題有目共睹,無論采用多么嚴(yán)謹(jǐn)?shù)奈臋n管理辦法,文檔與真實(shí)的實(shí)現(xiàn)總是存在偏差。正如“盡信書不如無書”,文檔可以提供參考價(jià)值,但絕對(duì)不能完全依賴于文檔。毫無疑問,代碼是最為真實(shí)的知識(shí)。它不會(huì)說謊,但卻過于沉迷于細(xì)節(jié),要通過代碼來了解遺留系統(tǒng)的知識(shí),一方面耗時(shí)耗力,另一方面也難免會(huì)產(chǎn)生“只見樹木不見森林”之嘆。

  引入自說明的可運(yùn)行文檔,可以有效地將文檔與代碼結(jié)合起來。通過運(yùn)用業(yè)務(wù)語言編寫功能場景來體現(xiàn)業(yè)務(wù)需求,完成文檔的撰寫;同時(shí),它又是可以運(yùn)行的代碼,通過直接調(diào)用代碼實(shí)現(xiàn),可以完全真實(shí)地驗(yàn)證功能是否準(zhǔn)確。目前,有許多框架和工具可以支持這種規(guī)格文檔,例如Java平臺(tái)下的jBehave,Ruby語言編寫的Cucumber,支持HTML格式的Concordion,以及ThoughtWorks的產(chǎn)品Twist[6]。

  在我們的一個(gè)項(xiàng)目中,需要完成系統(tǒng)從WebLogic到JBoss的技術(shù)棧遷移。該系統(tǒng)是一個(gè)長達(dá)十年以上時(shí)間的遺留系統(tǒng)。雖然有比較完整的文檔說明,但許多具體的業(yè)務(wù)對(duì)于我們而言,還是像一個(gè)黑盒,不知道具體的交互行為。此時(shí),我們和客戶一起為其建立了一個(gè)專門的項(xiàng)目,通過運(yùn)用jBehave為該系統(tǒng)的業(yè)務(wù)行為編寫可以運(yùn)行的Story。在編寫Story時(shí),我們參考了系統(tǒng)的文檔,并根據(jù)文檔描述的功能建立場景,確定輸入和輸出,判斷系統(tǒng)的行為是否與文檔描述一致。事實(shí)上,我們?cè)诰帉慡tory的過程中,確曾發(fā)現(xiàn)系統(tǒng)的真實(shí)行為與文檔描述不一致的地方。這時(shí),我們會(huì)判斷這種不一致究竟是缺陷,還是期待的真實(shí)行為。在編寫Story的過程中,我們尋找回了已經(jīng)丟失的知識(shí),并進(jìn)一步熟悉了系統(tǒng)的結(jié)構(gòu),了解到系統(tǒng)組件的功能以及組件之間的關(guān)系。通過這些不斷完善的Story,我們逐漸建立起了一個(gè)完全反應(yīng)了真實(shí)實(shí)現(xiàn)的可運(yùn)行文檔庫,它甚至可以取代原來的文檔,成為系統(tǒng)的重要知識(shí)。

  · 及時(shí)驗(yàn)證,快速反饋

  在對(duì)系統(tǒng)進(jìn)行技術(shù)棧遷移時(shí),我們常常會(huì)擔(dān)心修改會(huì)破壞原有的功能。尤其是對(duì)于大多數(shù)遺留系統(tǒng),普遍存在測試不足,代碼緊耦合,可維護(hù)性差的特點(diǎn)。雖然遺留系統(tǒng)會(huì)因?yàn)檫@些缺點(diǎn)而受人詬病,但不可否認(rèn)的是,這些遺留系統(tǒng)畢竟經(jīng)歷了長時(shí)間的考驗(yàn),在功能的正確性上已經(jīng)得到了充分的驗(yàn)證。在遷移到新的技術(shù)時(shí),如果不慎破壞了原有功能,引入了新的缺陷,就可能得不償失了。

  為了避免這種情況發(fā)生,我們就需要為其建立充分的測試,并通過建立持續(xù)集成(Continuous Integration)環(huán)境,提供快速反饋的通道。一旦發(fā)現(xiàn)新的修改破壞了系統(tǒng)功能,就需要馬上修復(fù)或者撤銷之前的提交。

  問題是我們?cè)撊绾谓y試保護(hù)網(wǎng)?為遺留系統(tǒng)建立測試是一件非常痛苦的事情,為了減小工作量,我們首先應(yīng)該根據(jù)技術(shù)遷移的目標(biāo),縮小和鎖定系統(tǒng)的范圍。例如,倘若我們要將系統(tǒng)從IBM MQ遷移到JBoss MQ,那么就只需要驗(yàn)證那些與消息隊(duì)列通信的組件。若要將報(bào)表遷移到JASPerReport,就應(yīng)該只檢測整個(gè)系統(tǒng)的報(bào)表組件。另一方面,我們應(yīng)盡量從粗粒度的測試開始入手。一個(gè)好消息是,在之前為了尋找失去的知識(shí)時(shí)建立的可運(yùn)行文檔,事實(shí)上可以看作是一種驗(yàn)收測試。它不僅提供了自說明的文檔,同時(shí)還建立了覆蓋率客觀的測試保護(hù)網(wǎng)。這種驗(yàn)收測試是針對(duì)業(yè)務(wù)行為編寫的完整功能場景,更接近業(yè)務(wù)需求。它的抽象層次相對(duì)較高,并不會(huì)涉及太多編程細(xì)節(jié)。即使實(shí)現(xiàn)模塊(包括類)是緊耦合的,沒有明顯的單元邊界,我們?nèi)匀豢梢詾槠渚帉憸y試。這就可以省去對(duì)類與模塊進(jìn)行解耦這一難度頗高的工作。

  通常,我們會(huì)將這些測試作為持續(xù)集成的一個(gè)單獨(dú)pipeline。每次對(duì)原有系統(tǒng)的修改,都要觸發(fā)該pipeline的運(yùn)行,以期獲得及時(shí)的反饋。這樣,就可以為原有系統(tǒng)建立一個(gè)覆蓋范圍廣泛的測試保護(hù)網(wǎng),使得我們可以有信心地對(duì)系統(tǒng)進(jìn)行技術(shù)棧遷移。

  針對(duì)一些核心場景,我們還可以為遺留系統(tǒng)編寫集成測試。這種粗粒度的測試不需要對(duì)原有代碼進(jìn)行太多的調(diào)整或重構(gòu),唯一需要付出的努力是對(duì)集成測試環(huán)境的搭建。

  對(duì)于遺留系統(tǒng)的集成測試,最好能夠支持本地構(gòu)建。因?yàn)槿裟茉诒镜亻_發(fā)環(huán)境運(yùn)行集成測試,就可以通過在本地運(yùn)行構(gòu)建腳本,快速地獲得反饋,避免一些集成錯(cuò)誤流入到源代碼服務(wù)器中,導(dǎo)致持續(xù)集成Pipeline頻繁出現(xiàn)錯(cuò)誤。這種快速失敗的方式,可以更好地驗(yàn)證錯(cuò)誤,降低集成風(fēng)險(xiǎn)。在搭建本地集成環(huán)境時(shí),可以選擇一些輕量級(jí)框架或容器,提高部署性能。例如我們可以在本地運(yùn)行Jetty這種輕量級(jí)的Web服務(wù)器,使用HSQL內(nèi)存數(shù)據(jù)庫來準(zhǔn)備數(shù)據(jù)。對(duì)于某些集成極為困難的情況,也可以適當(dāng)考慮建立Stub。例如對(duì)外部服務(wù)的依賴,可以建立一個(gè)Stub的Web Service。這種方式雖然沒有真實(shí)地體現(xiàn)集成功能,但它卻可以快速地驗(yàn)證系統(tǒng)內(nèi)部的功能。

  倘若因?yàn)橐恍┩獠考s束,我們無法做到完全的本地構(gòu)建,也應(yīng)該提供足夠的集成環(huán)境,采取混合的方式運(yùn)行構(gòu)建腳本。例如可以將正在進(jìn)行遷移的系統(tǒng)運(yùn)行在本地環(huán)境上,而將該系統(tǒng)需要訪問的中間件或者數(shù)據(jù)庫放到其他的集成環(huán)境下。我們還可以利用構(gòu)建腳本如Gradle,建立多種部署環(huán)境,例如Dev、Local、Stub、Intg等,使得開發(fā)人員或測試人員可以根據(jù)不同情況運(yùn)行不同環(huán)境的構(gòu)建腳本。

  · 做好充分的技術(shù)預(yù)研

  所謂“技術(shù)棧遷移”,必然是指從一種技術(shù)遷移到另一種技術(shù)。在充分了解系統(tǒng)當(dāng)前存在的問題后,還需要深思熟慮,選擇合理的目標(biāo)技術(shù)。通常,我們會(huì)識(shí)別出待遷移模塊(或系統(tǒng))希望達(dá)到的質(zhì)量屬性,然后就此功能給出候選技術(shù),建立一個(gè)用于權(quán)衡的矩陣。接著,再對(duì)這些待選技術(shù)進(jìn)行技術(shù)預(yù)研(Spike),預(yù)研的結(jié)果將作為最終判斷的依據(jù)。這種決策是有理有據(jù)的,可以有效地規(guī)避遷移中因?yàn)橐胄录夹g(shù)帶來的風(fēng)險(xiǎn)。下圖是我們?cè)谝粋€(gè)項(xiàng)目中對(duì)文本搜索進(jìn)行的技術(shù)預(yù)研結(jié)果矩陣。

  因?yàn)槭羌夹g(shù)棧遷移,必然要求目標(biāo)技術(shù)一定要優(yōu)于現(xiàn)有技術(shù),否則就沒有遷移的必要了。通過技術(shù)預(yù)研,既可以提供可以量化的數(shù)據(jù),保證這種遷移是值得的;同時(shí)也相當(dāng)于預(yù)先開始對(duì)目標(biāo)技術(shù)展開學(xué)習(xí)和了解,及早發(fā)現(xiàn)技術(shù)難點(diǎn)和遷移的痛點(diǎn)。

  在我曾經(jīng)參與的一個(gè)項(xiàng)目中,我們針對(duì)報(bào)告生成器模塊編寫了自己的一個(gè)支持并發(fā)處理的Batch Job。但隨著系統(tǒng)用戶數(shù)量的逐步增加,在生成報(bào)告的高峰期,并發(fā)請(qǐng)求數(shù)超過了之前架構(gòu)設(shè)計(jì)預(yù)見的峰值,且每個(gè)報(bào)告生成所耗費(fèi)的時(shí)間較長。于是,我們計(jì)劃引入消息隊(duì)列技術(shù)來替換現(xiàn)有的Batch Job。我們對(duì)一些候選技術(shù)進(jìn)行了前期預(yù)研,這其中包括微軟的MSMQ、Apache ActiveMQ以及RabbitMQ,針對(duì)并發(fā)處理、可維護(hù)性、成本、部署、安全、分布式處理以及災(zāi)備等多方面進(jìn)行了綜合考慮,如下表所示:

  技術(shù)選型從來都不是以單方面的高質(zhì)量作為評(píng)價(jià)標(biāo)準(zhǔn),即使某項(xiàng)技術(shù)在多個(gè)評(píng)判維度上都得到了最高的分?jǐn)?shù),也未必就是最佳選擇。我們必須結(jié)合當(dāng)前項(xiàng)目的具體場景,實(shí)事求是地進(jìn)行判斷,以期獲得一個(gè)恰如其分的遷移方案。

  · 新舊共存,小步前行

  技術(shù)棧遷移的某些特征與架構(gòu)的演化不謀而合,我們絕對(duì)不能奢求獲得一個(gè)一蹴而就的完美方案,更不能盼望整個(gè)遷移過程能夠一步到位。尤其針對(duì)那些因?yàn)閼?zhàn)略調(diào)整而驅(qū)動(dòng)的技術(shù)棧遷移,可能牽涉到架構(gòu)風(fēng)格或整個(gè)基礎(chǔ)設(shè)施的修改或調(diào)整,單就遷移這一項(xiàng)工作而言,就可能是一個(gè)浩大的工程。這時(shí),我們必須要允許新舊共存,通過小步前行的方式逐步以新技術(shù)替換舊技術(shù)。我們必須保證前進(jìn)的每一小步,都不會(huì)破壞系統(tǒng)的整體功能。這種新舊共存的局面,可能導(dǎo)致在一段時(shí)間會(huì)出現(xiàn)架構(gòu)風(fēng)格或解決方案的不一致,但只要做好整體規(guī)劃,最終仍能在一致性方面獲得完美的答案。

  在我們工作的一個(gè)項(xiàng)目中,需要將一個(gè)獨(dú)立的系統(tǒng)徹底移除,并將該系統(tǒng)原有的功能集成到另一個(gè)系統(tǒng)。需要移除的目標(biāo)系統(tǒng)目前以Web Service方式提供服務(wù)。我們選擇的解決方案是漸進(jìn)地移除該系統(tǒng)。假設(shè)待移除的目標(biāo)系統(tǒng)為Target,要集成的系統(tǒng)為Integration,我們采用了如下的遷移步驟:

  1. 修改Integration,為其創(chuàng)建與Target提供的Web Service一致的服務(wù)接口;
  2. 讓新建立的服務(wù)接口的實(shí)現(xiàn)調(diào)用Target提供的Web Service;
  3. 修改客戶端對(duì)Target服務(wù)的調(diào)用,改為指向新增的Integration服務(wù)接口;
  4. 如果運(yùn)行一切正常,再將Target中的實(shí)現(xiàn)遷移到Integration中;
  5. 在遷移過程中,提供Toggle開關(guān),可以隨時(shí)通過改變Toggle的值,選擇使用新或舊的調(diào)用方式;
  6. 再次確定采用新的調(diào)用方式是否正常,如果正常,徹底去掉原有的實(shí)現(xiàn),移除Target系統(tǒng)。

  新舊共存并非一種妥協(xié),而是遷移過程中必須存在的中間狀態(tài)。Jez Humble介紹了ThoughtWorks產(chǎn)品GO的幾次技術(shù)棧遷移[7],包括從iBatis遷移到Hibernate,從Velocity和JsTemplate轉(zhuǎn)向JRuby on Rails的案例。文章提出了一種稱為Branch By Abstraction(抽象分支)的遷移方法,執(zhí)行步驟如下圖所示:

  圖中的抽象層將客戶端(Consumer)與被替換的實(shí)現(xiàn)進(jìn)行了解耦,使得這種替換可以透明地進(jìn)行。在對(duì)抽象層的實(shí)現(xiàn)進(jìn)行替換時(shí),可以規(guī)定替換紀(jì)律,例如對(duì)于新增功能,必須運(yùn)用新技術(shù)提供實(shí)現(xiàn);還可以通過持續(xù)集成的驗(yàn)證門自動(dòng)驗(yàn)證,例如設(shè)置舊有技術(shù)在系統(tǒng)中的閾值,每次提交都不允許舊有技術(shù)的代碼量超過這個(gè)閾值。整個(gè)遷移過程要保證這個(gè)閾值是不斷減少,絕不能增加。

  · 理清思路,持續(xù)改進(jìn)

  要完成遺留系統(tǒng)的技術(shù)棧遷移,不可避免地需要對(duì)代碼實(shí)現(xiàn)進(jìn)行修改或重構(gòu)。這或許是遷移難度最大的一部分內(nèi)容。我的經(jīng)驗(yàn)是針對(duì)遺留系統(tǒng)進(jìn)行處理時(shí),不要從一開始就埋首于浩如煙海的代碼段中,太多的細(xì)節(jié)可能會(huì)讓你迷失其中。若系統(tǒng)是可以運(yùn)行的,可以首先運(yùn)行該系統(tǒng),通過實(shí)際操作了解系統(tǒng)的各個(gè)功能點(diǎn)、業(yè)務(wù)流程。這樣的直觀感受可以最快地幫助你了解該系統(tǒng):它能夠做什么?它能達(dá)成什么目標(biāo)?它的范圍是什么?它存在什么問題?

  接下來,我們需要從系統(tǒng)架構(gòu)出發(fā),了解遺留系統(tǒng)的邏輯結(jié)構(gòu)和物理分布,最好能描繪出遺留系統(tǒng)的輪廓圖,這可以幫助你從技術(shù)的宏觀角度剖析遺留系統(tǒng)的結(jié)構(gòu)與組成;然后再結(jié)合你對(duì)該系統(tǒng)業(yè)務(wù)的理解,快速地掌握遺留系統(tǒng)。在閱讀源代碼時(shí),最好能夠從主程序入口開始,找到一些主要的模塊,了解其大體的設(shè)計(jì)方式與編碼習(xí)慣。由于之前對(duì)系統(tǒng)架構(gòu)已有了解,閱讀代碼時(shí),不應(yīng)在一開始就去理解代碼實(shí)現(xiàn)的細(xì)節(jié),而應(yīng)結(jié)合架構(gòu)文檔,比對(duì)代碼實(shí)現(xiàn)是否與文檔的描述一致,并充分利用自己的技術(shù)與經(jīng)驗(yàn),找到閱讀代碼的終南捷徑。例如,如果我們知道該系統(tǒng)采用了MVC架構(gòu),就可以很容易地根據(jù)Url找到對(duì)應(yīng)的Controller對(duì)象,并在該對(duì)象中尋找業(yè)務(wù)功能實(shí)現(xiàn)的脈絡(luò)。又例如我們知道系統(tǒng)引入了WCF來支持分布式處理,而我們又非常熟悉WCF,就可以基本忽略系統(tǒng)基礎(chǔ)設(shè)施的部分,直接了解系統(tǒng)的業(yè)務(wù)實(shí)現(xiàn)。如果系統(tǒng)基于EJB 2.0實(shí)現(xiàn),則完全可以根據(jù)EJB提供的Bean的結(jié)構(gòu),快速地定位到對(duì)應(yīng)的服務(wù)接口與實(shí)現(xiàn)。這是因?yàn)樵S多框架都規(guī)定了一些約束或規(guī)范,從這些約束與規(guī)范入手,可以做到事半功倍。

  在嘗試?yán)斫獯a的過程中,可以通過手工繪制或利用IDE自動(dòng)生成包圖、時(shí)序圖等可視性強(qiáng)的UML圖,幫助我們理解代碼結(jié)構(gòu)。Michael Feathers提出可以為遺留代碼繪制影響結(jié)構(gòu)圖與特征草圖[8],從而幫助我們?nèi)ナ崂沓绦蛑懈鱾€(gè)對(duì)象之間的關(guān)系,尤其是幫助我們識(shí)別依賴,進(jìn)而利用接縫類型、隱藏依賴等手法去解除依賴。

  了解了代碼,還需要對(duì)代碼進(jìn)行修改。多數(shù)情況下,我們需要首先通過重構(gòu)來改善代碼質(zhì)量。注意,技術(shù)棧的遷移并非重構(gòu),但重構(gòu)可以作為遷移工具箱中一件最為重要的工具。例如,我們可以通過Extract Interface,并結(jié)合Use Interface Where Possible手法,對(duì)一些具體類進(jìn)行接口提取,并改變對(duì)原來具體類對(duì)象的依賴。重構(gòu)時(shí),必須采取“分而治之,小步前進(jìn)”的策略。可以首先選擇實(shí)現(xiàn)較為容易,或者獨(dú)立性較好的模塊進(jìn)行重構(gòu)。將遺留系統(tǒng)逐步提取為一些可重用的模塊與類。其中,對(duì)于原有類或模塊的調(diào)用方,由于在重構(gòu)時(shí)可能會(huì)更改接口,因而可以考慮引入Facade模式或Adapter模式,通過引入間接層對(duì)接口進(jìn)行包裝或適配,逐漸替換系統(tǒng),最后演化為一個(gè)結(jié)構(gòu)合理的良好系統(tǒng)。需要注意的是,在重構(gòu)時(shí)一定要時(shí)刻謹(jǐn)記,我們之所以進(jìn)行重構(gòu),其目的是為了更好地遷移遺留系統(tǒng)的技術(shù)棧,而非為了重構(gòu)而重構(gòu),從而偏離我們之前確定的目標(biāo)。故而,重構(gòu)與遷移應(yīng)該是兩頂不同的帽子,不能同時(shí)進(jìn)行。

  四. 結(jié)束語

  遺留系統(tǒng)的技術(shù)棧遷移可能是一個(gè)漫長艱苦的過程,它的難度甚至要高于新開發(fā)一個(gè)系統(tǒng),這是因?yàn)槲覀兂3?huì)掙扎在新舊系統(tǒng)之間,并在不斷的妥協(xié)、權(quán)衡中緩步前行。

  它是一個(gè)復(fù)雜工程,需要參與者了解遷移前后的技術(shù)棧知識(shí),掌握或者至少善于分析與理解遺留系統(tǒng)。我們需要審慎地做出技術(shù)決策,通過識(shí)別遷移過程的風(fēng)險(xiǎn)來驅(qū)動(dòng)整個(gè)遷移過程。在決定遷移選擇的技術(shù)時(shí),要根據(jù)這些識(shí)別出來的風(fēng)險(xiǎn)對(duì)這些候選技術(shù)做充分的預(yù)研,獲得可供參考的度量矩陣。我們還可以引入BDD框架來編寫可運(yùn)行的功能場景,以此來尋找失去的知識(shí),同時(shí)兼得驗(yàn)收測試的保護(hù)網(wǎng)。

  我們可以通過引入持續(xù)集成,建立快速反饋環(huán),以避免遷移時(shí)做出的改動(dòng)對(duì)原有系統(tǒng)造成破壞。同時(shí),還必須具備技術(shù)遷移的能力。我們可以考慮引入一些最佳實(shí)踐或遷移方法,例如抽象分支、影響結(jié)構(gòu)圖、特征草圖,運(yùn)用設(shè)計(jì)模式和重構(gòu)手法來改善遺留代碼,以利于技術(shù)的遷移。當(dāng)然,團(tuán)隊(duì)協(xié)作、架構(gòu)設(shè)計(jì)、組織管理、進(jìn)度跟蹤等一系列技術(shù)與管理實(shí)踐同樣重要,只是這些實(shí)踐并非技術(shù)棧遷移所必須的,而是所有開發(fā)過程都必須經(jīng)歷的過程,因而本文不再贅述這些內(nèi)容。

  參考文獻(xiàn):

  [1]:http://en.wikipedia.org/wiki/Legacy_system,原文為:“A legacy system is an old method, technology, computer system, or application program.”

  [2]:文章How Rackspace Now Uses MapReduce And Hadoop To Query Terabytes Of Data

  [3]:煙囪系統(tǒng),一種反模式,http://sourcemaking.com/antipatterns/stovepipe-system。

  [4]:供應(yīng)商鎖定,一種反模式,參見http://sourcemaking.com/antipatterns/vendor-lock-in。

  [5]:Gorge Fairbanks:Just Enough Software Architecture,參見第3章Risk Driven Model

  [6]:以上所述皆為BDD框架或整體工具。

  [7]:Jez Humble:Make Large Scale Changes Incrementally with Branch By Abstraction

  [8]:Michael Feathers:Working Effectively with Legacy Code

it知識(shí)庫遺留系統(tǒng)的技術(shù)棧遷移,轉(zhuǎn)載需保留來源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 国产极品在线观看 | 色久优优| 国产一区二区在免费观看 | 久久国产精品免费一区二区三区 | 国产国产成人精品久久 | 欧美激情亚洲激情 | 一区二区视频在线观看免费的 | 99精品国产第一福利网站 | 91网页版 | 国产一二三区视频 | 国产精品久久久久久久久ktv | 国产男人和女人做性全部视频 | 999精品视频在线 | 亚洲不卡一区二区三区在线 | 国产精品视频1区 | 欧美激情性色生活片在线观看 | 四虎精品永久在线 | 色婷婷伊人 | www.色av.com| 色呦 | 91久久国产成人免费观看资源 | 成人黄色小视频在线观看 | 国产精品亚洲一区二区三区在线观看 | 亚洲一区二区三区久久精品 | 91久久国产情侣真实对白 | 台湾佬自偷自拍情侣在线 | 国产自在线观看 | 久久一区视频 | 久久国产亚洲精品麻豆 | 国产免费久久精品丫丫 | 亚洲人成a在线网站 | 亚洲一区免费 | 女人一级毛片 | 三级网站国产 | 国产精品福利在线 | 一级囗交片| 久热中文字幕在线精品免费 | 久久久久久久久网站 | 国产极品嫩模在线观看91精品 | a级国产乱理论片在线观看看 | 精品久久久久久久一区二区手机版 |