大型專案的XP(極限程式設計)

agile_boy發表於2009-03-31

我們在ThoughtWorks這樣的大型專案中應用XP方法的時間超過了15個月。這個專案開始於三年前,那時它有大量的需求文件和幾個獨立的功能小組。從2000年1月起,我們決定應用XP,雖然當時我們已經知道XP並不適用於大型專案。那時,我們需要向客戶提交功能演示,並要通過提交一個工作子集而不僅僅是原型來贏得他們的信心(我們在團隊中有超過25名開發人員和大約15名分析員)。但我們並未準備好功能,各個組都使用自己的程式碼框架,一個完整的應用無從談起。簡短地說,就是客戶想要看到點什麼,但我們還沒有真正的功能。應該說開發的第一迭代期是成功的:我們給客戶提交了一個真正的應用子集。成功的首要原因是我們讓來自Asset, AR 和GUI組從事不同工作的開發者融合在一起。當然,其間也有"成長的煩惱":在分析員和開發者之間發生某些個人衝突,但我們成功跨越了這些障礙。那時一切都很美好:我們以飛快的速度成功地提交了功能演示,但隨著時間的流逝和專案的繼續,有些事情卻不如我們所願。這就是這篇文章要講述的內容:我們真正的收穫在"蜜月"期後,關於我們如何在一年半中管理一個50人的專案開發並及時完成階段性的提交(儘管有時並不成功),關於我們經歷的痛苦,我們後續的工作,我們最終學到的以及作為改進要用到下一個專案中的經驗。

首先,我們給出我們開始的狀況:15個月前我們是如何應用XP的,然後展示我們現在的XP應用情況。也就是說,下面將討論我們改變技術的原因。這是一個自然選擇的過程,它剔除了許多不好的想法,或把它們改造成更有效的方法,使之更適於大型專案。最後我們將總結並給出在大型專案中使用XP的謹慎建議。

大型專案中XP的元素

好吧,讓我們來進入正題。我們開發和分析的隊伍由大約35名開發人員、15名分析人員和10名QA組成。開發人員依賴分析人員作為專案的客戶。儘管有實際的客戶,分析人員還是要協同工作以便有選擇地做出客戶決策。下表演示了[1]所討論的XP基本元素並簡要介紹了這些方面如何應用到專案的各個階段。我們用這個表來分析我們團隊自然選擇的實踐,以及書本上的XP如何應用到一個超過50人的大型專案中。

  計劃 提交週期 比喻 設計的簡單性 測試 重構
1/2000 大跨度的迭代計劃會議。開發和分析組的全部成員整天在一起討論新的故事卡片和預估。大多數開發者簽入(sign up)新的功能。 1個月 轉變已有的程式碼基準。已有的程式碼依然複雜,但新的程式碼要儘可能簡單。這個階段包括拋棄老的程式碼和重寫那些"今後可能會被用到"的功能程式碼。 單元測試開始於一些新的程式碼。推動建立一個大的測試基準。QA做所有的功能測試並有權留棄故事卡片。 對於舊有程式碼,如有必要就進行重構。
7/2000 基本同1/2000,但確實感覺十分低效。多數與會者沒能很好地參與。拖沓的討論,50人的會議是無法忍受的。 1個月 以儘可能簡單的原則繼續設計。完成對已有設計的重構。完成程式碼會審,旨在全體範圍中討論新設計以便整個團隊瞭解程式碼和設計的發展趨勢。 更好的單元測試覆蓋更大的範圍,儘管沒有完全覆蓋。程式碼功能測試幫助覆蓋測試範圍。 多數開發人員埋頭於新功能的開發,很少會去做重構。程式碼基準在迭代期末向QA組提交卡片時變得糟糕起來。
1/2001 希望能儘快做出每個迭代期間的計劃-我們的辦法是在正式會議前以小組為單位進行更多的準備工作。 2 周 多數的設計基於已有的設計:保留標準,程式碼會審逐漸停止,因為新的設計和重構尚未完成。 試圖去掉程式碼功能測試而代之以螢幕搜刮(Screen Scraper),若失敗就回到程式碼功能測試 。加入新的單元測試但仍然沒有全部覆蓋。QA組開始結合介面測試使用自動功能測試。 重構開始更頻繁,因為部分程式碼開始變得凌亂不堪。需要清理的原因主要是實現簡單和迭代期限使得程式碼在沒有重要重構的情況下增長。
6/2001 舉行一些討論卡片或相關卡片組的會議,參加者包括對這些功能感興趣或有經驗的開發者和負責這些卡片的分析人員。 2 周 隊伍中的大多數人及整個QA組準備提交1.0版本給客戶。程式碼的基準分離以便加入沒有測試的新功能。對單元測試有更多的依賴。 儘管仍有遺漏,測試範圍已經基本穩定。QA組不再測試新功能,因為焦點是1.0版本的提交。 在釋出版上做的重構很少,而在繼續開發的版本上,開發人員會很盡責地進行重構,特別是在年初被迫做了更大更痛苦的重構以後.


  結對程式設計 集體所有 持續整合 40小時周 在場客戶 程式碼規範
