極限編程與敏捷開(kāi)發(fā)
作者:徐景周
在按照我的理解方式審查了軟件開(kāi)發(fā)的生命周期后,我得出一個(gè)結論:實(shí)際上滿(mǎn)足工程設計標準的惟一軟件文檔,就是源代碼清單。
-- Jack Reeves
簡(jiǎn)介 2001年,為了解決許多公司的軟件團隊陷入不斷增長(cháng)的過(guò)程泥潭,一批業(yè)界專(zhuān)家一起概括出了一些可以讓軟件開(kāi)發(fā)團隊具有快速工作、響應變化能力的價(jià)值觀(guān)和原則,他們稱(chēng)自己為敏捷聯(lián)盟。敏捷開(kāi)發(fā)過(guò)程的方法很多,主要有:SCRUM,Crystal,特征驅動(dòng)軟件開(kāi)發(fā)(Feature Driven Development,簡(jiǎn)稱(chēng)FDD),自適應軟件開(kāi)發(fā)(Adaptive Software Development,簡(jiǎn)稱(chēng)ASD),以及最重要的極限編程(eXtreme Programming,簡(jiǎn)稱(chēng)XP)。極限編程(XP)是于1998年由Smalltalk社群中的大師級人物Kent Beck首先倡導的。
極限編程 設計和編程都是人的活動(dòng)。忘記這一點(diǎn),將會(huì )失去一切。
-- Bjarne Stroustrup
極限編程(XP)是敏捷方法中最著(zhù)名的一個(gè)。它是由一系列簡(jiǎn)單卻互相依賴(lài)的實(shí)踐組成。這些實(shí)踐結合在一起形成了一個(gè)勝于部分結合的整體。
下面是極限編程的有效實(shí)踐:
- 完整團隊 XP項目的所有參與者(開(kāi)發(fā)人員、客戶(hù)、測試人員等)一起工作在一個(gè)開(kāi)放的場(chǎng)所中,他們是同一個(gè)團隊的成員。這個(gè)場(chǎng)所的墻壁上隨意懸掛著(zhù)大幅的、顯著(zhù)的圖表以及其他一些顯示他們進(jìn)度的東西。
- 計劃游戲計劃是持續的、循序漸進(jìn)的。每2周,開(kāi)發(fā)人員就為下2周估算候選特性的成本,而客戶(hù)則根據成本和商務(wù)價(jià)值來(lái)選擇要實(shí)現的特性。
- 客戶(hù)測試作為選擇每個(gè)所期望的特性的一部分,客戶(hù)可以根據腳本語(yǔ)言來(lái)定義出自動(dòng)驗收測試來(lái)表明該特性可以工作。
- 簡(jiǎn)單設計團隊保持設計恰好和當前的系統功能相匹配。它通過(guò)了所有的測試,不包含任何重復,表達出了編寫(xiě)者想表達的所有東西,并且包含盡可能少的代碼。
- 結對編程所有的產(chǎn)品軟件都是由兩個(gè)程序員、并排坐在一起在同一臺機器上構建的。
- 測試驅動(dòng)開(kāi)發(fā)編寫(xiě)單元測試是一個(gè)驗證行為,更是一個(gè)設計行為。同樣,它更是一種編寫(xiě)文檔的行為。編寫(xiě)單元測試避免了相當數量的反饋循環(huán),尤其是功功能能驗證方面的反饋循環(huán)。程序員以非常短的循環(huán)周期工作,他們先增加一個(gè)失敗的測試,然后使之通過(guò)。
- 改進(jìn)設計隨時(shí)利用重構方法改進(jìn)已經(jīng)腐化的代碼,保持代碼盡可能的干凈、具有表達力。
- 持續集成團隊總是使系統完整地被集成。一個(gè)人拆入(Check in)后,其它所有人責任代碼集成。
- 集體代碼所有權任何結對的程序員都可以在任何時(shí)候改進(jìn)任何代碼。沒(méi)有程序員對任何一個(gè)特定的模塊或技術(shù)單獨負責,每個(gè)人都可以參與任何其它方面的開(kāi)發(fā)。
- 編碼標準 系統中所有的代碼看起來(lái)就好像是被單獨一人編寫(xiě)的。
- 隱喻 將整個(gè)系統聯(lián)系在一起的全局視圖;它是系統的未來(lái)影像,是它使得所有單獨模塊的位置和外觀(guān)變得明顯直觀(guān)。如果模塊的外觀(guān)與整個(gè)隱喻不符,那么你就知道該模塊是錯誤的。
- 可持續的速度 團隊只有持久才有獲勝的希望。他們以能夠長(cháng)期維持的速度努力工作,他們保存精力,他們把項目看作是馬拉松長(cháng)跑,而不是全速短跑。 極限編程是一組簡(jiǎn)單、具體的實(shí)踐,這些實(shí)踐結合在形成了一個(gè)敏捷開(kāi)發(fā)過(guò)程。極限編程是一種優(yōu)良的、通用的軟件開(kāi)發(fā)方法,項目團隊可以拿來(lái)直接采用,也可以增加一些實(shí)踐,或者對其中的一些實(shí)踐進(jìn)行修改后再采用。

