敏捷軟件開發:原則、模式與實踐——第2章 極限編程概述

第2章 極限編程概述程序員

做爲開發人員,咱們應該記住,XP並不是惟一選擇。--Pete McBreen,軟件技術專家

在第1章中,咱們概述了有關敏捷軟件開發方法方面的內容,但它沒有確切地告訴咱們去作些什麼;其中給出了一些泛泛的陳述和目標,卻沒有給出實際的指導方法。本章要改變這種情況。

2.1  極限編程實踐

2.1.1  完整團隊

咱們但願客戶、管理者和開發人員緊密地工做在一塊兒,以便於彼此知曉對方所面臨的問題,並共同去解決這些問題。誰是客戶?XP團隊中的客戶是指定義產品的特性並排列這些特性優先級的人或者團體。有時,客戶是和開發人員同屬一家公司的一組業務分析師、質量保證專家和/或者市場專家。有時,客戶是用戶團體委派的用戶表明。有時,客戶事實上是支付開發費用的人。可是在XP項目中,不管誰是客戶,他們都是可以和團隊一塊兒工做的團隊成員。

最好的狀況是客戶和開發人員在同一個房間中工做,次一點的狀況是客戶和開發人員之間的工做距離在100m之內。距離越大,客戶就越難成爲真正的團隊成員。若是客戶工做在另一幢建築或另一個州,那麼他將會很難融合到團隊中來。

若是確實沒法和客戶工做在一塊兒,該怎麼辦呢?個人建議是去尋找可以在一塊兒工做、願意並可以代替真正客戶的人。


2.1.2  用戶故事

爲了進行項目計劃,必需要了解需求,可是卻無需瞭解得太多。對於作計劃而言,瞭解需求只須要到可以估算它的程度就足夠了。你可能認爲,爲了對需求進行估算,就必需要了解該需求的全部細節。其實並不是如此。你必須知道存在不少的細節,也必須知道細節的大體分類,可是你沒必要知道特定的細節。

需求的具體細節極可能會隨時間而改變,一旦客戶開始看到集成到一塊兒的系統,就更會如此。看到新系統的問世是關注需求的最好時刻。所以,不要去捕獲某個在很長一段時間以後纔會實現的需求的特定細節,不然極可能會致使無用功以及對需求不成熟的關注。

在XP中,咱們和客戶反覆討論,以獲取對於需求細節的理解,可是不去記錄那些細節。咱們更願意客戶在索引卡片上寫下一些共識的言語,這些隻言片語能夠提醒咱們記起此次交談。基本上在客戶進行書寫的同一時刻,開發人員在該卡片上寫下對應於卡片上需求的估算。估算是基於在和客戶進行交談期間所獲得的對於細節的理解進行的。

用戶故事(user story)就是正在進行的關於需求的談話的助記符。它是一個計劃工具,客戶可使用它並根據需求的優先級和估算代價來安排實現該需求的時間。

2.1.3  短交付週期

XP項目每兩週交付一次能夠工做的軟件。每兩週的迭代都實現了利益相關者的一些需求。在每次迭代結束時,會給利益相關者演示迭代生成的系統,以獲得他們的反饋。

迭代計劃

每次迭代一般耗時兩週。迭代是一次較小的交付,可能會被加入到產品中,也可能不會。迭代計劃由一組用戶故事組成,這些用戶故事是客戶根據開發人員肯定的預算選出來的。

開發人員經過度量在之前的迭代中所完成的工做量來爲本次迭代設定預算。只要估算成本的總量不超過預算,客戶就能夠爲本次迭代選擇任意數量的用戶故事。

一旦迭代開始,客戶就贊成再也不修改當次迭代中用戶故事的定義和優先級別。迭代期間,開發人員能夠自由地將用戶故事分解成任務(task),並依據最具技術和商業意義的順序來開發這些任務。

發佈計劃

XP團隊一般會建立一個發佈計劃來規劃出隨後大約6次迭代的內容。這就是所謂的發佈計劃。一次發佈一般須要3個月的工做。它表示了一次較大的交付,一般這次交付會被加入到產品中。發佈計劃是由客戶根據開發人員給出的預算所選擇的、排好優先級別的一組用戶故事組成。