1/2000 由於我們決定採用XP,整個團隊讀了[1]。每個人都做了嘗試,多數人被吸引。 由於最初階段的分組是面向功能,因此此時我們並未意識到集體所有 (collective ownership) ,也沒有意識到程式碼的保護。 從第一迭代期開始,進行線上整合,參見[2] 這是一個概念工作時間:因為我們希望客戶在場。於是我們會花另外的時間來滿足最後期限。 事務分析人員是在場的客戶,他們15人一組。真正的客戶是不在的,由分析人員同他們溝通。 基本上是JAVA的一般語法。
7/2000 結對程式設計依舊盛行:開發者對新功能進行結對程式設計,但改錯和維護工作由單個人來做。也有一些開發者停止了結對程式設計。 當開發者越來越多地接觸系統不同的部分的時候,程式碼的所有者逐漸顯現出來。成員間通過閒談,程式碼互審和短小的站立會議(Stand up meeting)進行很好的溝通。 程式碼功能測試加入構造過程。 為了通過故事卡片,在每個迭代期的最後工作時間達到50至60小時。 同上 兩週一次的程式碼互審給開發人員一個機會討論不同子系統的實現方式。我們可以接受某些子系統程式碼的非正式方式。
1/2001 結對程式設計更少了,因為這一階段編碼更直接,而有些人在進行重構。 因為效率低,站立會議被棄用,但程式碼的所有顯現得更加清晰。開發人員開始專職負責系統的某部分。 穩定_同上。 以2周為迭代期,開發人員的工作時間更接近於40小時… 同上 程式碼互審逐漸減少,設計及編碼規範趨於飽和。
6/2001 定下了規則:所有新功能要應用結對程式設計,而改錯和維護則由一人完成。 隨著專業化分工的繼續,不同的開發小組人員擁有不同部分程式碼的知識,於是我們將使他們在接下來相應模組的設計中起更活躍的作用,但程式碼仍是集體共有。 穩定同上。 同上 同上 同上


結對程式設計

首先我們說說結對程式設計的體會。多數情況下,我們在某個迭代期間有兩個開發人員同時為一個故事卡片(或幾個迭代期的相關卡片)工作。在大型專案中開發人員需要投入更多的關注,因為開始新領域的編碼的熱身時間是不容忽視的。開發人員間良好的溝通和週期性的計劃會議讓每個人都具有誰在做什麼的整體概念。這使得經典教科書中開發者甲找到開發者乙要求共同解決問題的結對程式設計方式成為可能。

結對程式設計當然很好,但並非任何時侯都適用。最通常的情況是,在改錯和維護時開發人員並不願結對,並且這種情況下許多眼睛盯著除錯程式碼也確實沒什麼好處。再有就是迭代期間的重複工作,這種情況下,問題的解決方案已經確定,不必再結對了。

還有,開發人員有不同的個性:有些人需要間歇性的結對程式設計,而有些人更加出色,結對程式設計會妨礙他們才能的發揮而最終成為他們的負擔。

單元測試和整合構造

單元測試和整合構造絕對是必要的,這意味著如果我們沒有測試,我們就不能提交任何程式碼。當應用程式變得越來越大時,沒有測試我們就不能加入任何新功能或進行重構。我們現在在新程式碼進庫時會有整合構造和測試。關於這些構造及測試的細節,負責人員會及時放在內部網頁上,這樣每個開發人員都能知道當前的構造狀態,事務分析員和QA能拿到最近構造的資訊來測試新的功能。

組內所有和資訊共享

對於這樣一個大型的專案,為了防止被分為孤立的部分而使整個系統做出不適當的假設,資訊的釋出和不同部分的程式碼輪作非常重要。溝通是必需的(但我們無法強迫一個沉默的人開口)於是我們試圖在每兩週一次的短會上給每個人發言的機會,以使沉默寡言的人能說出他們的要求。而最終我們取消了這樣的會議,因為大多數開發人員認為這種把每件事都蜻蜓點水地提一下的會議只是浪費時間。這也是這個團隊的優點之一??我們總能象一個共同體般地工作,如同結對程式設計一樣地合作。

開始,我們採用了輪作的方法,也就是每個人對每件事都作一點,這使得我們在後來快到截止期限的時候都在從事己經瞭解的事情。但對於一段複雜的程式碼,要做到這一點,時間投入非常巨大。最好採用折衷的辦法:也