敏捷開(kāi)發(fā) 人與人之間的交互是復雜的,并且其效果從來(lái)都是難以預期的,但卻是工作中最重要的方面。
-- Tom DeMacro和Timothy Lister
敏捷軟件開(kāi)發(fā)宣言:
- 個(gè)體和交互 勝過(guò) 過(guò)程和工具
- 可以工作的軟件 勝過(guò) 面面俱到的文檔
- 客戶(hù)合作 勝過(guò) 合同談判
- 響應變化 勝過(guò) 遵循計劃
雖然右項也有價(jià)值,但是我們認為左項具有更大的價(jià)值。
- 我們最優(yōu)先要做的是通過(guò)盡早的、持續的交付有價(jià)值的軟件來(lái)使客戶(hù)滿(mǎn)意。
- 即使到了開(kāi)發(fā)的后期,也歡迎改變需求。敏捷過(guò)程利用變化來(lái)為客戶(hù)創(chuàng )造競爭優(yōu)勢。
- 經(jīng)常性地交付可以工作的軟件,交付的間隔可以從幾個(gè)星期到幾個(gè)月,交付的時(shí)間間隔越短越好。
- 在整個(gè)項目開(kāi)發(fā)期間,業(yè)務(wù)人員和開(kāi)發(fā)人員必須天天都在一起工作。
- 圍繞被激勵起來(lái)的個(gè)體來(lái)構建項目。給他們提供所需的環(huán)境和支持,并且信任他們能夠完成工作。
- 在團隊內部,最具有效果并富有效率的傳遞信息的方法,就是面對面的交談。
- 工作的軟件是首要的進(jìn)度度量標準。
- 敏捷過(guò)程提倡可持續的開(kāi)發(fā)速度。責任人、開(kāi)發(fā)者和用戶(hù)應該能夠保持一個(gè)長(cháng)期的、恒定的開(kāi)發(fā)速度。
- 不斷地關(guān)注優(yōu)秀的技能和好的設計會(huì )增強敏捷能力。
- 簡(jiǎn)單是最根本的。
- 最好的構架、需求和設計出于自組織團隊。
- 每隔一定時(shí)間,團隊會(huì )在如何才能更有效地工作方面進(jìn)行反省,然后相應地對自己的行為進(jìn)行調整。
當軟件開(kāi)發(fā)需求的變化而變化時(shí),軟件設計會(huì )出現壞味道,當軟件中出現下面任何一種氣味時(shí),表明軟件正在腐化。
- 僵化性: 很難對系統進(jìn)行改動(dòng),因為每個(gè)改動(dòng)都會(huì )迫使許多對系統其他部分的其它改動(dòng)。
- 脆弱性: 對系統的改動(dòng)會(huì )導致系統中和改動(dòng)的地方在概念上無(wú)關(guān)的許多地方出現問(wèn)題。
- 牢固性: 很難解開(kāi)系統的糾結,使之成為一些可在其他系統中重用的組件。
- 粘滯性: 做正確的事情比做錯誤的事情要困難。
- 不必要的復雜性: 設計中包含有不具任何直接好處的基礎結構。
- 不必要的重復性: 設計中包含有重復的結構,而該重復的結構本可以使用單一的抽象進(jìn)行統一。
- 晦澀性: 很難閱讀、理解。沒(méi)有很好地表現出意圖。
敏捷團隊依靠變化來(lái)獲取活力。團隊幾乎不進(jìn)行預先設計,因此,不需要一個(gè)成熟的初始設計。他們更愿意保持設計盡可能的干凈、簡(jiǎn)單,并使用許多單元測試和驗收測試作為支援。這保持了設計的靈活性、易于理解性。團隊利用這種靈活性,持續地改進(jìn)設計,以便于每次迭代結束生成的系統都具有最適合于那次迭代中需求的設計。為了改變上面軟件設計中的腐化味,敏捷開(kāi)發(fā)采取了以下面向對象的設計原則來(lái)加以避免,這些原則如下:
- 單一職責原則(SRP)
就一個(gè)類(lèi)而言,應該僅有一個(gè)引起它變化的原因。 - 開(kāi)放-封閉原則(OCP)
軟件實(shí)體應該是可以擴展的,但是不可修改。 - Liskov替換原則(LSP)
子類(lèi)型必須能夠替換掉它們的基類(lèi)型。 - 依賴(lài)倒置原則(DIP)
抽象不應該依賴(lài)于細節。細節應該依賴(lài)于抽象。 - 接口隔離原則(ISP)
不應該強迫客戶(hù)依賴(lài)于它們不用的方法。接口屬于客戶(hù),不屬于它所在的類(lèi)層次結構。 - 重用發(fā)布等價(jià)原則(REP)
重用的粒度就是發(fā)布的粒度。 - 共同封閉原則(CCP)
包中的所有類(lèi)對于同一類(lèi)性質(zhì)的變化應該是共同封閉的。一個(gè)變化若對一個(gè)包產(chǎn)生影響,則將對該包中的所有類(lèi)產(chǎn)生影響,而對于其他的包不造成任何影響。 - 共同重用原則(CRP)
一個(gè)包中的所有類(lèi)應該是共同重用的。如果重用了包中的一個(gè)類(lèi),那么就要重用包中的所有類(lèi)。 - 無(wú)環(huán)依賴(lài)原則(ADP)
在包的依賴(lài)關(guān)系圖中不允許存在環(huán)。 - 穩定依賴(lài)原則(SDP)
朝著(zhù)穩定的方向進(jìn)行依賴(lài)。 - 穩定抽象原則(SAP)
包的抽象程度應該和其穩定程度一致。
上述中的包的概念是:包可以用作包容一組類(lèi)的容器,通過(guò)把類(lèi)組織成包,我們可以在更高層次的抽象上來(lái)理解設計,我們也可以通過(guò)包來(lái)管理軟件的開(kāi)發(fā)和發(fā)布。目的就是根據一些原則對應用程序中的類(lèi)進(jìn)行劃分,然后把那些劃分后的類(lèi)分配到包中。
下面舉一個(gè)簡(jiǎn)單的設計問(wèn)題方面的模式與原則應用的示例:
問(wèn)題:
選擇設計運行在簡(jiǎn)易臺燈中的軟件,臺燈由一個(gè)開(kāi)關(guān)和一盞燈組成。你可以詢(xún)問(wèn)開(kāi)關(guān)開(kāi)著(zhù)還是關(guān)著(zhù),也可以讓燈打開(kāi)或關(guān)閉。
解決方案一:
下面圖1是一種最簡(jiǎn)單的解決方案,Switch對象可以輪詢(xún)真實(shí)開(kāi)關(guān)的狀態(tài),并且可以發(fā)送相應的turnOn和turnOff消息給Light。
解決方案二:
上面這個(gè)設計違反了兩個(gè)設計原則:依賴(lài)倒置原則(DIP)和開(kāi)放封閉原則(OCP),DIP原則告訴我們要優(yōu)先依賴(lài)于抽象類(lèi),而Switch依賴(lài)了具體類(lèi)Light,對OCP的違反是在任何需要Switch的地方都要帶上Light,這樣就不能容易擴展Switch去管理除Light外的其他對象。為了解決這個(gè)方案,可以采用ABSTRACT SERVER模式,在Switch和Light之間引入一個(gè)接口,這樣就使得Switch能夠控制任何實(shí)現了這個(gè)接口的東西,這也就滿(mǎn)足了DIP和OCP原則。如下面圖2所示:
解決方案三:
上面圖2所示解決方案,違返了單一職責原則(SRP),它把Switch和Light綁定在一起,而它們可能會(huì )因為不同的原因而改變。這種問(wèn)題可以采用ADAPTER模式來(lái)解決,適配器從Switchable 派生并委托給Light,問(wèn)題就被優(yōu)美的解決了,現在,Switch就可以控制任何能夠被打開(kāi)或者關(guān)閉的對象。但是這也需要會(huì )出時(shí)間和空間上的代價(jià)來(lái)?yè)Q取。如下面圖3所示:
敏捷設計是一個(gè)過(guò)程,不是一個(gè)事件。它是一個(gè)持續的應用原則、模式以及實(shí)踐來(lái)改進(jìn)軟件的結構和可讀性的過(guò)程。它致力于保持系統設計在任何時(shí)間都盡可能得簡(jiǎn)單、干凈和富有表現力。
參考文獻 - 設計模式-可復用面向對象軟件的基礎 -- 李英軍等譯
- 重構-改善既有代碼的設計 -- 侯捷等譯
- 敏捷軟件開(kāi)發(fā)-原則、模式與實(shí)現 -- 鄧輝譯
聯(lián)系方式 - 地址:陜西省西安市勞動(dòng)路90號院(臺板廠(chǎng)家屬院)六單元
- 郵編:710082
- Email: jingzhou_xu@163.net
- 未來(lái)工作室(Future Studio)