開發人員經過度量在之前的發佈中所完成的工做量來爲本次發佈設定預算。只要估算成本的總量不超過預算,客戶就能夠爲本次發佈選擇任意數目的用戶故事。客戶一樣能夠決定在本次發佈中用戶故事的實現順序。若是開發團隊強烈要求的話,客戶能夠經過指明哪些用戶故事應該在哪次迭代中完成的方式,制訂出發布中最初幾回迭代的內容。

發佈計劃不是一成不變的。客戶能夠隨時改變發佈的內容。他能夠取消用戶故事,編寫新的用戶故事,或者改變用戶故事的優先級別。可是,客戶應該儘可能不去更改一次迭代。

2.1.4  驗收測試

能夠以客戶指定的驗收測試的形式來記錄有關用戶故事的細節。用戶故事的驗收測試是在就要實現該用戶故事以前,或者在實現該用戶故事的同時纔開始編寫的。驗收測試使用腳本語言編寫,這樣它們能夠自動、反覆地運行 。這些測試共同來驗證系統是否按照客戶指定的行爲運轉。

驗收測試是由業務分析師、質量保證專家以及測試人員在迭代期間編寫的。編寫驗收測試使用的語言對於程序員、客戶以及業務人員來講都很容易閱讀和理解。程序員就是從這些測試中瞭解他們正在實現的故事的真實工做細節。這些測試成爲真正的項目需求文檔。驗收測試描述了每一個特性的全部細節,並用做驗證這些特性是否被正確完成的決定性依據。

一旦經過一項驗收測試,就將該測試加入到已經經過的驗收測試集合中,並決不容許該測試再次失敗。這個不斷增加的驗收測試集合天天會屢次運行,每當系統被建立時,都要運行這個驗收測試集。若是一項驗收測試失敗了,那麼系統建立就宣告失敗。於是,一項需求一旦被實現,就再不會遭到破壞。系統從一種工做狀態遷移到另外一種工做狀態,期間,系統的不能工做狀態時間決不容許超過幾個小時。

2.1.5  結對編程

代碼都是由結對的程序員使用同一臺工做站共同完成的。結對人員中,一個控制鍵盤並輸入代碼。另外一個觀察着輸入的代碼,尋找着代碼中的錯誤和能夠改進的地方 。兩我的認真地進行着交互。他們都全身心地投入到軟件的編寫中。

兩人頻繁互換角色。控制鍵盤的可能累了或者遇到了困難,他的同伴會取得鍵盤的控制權。在一個小時內,鍵盤可能在他們之間來回傳遞好幾回。最終生成的代碼是由他們兩人共同設計、共同編寫的,兩人功勞均等。

結對的關係要常常變換。天天至少要改變一次,這樣每一個程序員在一天中能夠在兩個不一樣的結對中工做。在一次迭代期間,每一個團隊成員應該和全部其餘的團隊成員在一塊兒工做過,而且他們應該參與了本次迭代中所涉及的每項工做。

結對編程會極大地促進知識在團隊中的傳播。仍然會須要一些專業知識,那些須要必定專業知識的任務一般須要合適的專家去完成,可是那些專家幾乎將會和團隊中的全部其餘人結對。這將加快專業知識在團隊中的傳播。這樣,在緊要關頭,其餘團隊成員就可以代替所須要的專家。Williams 和Nosek 的研究代表,結對非但不會下降編程人員的效率,反而會大大減小缺陷率。

2.1.6  測試驅動開發

第4章會詳細地討論這個主題。在此,咱們僅進行大體的介紹。

編寫全部產品代碼的目的都是爲了使失敗的單元測試可以經過。首先編寫一個單元測試,因爲它要測試的功能還不存在,因此它會運行失敗。而後,編寫代碼使測試經過。

編寫測試用例和代碼之間的更迭速度是很快的,基本上在幾分鐘左右。測試用例和代碼共同演化,其中測試用例按部就班地對代碼的編寫進行指導(參見第6章中的例子)。

做爲結果,一個很是完整的測試用例集就和代碼一塊兒發展起來。程序員可使用這些測試來檢查程序是否正確地工做。若是結對的程序員對代碼進行了小的更改,那麼他們能夠運行測試,以確保更改沒有對程序形成任何的破壞。這會很是有利於重構(在本章後面介紹)。

