<ruby id="h6500"><table id="h6500"></table></ruby>
    1. <ruby id="h6500"><video id="h6500"></video></ruby>
          1. <progress id="h6500"><u id="h6500"><form id="h6500"></form></u></progress>

            利用“抽象分支”做增量式大規模軟件改造

            發(fā)表于:2013-02-27來(lái)源:不祥作者:?jiǎn)塘?/small>點(diǎn)擊數: 標簽:持續交付
            利用“抽象分支”做增量式大規模軟件改造!很多開(kāi)發(fā)團隊通常嚴重依賴(lài)于版本控制系統的分支功能。分布式版本控制系統讓分支操作更加方便。然而,在《持續交付》一書(shū)中描述的很多非常規言論中,就有一條是:“使用分支,你就無(wú)法做持續集成”。

              很多開(kāi)發(fā)團隊通常嚴重依賴(lài)于版本控制系統的分支功能。分布式版本控制系統讓分支操作更加方便。然而,在《持續交付》一書(shū)中描述的很多非常規言論中,就有一條是:“使用分支,你就無(wú)法做持續集成”。根據定義,如果你有代碼在某個(gè)分支上,那就沒(méi)有集成。有一種很常見(jiàn)的情況,會(huì )讓人很自然地想到利用版本控制工具的分支功能:那就是“對應用程序進(jìn)行大規模改造時(shí)”。然而,還有一種替代這種真實(shí)分支的做法,技術(shù)上叫做“抽象分支(Branch by Abstraction)”。

              抽象分支:在主干上進(jìn)行以增量方式對軟件進(jìn)行大規模改造的一種模式。

              Paul Hammant在2007年就提到過(guò)用這種方式把OR mapping的方案從Hibernate切換到iBatis(詳見(jiàn)這里)。同樣,我曾經(jīng)工作的一款商業(yè)產(chǎn)品(持續集成與敏捷發(fā)布管理平臺 Go)則從iBatis改到了Hibernate,這已經(jīng)是兩年前做的事情了。我們也把產(chǎn)品的UI層慢慢地從“使用Velocity和JsTemplate”轉移到了“JRuby on Rails”上。

              這兩種變化都是慢慢地增量式地完成的,在改變的同時(shí),也做新功能的開(kāi)發(fā),但這并不妨礙我們每天向Mercurail的版本庫主干上提交數次代碼,甚至在切換過(guò)程中做了數次正式發(fā)布。我們是如何做到的呢?

              從iBatis遷移到Hibernate

              團隊決定從iBatis遷移到Hibernate,有兩個(gè)原因:第一,我們可以更高效地使用ORM,因為我們對產(chǎn)品數據庫的結構有絕對控制權,這樣就不用寫(xiě)太多的定制SQL;第二,它有二級緩存,對性能有幫助。

              當然,我們并沒(méi)想一次性把整個(gè)代碼庫都遷移到Hibernate上。我們的策略是:當開(kāi)始增加新功能時(shí),如果需要增加新的方法去訪(fǎng)問(wèn)數據庫的話(huà),就使用Hibernate來(lái)完成,當必要時(shí),才將原有對iBatis的調用遷移過(guò)來(lái)。

              對持久層邏輯的更新相對來(lái)說(shuō)比較直接,因為產(chǎn)品 Go的代碼庫使用標準的分層結構,控制器層使用服務(wù)層,而服務(wù)層使用倉庫層(repositories)。因為所有需要訪(fǎng)問(wèn)數據庫的代碼都利用repository pattern封裝在倉庫層中,所以每次將一個(gè)倉庫從iBatis改成Hibernate,增量式地完成修改是一件比較容易的事情。服務(wù)層根本不知道底下的持久層框架是什么。

              我 的同事Pavan K.S.說(shuō):“抽象分支有一個(gè)嚴格要求,那是紀律性,即:開(kāi)發(fā)人員不能再以任何借口添加原有模式的代碼。也就是說(shuō),作為第一原則,不要再增加iBatis查詢(xún)(盡管這么做可能更快更省事兒),必須用Hibernate來(lái)做。這是確保你進(jìn)度的唯一方法。一種強制手段是在持續集成構建時(shí)只要發(fā)現新增了iBatis查詢(xún), 就令持續集成構建失敗。并且,只能不斷減少這個(gè)閥值,絕不能增加。”

              從Velocity和JsTemplate轉向JRuby on Rails

              產(chǎn)品GO還從“以Java為基礎的UI軟件棧”轉向“JRuby on Rails”的軟件棧。這也有兩個(gè)原因:一是新的框架更容易寫(xiě)測試,二是它會(huì )加速UI的開(kāi)發(fā)。當然,這個(gè)變更也是增量式完成的。當在應用程序中創(chuàng )建新的頁(yè)面時(shí),我們會(huì )使用JRuby on Rails,一旦做好以后,就讓?xiě)贸绦虻钠渌糠种赶蜻@個(gè)新頁(yè)面。

              當需要對某個(gè)舊頁(yè)面進(jìn)行大量變更時(shí),我們就把它遷移到JRuby on Rails上。一旦做好,就把應用程序中所有指向這個(gè)頁(yè)面的URI都更改為這個(gè)新的頁(yè)面。此時(shí),要把對應的舊頁(yè)面刪除。所以,當Go的界面大部分都是JRuby on Rails的實(shí)現時(shí),仍舊有一些頁(yè)面是原有JAVA版的實(shí)現。

              ​然而,只看頁(yè)面的話(huà),根本不會(huì )覺(jué)察,因為它們的樣式是統一的,但從URI是能夠看出來(lái)的。所有使用/go/tab前綴的URI都會(huì )跳轉到舊的Velocity頁(yè)面上。其它頁(yè)面會(huì )跳轉到JRuby on Rails頁(yè)面上,當然它也同樣會(huì )使用原有界面所用的java 服務(wù)層。

              抽象分支究竟如何操作呢?

              抽象分支通過(guò)如下幾個(gè)步驟進(jìn)行大規模增量式修改:

              在你想改變的那部分代碼之上創(chuàng )建一個(gè)抽象層。

              對其余部分的代碼進(jìn)行重構,使其使用這個(gè)抽象層使用其之下的代碼提供的功能。

              在新的實(shí)現代碼里實(shí)現一些新的類(lèi),讓其上的抽象層根據需要,選擇性的導向舊代碼或新增的類(lèi)上。

              剔除原有的舊實(shí)現。

              清理,并重復前兩步,如果需要,可同時(shí)交付你的軟件。

              一旦舊實(shí)現完全被代替后,如果你愿意,可以移除那個(gè)抽象層。

              老馬(Martin Fowler)指出,這些步驟也可以變化一下。“在最簡(jiǎn)單的情況下,你可以創(chuàng )建一個(gè)抽象層,然后重構,讓所有的代碼都調用它,然后再新寫(xiě)一個(gè)實(shí)現,最后切換一下就行了。但是,還可以將它分開(kāi)做。比如,不創(chuàng )建整個(gè)抽象層,而只是創(chuàng )建將要修改的功能的一個(gè)子集,遷移這部分代碼,然后再做下一部分(此時(shí)新舊代碼共存)。”

              在上面iBatis/Hibernate的例子中,抽象層就是指那個(gè)倉庫層,它隱藏了持久層框架使用的細節。在JRuby on Rails的例子中,抽象層是Servlet Engine,通過(guò)URI的匹配,它可以決定是將Request分發(fā)到JRuby on Rails框架,還是標準的Java Servlets上。

              盡管Go這個(gè)項目相對比較小,開(kāi)發(fā)人員不到十個(gè),而且到現在也僅有五年的時(shí)間,但是,這些原則完全可以應用于各種大小的項目上。即使在大型且分布式的團隊項目里,也可以成功地使用這種模式。

              不可否認的是,抽象分支在開(kāi)發(fā)過(guò)程上增加了開(kāi)銷(xiāo),而且當你的代碼庫結構性很差時(shí),開(kāi)銷(xiāo)會(huì )更多一些。為了能夠以這種方式做增量式變更,你必須仔細思考,一點(diǎn)兒一點(diǎn)兒地慢慢向前走。但是,在很多情況下,這種額外的工作量是值得的,越是大的重構,就越應該考慮使用這種抽象分支。

              抽象分支的關(guān)鍵收益是你的代碼在整個(gè)結構調整的過(guò)程中都能夠正常工作,能夠做到持續交付。​也就是說(shuō),你的發(fā)布計劃與架構上的調整完全解耦,因此,在任何時(shí)間點(diǎn)你都可以停止重構工作,做優(yōu)先級更高的事情,比如發(fā)布一個(gè)你剛剛想到的非常好的功能特性。

              對于抽象分支來(lái)說(shuō),需要定義一個(gè)終止策略,這一點(diǎn)非常重要。當你能夠做到“不完成全部的結構調整也可以發(fā)布”時(shí),很容易產(chǎn)生一種傾向,即:一旦完成了重要部分的改造后,剩下的那部分尚未完成的工作,就放在那里不管了。然而,在系統中混合多種技術(shù)會(huì )讓系統更難維護,也要求團隊非常了解哪些地方還在使用舊有技術(shù)實(shí)現。這也許是一種可接收的權衡狀態(tài),但至少要對整個(gè)團隊做到可見(jiàn)。

            原文轉自:http://www.continuousdelivery.info/index.php/2013/01/04/branch_by_abstraction/

            老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月
              <ruby id="h6500"><table id="h6500"></table></ruby>
              1. <ruby id="h6500"><video id="h6500"></video></ruby>
                    1. <progress id="h6500"><u id="h6500"><form id="h6500"></form></u></progress>