就是在專案時間緊的時候只作每個人熟悉的工作,而在其它時候,比如改錯、研究或正在做一項熟悉的工作時,可以同時做一件不熟悉的事。我們現在的原則是,開發人員在幾個迭代週期中連續做一些相關的卡片,同時逐漸地轉向系統的其它部分。在同一個迭代期內簽入幾個不同卡片的做法己經不再用了。

程式碼確實會越變越糟。是因為我們的專案有些大嗎?還是因為許多做程式碼的人都是新手(是指這個功能領域中的新手,而非程式設計新手)?答案可能是二者皆有吧。但有時我們不接觸程式碼,很難開始系統的其它部分,因此定期清理程式碼是必須的。這樣引出我們下一個論題:重構。

重構

在應用XP的大型專案中,為了消除程式碼的不一致性,重構是絕對必要的。即便對於那些對專案的應用領域很熟悉的人,也會面對重構的巨大工作量望而卻步。對於專案經理來說,必須認識到重構需要另行分配時間。我們做到了這一點,我們留出了時間來重構程式碼的主要部分。

短迭代週期

迭代期及其期限是必須的,但長度一直是個問題。過去我們採用長迭代週期(如一個月),而每到月末就會很緊張並伴隨著一些不良程式碼的加入,並且不可避免地在估計上出現問題。我們不得不接受一些未做的卡片(這對開發人員來說非常困難,並且難以滿足既定的期限)。

總結

下面把18個月中我們在這個50人專案的經驗和教訓列出如下:

1) 在每個迭代期開始時進行迭代計劃會議。每日客戶和開發人員討論最近的故事卡片並評估它們,在每天的討論結束後重新分組並演示這些評價和發現,然後讓開發人員簽入。這可以讓整個專案組知道專案的當前情況而不用讓每個人都捲入馬拉松式的會議。

2) 使提交版本週期儘可能短:我們是兩週一次,但在必要的時候也可以使提交跨多個迭代週期。允許在多個迭代週期簽入卡片,但要以每個週期為單位進行進度的監控。

3) 進行儘可能多的單元測試,這是不言而喻的。應當有一個自動進行功能測試的軟體包以保證測試的覆蓋範圍。但是QA組是不可替代的(無論開發人員寫過多少測試程式),因為我們對系統怎樣工作總是存在偏見。

4) 簡單的設計能幫助我們連續向客戶提供可工作的版本。頻繁的設計會議對於加入大量新功能時是很有用的,而午餐是一個召集整個專案組的好時候。這可以避免在系統的不同部分同時存在不相容的解決方案。

5) 重構是能夠做到簡單設計的唯一方法。設計的重構與程式碼的重構同等重要。儘管不進行重構而採用打補丁的解決方法往往是有吸引力的,但是如果一個系統的補丁太多,那就意味著今後它將進行更大的重構。

6) 在加入新功能時,要堅定不移地貫徹結對程式設計,而在改錯和做重複性工作時停止,因為問題已經在結對時解決了。

7) 集體所有和溝通密不可分。團隊必須有一種有效的溝通方式。也許不僅僅是非正式的討論,有時定期的10到15分鐘的釋出會是很好的方式。

8) 在大型專案中,一些人要扮演客戶的角色,為大量開發人員產生足夠的工作。這和領域知識密切相關。

9) 編碼標準是十分非正式的,這不會損害你的進度。更重要的是一種通過演示的溝通。程式碼不是文件的全部,開發人員需要看到全貌,這是程式碼不能提供的。

也有一些規則我們沒有實行:

1) 兩週一次的站立會議是低效的。可以選擇每月一次的迭代團隊通氣會來替代。

2) 迭代計劃會議沒有必要讓全部人員參與。更好的方式是按更小的組進行研討,而在每天下班前用30到45分鐘對卡片進行討論。

3) 一個月的迭代期太長,不利於產生高質量的程式碼。2週一次的迭代週期更容易跟蹤並使估計更準確。

4) 上一點在大程式碼量時並不合適,特別是重構大規模系統時。這時一張卡片會影響到多個迭代期。

5) 比喻(Metaphor)對於大型系統是不適合的。

6) 每週40小時我們來說不成問題,40小時是最少的情況,超時工作並沒有給我們帶來不利的影響。要重申的是,我們不是100%的實行結對程式設計。

這就是XP,或者說我們的XP版本,在我們小組所做的工作。我們經歷了按時提交大型複雜應用的過程,也為每個開發人員提供了應對此類專案的寶貴經驗。

參考書目

1. Beck, K. Extreme Programming Explained: Embrace Change. Addison-Wesley, 1999; ISBN201-61641-6

2. Fowler, M. and Foemmel, M.; Continuous Integration

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/14639675/viewspace-582381/,如需轉載,請註明出處,否則將追究法律責任。

相關文章