當爲了使測試用例經過而編寫代碼時,那麼所編寫的代碼天生就是可測試的。更重要的是,這樣作會強烈地激發你去解除各個模塊間的耦合,以便可以獨立地對它們進行測試。於是,以這種方式編寫的代碼的設計每每具備更弱的耦合。面向對象設計的原則在進行這種解耦方面具備巨大的幫助做用(參見本書第二部分)。


2.1.7  集體全部

每一對編程者都具備簽出(check out)任何模塊並對它進行改進的權力。每一個程序員都不會對任何一個特定的模塊或技術單獨負責。每一個人都參與GUI方面的工做 ,每一個人都參與中間件方面的工做,每一個人都參與數據庫方面的工做。任何人都不會比其餘人在一個模塊或者技術上具備更多的權威。

這並不意味着XP不須要專業知識。若是你的專業領域是有關GUI的,那麼你最有可能去從事GUI方面的任務,可是你也將會被邀請去和別人結對從事有關中間件和數據庫方面的任務。若是你決定去學習另外一門專業知識,那麼你能夠承擔相關的任務,並和可以傳授你這方面知識的專家一塊兒工做。你不會被限制在本身的專業領域。

2.1.8  持續集成

程序員天天會屢次簽入(check in)他們的代碼並進行集成。規則很簡單:第一個簽入的只要完成簽入就能夠了,全部後面簽入的人負責代碼的合併工做。

XP團隊使用非阻塞的源代碼控制工具。這就意味着程序員能夠在任什麼時候候簽出任何模塊,而無論是否有其餘人已經簽出了這個模塊。當程序員完成了對於模塊的修改並把該模塊簽入時,他必須把他所作的改動和在他前面簽入該模塊的程序員所做的任何改動進行合併。爲了不合並的時間過長,團隊的成員會很是頻繁地檢查他們的模塊。

結對人員會在一項任務上工做一到兩個小時。他們建立測試用例和產品代碼。在某個適當的間歇點,也許遠在這項任務完成以前,他們決定把代碼簽入回去。他們首先確保全部的測試都可以經過,而後把新的代碼集成進當前的代碼庫中。若是須要,他們會對代碼進行合併。若是有必要,他們會和在簽入上有衝突的其餘程序員協商。一旦集成進了他們的更改,他們就構建新的系統。他們運行系統中的每個測試,包括當前全部有效的驗收測試。若是他們破壞了原先能夠工做的部分,他們會進行修正。一旦全部的測試都經過了,他們就算完成了這次簽入工做。

於是,XP團隊天天會進行屢次系統構建。他們會從頭開始建立整個系統 。若是系統的最終結果是一張CD,他們就刻錄該CD。若是系統的最終結果是一個能夠訪問的Web站點,他們就安裝該Web站點,或許會把它安裝在一個測試服務器上。

2.1.9  可持續的開發速度

軟件項目不是全速短跑,它是馬拉松長跑。那些一躍過起跑線就開始盡力狂奔的團隊將會在遠離終點前就筋疲力盡。爲了快速地完成開發,團隊必需要以一種可持續的速度前進。團隊必須保持旺盛的精力和敏銳的警覺。團隊必需要有意識地保持穩定、適中的速度。

XP的規則不容許團隊加班工做。在版本發佈前的一個星期是該規則的惟一例外。若是發佈目標就在眼前而且可以一蹴而就,則容許加班。

2.1.10  開放的工做空間

團隊在一個開放的房間中一塊兒工做。房間中有一些桌子。每張桌子上擺放了兩到三臺工做站。每臺工做站前有兩把椅子。牆壁上掛滿了狀態圖表、任務明細表、UML圖,等等。

房間裏充滿了交談的嗡嗡聲,結對編程的兩人坐在互相可以聽獲得的距離內,每一個人均可以得知另外一人是否遇到了麻煩,每一個人都瞭解對方的工做狀態,程序員們都處在適合於激烈地進行討論的位置上。

