中文字幕日韩一区二区_国产一区二区av_国产毛片av_久久久久国产一区_色婷婷电影_国产一区二区精品

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  二、引入風(fēng)險驅(qū)動模型

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

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

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

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

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

  · 尋找丟失的知識

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

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

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

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

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

  · 及時驗證,快速反饋

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

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

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

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

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

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

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

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

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

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

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

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

  · 新舊共存,小步前行

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

  在我們工作的一個項目中,需要將一個獨立的系統(tǒng)徹底移除,并將該系統(tǒng)原有的功能集成到另一個系統(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ù)接口的實現(xiàn)調(diào)用Target提供的Web Service;
  3. 修改客戶端對Target服務(wù)的調(diào)用,改為指向新增的Integration服務(wù)接口;
  4. 如果運行一切正常,再將Target中的實現(xiàn)遷移到Integration中;
  5. 在遷移過程中,提供Toggle開關(guān),可以隨時通過改變Toggle的值,選擇使用新或舊的調(diào)用方式;
  6. 再次確定采用新的調(diào)用方式是否正常,如果正常,徹底去掉原有的實現(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)與被替換的實現(xiàn)進(jìn)行了解耦,使得這種替換可以透明地進(jìn)行。在對抽象層的實現(xiàn)進(jìn)行替換時,可以規(guī)定替換紀(jì)律,例如對于新增功能,必須運用新技術(shù)提供實現(xiàn);還可以通過持續(xù)集成的驗證門自動驗證,例如設(shè)置舊有技術(shù)在系統(tǒng)中的閾值,每次提交都不允許舊有技術(shù)的代碼量超過這個閾值。整個遷移過程要保證這個閾值是不斷減少,絕不能增加。

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

  要完成遺留系統(tǒng)的技術(shù)棧遷移,不可避免地需要對代碼實現(xiàn)進(jìn)行修改或重構(gòu)。這或許是遷移難度最大的一部分內(nèi)容。我的經(jīng)驗是針對遺留系統(tǒng)進(jìn)行處理時,不要從一開始就埋首于浩如煙海的代碼段中,太多的細(xì)節(jié)可能會讓你迷失其中。若系統(tǒng)是可以運行的,可以首先運行該系統(tǒng),通過實際操作了解系統(tǒng)的各個功能點、業(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é)合你對該系統(tǒng)業(yè)務(wù)的理解,快速地掌握遺留系統(tǒng)。在閱讀源代碼時,最好能夠從主程序入口開始,找到一些主要的模塊,了解其大體的設(shè)計方式與編碼習(xí)慣。由于之前對系統(tǒng)架構(gòu)已有了解,閱讀代碼時,不應(yīng)在一開始就去理解代碼實現(xiàn)的細(xì)節(jié),而應(yīng)結(jié)合架構(gòu)文檔,比對代碼實現(xiàn)是否與文檔的描述一致,并充分利用自己的技術(shù)與經(jīng)驗,找到閱讀代碼的終南捷徑。例如,如果我們知道該系統(tǒng)采用了MVC架構(gòu),就可以很容易地根據(jù)Url找到對應(yīng)的Controller對象,并在該對象中尋找業(yè)務(wù)功能實現(xiàn)的脈絡(luò)。又例如我們知道系統(tǒng)引入了WCF來支持分布式處理,而我們又非常熟悉WCF,就可以基本忽略系統(tǒng)基礎(chǔ)設(shè)施的部分,直接了解系統(tǒng)的業(yè)務(wù)實現(xiàn)。如果系統(tǒng)基于EJB 2.0實現(xiàn),則完全可以根據(jù)EJB提供的Bean的結(jié)構(gòu),快速地定位到對應(yīng)的服務(wù)接口與實現(xiàn)。這是因為許多框架都規(guī)定了一些約束或規(guī)范,從這些約束與規(guī)范入手,可以做到事半功倍。

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

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

  四. 結(jié)束語

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

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

  我們可以通過引入持續(xù)集成,建立快速反饋環(huán),以避免遷移時做出的改動對原有系統(tǒng)造成破壞。同時,還必須具備技術(shù)遷移的能力。我們可以考慮引入一些最佳實踐或遷移方法,例如抽象分支、影響結(jié)構(gòu)圖、特征草圖,運用設(shè)計模式和重構(gòu)手法來改善遺留代碼,以利于技術(shù)的遷移。當(dāng)然,團隊協(xié)作、架構(gòu)設(shè)計、組織管理、進(jìn)度跟蹤等一系列技術(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知識庫遺留系統(tǒng)的技術(shù)棧遷移,轉(zhuǎn)載需保留來源!

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

主站蜘蛛池模板: 国产农村妇女毛片精品久久麻豆 | 国产99小视频 | 久久综合一区 | 日韩久久久久久 | 精品一区二区三区四区外站 | 亚洲国产精品一区二区第一页 | 国产成人精品999在线观看 | 91精品国产乱码久久久久久久久 | 国产成人精品免费视频大全最热 | 国产福利观看 | 中文字幕高清 | 九九伦理电影 | 日本在线观看视频 | 精一区二区 | 一级毛片免费完整视频 | 麻豆毛片| 一级片aaa | 一级黄色片在线看 | 亚洲最新在线视频 | 成人午夜精品 | 国产第二页 | 精品国产一区二区三区久久影院 | 色网站在线免费观看 | 欧美激情在线观看一区二区三区 | 91.色| 国产一级片91 | 正在播放一区二区 | 放个毛片看看 | 中文字幕在线不卡播放 | 国产精品一区二区三区在线 | www.99热.com| 欧美一区二区三区,视频 | 老司机久久 | 日韩欧美在线播放 | 欧美在线一二三 | 免费看黄色片 | 日韩精品一区二区三区中文在线 | 一级a性色生活片久久毛片波多野 | 狠狠干影院 | 国产农村妇女精品一二区 | 在线观看国产wwwa级羞羞视频 |