持續集成是一種軟件開(kāi)發(fā)實(shí)踐,在實(shí)踐中項目成員頻繁地進(jìn)行集成,通常每個(gè)成員每天都會(huì )做集成工作,如此,每天整個(gè)項目將會(huì )有多次集成。每次集成后都會(huì )通過(guò)自動(dòng)化構建(包括測試)來(lái)盡快發(fā)現其中的錯誤。許多團隊都發(fā)現這種方法大大地減少了集成問(wèn)題并且能夠快速地開(kāi)發(fā)出高內聚性的軟件。本文簡(jiǎn)要地總結了持續集成技術(shù)及其現狀。
我還清楚地記得我剛加入一個(gè)大型軟件項目時(shí)的情形,那時(shí)我正在英國一個(gè)電子公司做暑期實(shí)習。我的經(jīng)理(屬于QA部門(mén))領(lǐng)我參觀(guān)了一個(gè)巨大并很壓抑的倉庫,里面堆滿(mǎn)了大塊頭的主機。經(jīng)理告訴我這個(gè)項目已經(jīng)開(kāi)發(fā)了有些年頭,現在正在做集成,并且已經(jīng)集成了好幾個(gè)月了。經(jīng)理還告訴我說(shuō),沒(méi)有人真正知道完成集成工作需要多少時(shí)間。由此我學(xué)到了軟件項目的一個(gè)通?。很浖墒且粋€(gè)漫長(cháng)并且無(wú)法預測的過(guò)程。
然而,軟件集成不必像這樣的。在ThoughtWorks的大多數項目還有世界上許多其它組織的軟件項目中,軟件集成并不是什么難事。每個(gè)開(kāi)發(fā)人員離共享的工程狀態(tài)只有咫尺之遙,并且可以在幾分鐘之內將自己的代碼集成進(jìn)去。任何集成錯誤都能被快速地發(fā)現并得到快速的修正。
這種鮮明的對比并不是源自于后者有多么昂貴或復雜的工具,而關(guān)鍵在于每人都頻繁集成這種簡(jiǎn)單實(shí)踐,通常是每天向一個(gè)被管控的代碼庫集成。
當我向人們闡述這種實(shí)踐時(shí),通常得到兩種反應:“(在我們這里)行不通”和“無(wú)關(guān)緊要”。當人們嘗試了這種實(shí)踐之后,他們發(fā)現其實(shí)做起來(lái)比說(shuō)起來(lái)簡(jiǎn)單,而且這樣的實(shí)踐對于開(kāi)發(fā)“至關(guān)重要”。因此有了第三種反應:“是的,我們就是這么做的,不然該怎么活啊?”
“持續集成”源自于極限編程(XP),并且是XP最初的12種實(shí)踐之一。當我以咨詢(xún)師的角色加入ThoughtWorks時(shí),我鼓勵我的團隊使用這種技術(shù)。Matthew Foemmel將我的建議變成了實(shí)實(shí)在在的行動(dòng),由此軟件集成從少有發(fā)生并且復雜的狀態(tài)變成了一樁易事。Matthew和我將我們的經(jīng)驗寫(xiě)在了本文的第一版中,而本文也是我的個(gè)人網(wǎng)站上最受歡迎的文章之一。
雖然持續集成并不需要使用特別的工具來(lái)部署,但是我們發(fā)現擁有一臺持續集成服務(wù)器將大有益處,其中最著(zhù)名的有開(kāi)源的CruiseControl,該軟件最初由ThoughtWorks的幾個(gè)員工開(kāi)發(fā),現在由一個(gè)很大的社區維護著(zhù)。后來(lái)幾款其它的持續集成服務(wù)器也相繼出現了,有開(kāi)源的,也有商業(yè)化的,包括ThoughtWorks Studios的Cruise。
在開(kāi)發(fā)中使用持續集成
對于我來(lái)說(shuō),解釋持續集成及其工作原理最簡(jiǎn)單的方法便是以一個(gè)小的軟件功能的開(kāi)發(fā)為例來(lái)進(jìn)行演示。假設我們需要向軟件添加一點(diǎn)功能,至于是什么樣的功能并不重要,我們假定它很小并且可以在幾個(gè)小時(shí)內完成。
首先我們需要在本地機器上保留一份當前已經(jīng)處于集成狀態(tài)的代碼的拷貝。我通過(guò)代碼管理系統在代碼庫的主線(xiàn)(mainline)上拉下(check out)一份工作代碼拷貝。
上一段文字主要針對使用代碼控制系統的人,對于不使用代碼控制系統的人來(lái)說(shuō)便是胡言亂語(yǔ)了。因此,我將向后者解釋一下。代碼控制系統用于將項目所有的代碼保存在一個(gè)代碼庫(repository)中,項目當前的狀態(tài)通常被稱(chēng)為主線(xiàn)。任何時(shí)候開(kāi)發(fā)人員都可以從主線(xiàn)上獲得一份拷貝到本地機器,這被稱(chēng)為“checking out”。本地機器上的代碼拷貝稱(chēng)為“working copy”。(多數時(shí)候,實(shí)際上你是在更新(update)本地代碼到主線(xiàn)狀態(tài),實(shí)踐中它們是一樣的效果。)
現在,為了完成軟件的功能添加,我對本地代碼進(jìn)行修改,其中既包括修改產(chǎn)品代碼,也包括添加自動(dòng)化測試。持續集成非??粗販y試,并且在軟件代碼本身中達到了測試自動(dòng)化——我將其稱(chēng)為自測試代碼,通常使用流行的XUnit測試框架的一個(gè)版本。
當我完成了功能開(kāi)發(fā)(或者在我開(kāi)發(fā)過(guò)程的不同階段),我將在本地開(kāi)發(fā)機上完成自動(dòng)化構建。構建過(guò)程將編譯并鏈接本地代碼,然后跑自動(dòng)化測試。只有當構建和測試都沒(méi)有錯誤時(shí),該次構建才能算是好的構建。
有了本地的成功構建,我便可以考慮將我修改的代碼提交到代碼庫了。但是,在我提交之前,其他開(kāi)發(fā)人員可能已經(jīng)向主線(xiàn)提交了他們的修改,所以首先我需要將他們的修改更新到我本地并且重新構建。如果他人的修改與我的修改有沖突,那么在本地編譯或者測試階段將會(huì )發(fā)生錯誤,這種情況下,我需要負責修改本地代碼直到與主線(xiàn)代碼保持適當同步為止。
當本地代碼與主線(xiàn)代碼同步之后,我便可以向主線(xiàn)提交自己的修改了,代碼庫也得以更新。
然而,單是提交了修改并不表示我的工作就完成了。我需要再次構建,但這次是在一臺擁有主線(xiàn)代碼的集成機器上進(jìn)行。只有這次構建成功了才表示我的任務(wù)完成。通常會(huì )出現這樣的情況:我忘了提交本地機器上的一些東西,因此代碼庫并沒(méi)有得到適當的更新。只有我提交的修改在集成機器上成功構建之后,我的工作才算完成。這樣的集成構建可以由我手動(dòng)完成,也可以由Cruise自動(dòng)完成。
當兩個(gè)開(kāi)發(fā)者的代碼有沖突時(shí),通常會(huì )在第二個(gè)開(kāi)發(fā)者更新本地代碼時(shí)捕獲到,否則,集成構建應該會(huì )失敗。在這兩種途徑中,錯誤都可以被快速地發(fā)現。在持續集成環(huán)境中,你決不應該使失敗的集成構建保留太長(cháng)時(shí)間。一個(gè)好的團隊每天都應該有許多成功的構建。當然,失敗的構建也會(huì )時(shí)常發(fā)生,但需要盡快的修復。
這樣做的結果是,我們總會(huì )得到一個(gè)穩定并且工作正常的軟件。每個(gè)人都圍繞著(zhù)一個(gè)共享并穩定的基礎代碼庫工作,絕不離基礎代碼庫太遠以至于需要很長(cháng)的時(shí)間將自己的修改集成到基礎代碼庫中。如此這般,我們花在找bug上的時(shí)間減少了,因為bug在頻繁的集成中經(jīng)常出現。
持續集成實(shí)踐
上文只是關(guān)于持續集成的一個(gè)概要和它在日常開(kāi)發(fā)中的工作原理。讓所有這些都能很好的運作顯然不止于此?,F在,就讓我們來(lái)看看有效持續集成所需的關(guān)鍵實(shí)踐。
維護一個(gè)單一的代碼庫
軟件項目需要大量的文件協(xié)同工作來(lái)構建出最終的產(chǎn)品。跟蹤所有的文件需要大量的工作,尤其是在多個(gè)開(kāi)發(fā)者參與的項目中。因此,我們可以并不驚奇的看到,不同的軟件開(kāi)發(fā)團隊都在開(kāi)發(fā)用于管理這些文件的工具——源代碼管理工具,也叫配置管理,版本控制系統,代碼庫等。這些工具是多數軟件項目不可分的組成部分。然而,令人傷心并吃驚的是,并不是所有的項目都使用了這樣的工具。我的確見(jiàn)到(雖然很少)不使用這些工具的項目,它們使用本地和共享磁盤(pán)這種混亂的結合來(lái)共同工作。
原文轉自:http://kjueaiud.com