可能有人認爲這種環境會分散人的注意力。很容易會讓人擔憂因爲持續的噪音和干擾而一事無成。事實上並不是如此。並且,密歇根大學的一項研究代表,在"充滿積極討論的屋子"(war room)裏工做,生產率非但不會下降,反而會成倍地提升 。

2.1.11  計劃遊戲
 

第3章中會詳細介紹XP的計劃遊戲。在這裏,僅作簡要介紹。

計劃遊戲(planning game)的本質是劃分業務和開發之間的職責。業務人員(也就是客戶)決定特性的重要性,開發人員決定實現一個特性所花費的代價。

在每次發佈和迭代的開始,開發人員向客戶提供一個預算。客戶選擇那些所需的代價合計起來小於等於該預算的用戶故事。開發者所提供的預算是基於他們在最近一次迭代或者發佈中所完成的工做量進行的。

依據這些簡單的規則,採用短週期迭代和頻繁的發佈,很快客戶和開發人員就會適應項目的開發節奏。客戶會了解開發人員的開發速度。基於這種瞭解,客戶可以肯定項目會持續多長時間,以及會花費多少成本。

2.1.12  簡單設計

XP團隊使他們的設計儘量的簡單、有表達力。此外,他們僅僅關注於計劃在本次迭代中要完成的用戶故事,而不會考慮那些將來的用戶故事。團隊更願意在一次次的迭代中不斷地變遷系統的設計,使之對正在實現的用戶故事而言始終保持在最優狀態。

這意味着XP團隊的工做可能不會從基礎設施開始。他們並不先去選擇數據庫或者中間件,而是先以最簡單的可能方式實現第一批用戶故事。只有當出現一個用戶故事迫切須要基礎設施時,他們纔會引入該基礎設施。

下面3條XP指導原則(mantra)能夠對開發人員進行指導。

(1) 考慮可以工做的最簡單的事情。XP團隊老是儘量尋找能實現當前用戶故事的最簡單的設計。在實現當前的用戶故事時,若是可以使用平面文件,就不去使用數據庫;若是可以使用簡單的socket鏈接,就不去使用ORB或者Web Service;若是可以不使用多線程,就別去用它。咱們儘可能考慮用最簡單的方法來實現當前的用戶故事。而後,選擇一種咱們可以實際獲得的和該簡單性最接近的解決方案。

(2) 你不須要它。是的,可是咱們知道總有一天會須要數據庫,會須要ORB,也總有一天得去支持多用戶。因此,咱們如今就須要爲那些東西作好準備,不是嗎?

若是在確實須要基礎設施前拒絕引入它,那麼會發生什麼呢?XP團隊會對此進行認真的考慮。他們開始時假設將不須要那些基礎設施。只有在有證據,或者至少有十分明顯的跡像代表如今引入這些基礎設施比繼續等待更加合算時,團隊纔會引入這些基礎設施。

(3) 一次,而且只有一次。極限編程者不能容忍重複的代碼。不管在哪裏發現重複的代碼,他們都會消除這些重複。

致使代碼重複的因素有許多。最明顯的是經過鼠標選中一段代碼,而後四處進行粘貼。當發現那些重複的代碼時,咱們會經過建立一個函數或基類的方法來消除它們。有時兩個或多個算法很是類似,可是它們之間又存在有微妙的差異,咱們會把它們變成函數,或者使用TEMPLATE METHOD模式(請參見第22章)。不管重複代碼源於何處,一旦發現,就必須被消除。

消除重複最好的方法就是抽象。畢竟,若是兩種事物類似的話,一定存在某種抽象可以統一它們。這樣,消除重複的行爲會迫使團隊提煉出許多的抽象,並進一步減小代碼間的耦合。

2.1.13  重構

第5章會對重構進行詳細的討論 ,下面只是一個簡單的介紹。

代碼每每會腐化。隨着咱們添加一個又一個的特性,處理一個又一個的錯誤,代碼的結構會逐漸退化。若是對此置之不理的話,這種退化最終會致使糾結不清、難於維護的混亂代碼。

XP團隊經過常常性的代碼重構來扭轉這種退化。重構就是在不改變代碼行爲的前提下,對其進行一系列小的改造,旨在改進系統結構的實踐活動。每一個改造都是微不足道的,幾乎不值得去作。可是全部的這些改造疊加在一塊兒,就造成了對系統設計和構架顯著的改進。

在每次細微改造以後,咱們都會運行單元測試以確保改造沒有形成任何破壞,而後再去作下一次改造。如此往復,周而復始。經過這種方式,咱們能夠在改造系統設計的同時,保持系統能夠工做。

重構是持續進行的,而不是在項目結束時、發佈版本時、迭代結束時甚至天天快下班時才進行的。重構是咱們每隔一個小時或者半個小時就要去作的事情。經過重構,咱們能夠持續地保持代碼儘量乾淨、簡單而且具備表達力。

2.1.14  隱喻

隱喻(metaphor)是惟一一個不具體、不直接的XP實踐,也是全部XP實踐中最難理解的一個。極限編程者在本質上都是務實主義者,隱喻這個缺少具體定義的概念使咱們以爲很不舒服。的確,一些XP的支持者常常討論把隱喻從XP的實踐中去除。然而,在某種意義上,隱喻倒是XP全部實踐中最重要的實踐之一。

想象一下智力拼圖玩具。你怎樣知道如何把各個小塊拼在一塊兒?顯然,每一塊都與其餘塊相鄰,而且它的形狀必須與相鄰的塊完美地吻合。若是你眼睛看不見可是具備很好的觸覺,那麼經過持之以恆地篩選每一個小塊,不斷地嘗試它們的位置,也可以拼出整個圖形。

可是,相對於各個小塊的形狀而言,還有一種更爲強大的力量把這些複雜的小塊拼裝在一塊兒。這就是整張拼圖的圖案。圖案是真正的嚮導。它的力量是如此之大,以致於若是圖案中相鄰的兩塊不具備互相吻合的形狀,那麼你就能夠判定拼圖玩具的製做者把玩具作錯了。

這就是隱喻。它是將整個系統聯繫在一塊兒的全局視圖。它是系統的願景,是它使得全部單獨模塊的位置和外觀變得明顯直觀。若是模塊的外觀與整個系統的隱喻不符,那麼你就知道該模塊是錯誤的。

隱喻一般能夠歸結爲一個名字系統。這些名字提供了一個系統組成元素的詞彙表,而且有助於定義它們之間關係。

例如,我曾經開發過一個以每秒60個字符的速度將文本輸出到屏幕的系統。以這樣的速度,字符充滿整個屏幕須要一段時間。因此咱們讓產生文本的程序把產生的文本放到一個緩衝區中。當緩衝區滿了的時候,咱們把該程序交換到磁盤上。當緩衝區快要變空時,咱們把該程序交換回來並讓它繼續運行。

咱們用裝卸卡車拖運垃圾來比喻整個系統。緩衝區是小卡車。屏幕是垃圾場。程序是垃圾製造者。全部的名字相互吻合,這有助於咱們從總體上去考慮系統。

舉另外一個例子,我曾經開發過一個分析網絡流量的系統。每30分鐘,系統會輪詢幾十個網絡適配器,並從中獲取監控數據。每一個網絡適配器爲咱們提供一小塊由幾個單獨變量組成的數據。咱們稱這些數據塊爲"麪包切片"。這些麪包切片是待分析的原始數據。分析程序"烤制"這些切片,於是被稱爲"烤麪包機"。咱們把數據塊中的單個變量稱爲"麪包屑"。總之,它是一個有用而且有趣的隱喻。

固然,隱喻不只僅是一個名字系統。隱喻是系統的願景,它指導着全部開發者去選擇合適的名字,把函數放到合適的位置,建立出新的合適的類和方法,等等。

算法

2.2  結論

極限編程是一組簡單、具體的實踐,這些實踐結合在一塊兒造成了一個敏捷開發過程。極限編程是一種優良、通用的軟件開發方法。對於大多數項目團隊來講,能夠拿來直接採用,也能夠增長一些實踐,或者對其中的一些實踐進行修改後再採用。

數據庫

 

 


摘自:《敏捷軟件開發:原則、模式與實踐(C#版)》Robert C.Martin    Micah Martin 著編程

相關文章
相關標籤/搜索