極限編程

極限編程（Extreme programming，縮寫為XP），是一種軟體工程方法學，是敏捷軟體開發的一種方式。如同其他敏捷方法學，極限編程和傳統方法學的本質不同在於它更強調可適應性而不是可預測性。極限編程的支持者認為軟體需求的不斷變化是很自然的現象，是軟體項目開發中不可避免的、也是應該欣然接受的現象；他們相信，和傳統的在項目起始階段定義好所有需求再費盡心思的控制變化的方法相比，有能力在項目周期的任何階段去適應變化，將是更加現實更加有效的方法。

極限編程為管理人員和開發人員開出了一劑指導日常實踐的良方；這個實踐意味著接受並鼓勵某些特別的有價值的方法。支持者相信，這些在傳統的軟體工程中看來是「極端的」實踐，將會使開發過程比傳統方法更加好的響應使用者需求，因此更加敏捷，更好的構建出高質量軟體。

## 歷史

極限編程的創始者是肯特·貝克、沃德·坎寧安和羅恩·傑弗里斯，他們在為克萊斯勒綜合報酬系統的薪水冊項目工作時提出了極限編程方法。肯特·貝克在1996年3月成為克萊斯勒系統的項目負責人，開始對項目的開發方法學進行改善。他寫了一本關於這個改善後的方法學的書，並且於1999年10月將之發行，這就是《極限編程解析》（2005第二版出版）。克萊斯勒在2000年2月取消了實質上並未成功的克萊斯勒系統，但是這個方法學卻一直流行在軟體工程領域中。直到2006年，很多軟體開發項目都一直以極限編程做為他們的指導方法學。

該書闡述了如下的極限編程的哲學思想：

- 一種社會性的變化機制
- 一種開發模式
- 一種改進的方法
- 一種協調生產率和人性的嘗試
- 一種軟體開發方法

把極限編程一般化並用於其它型別的專案稱為極限專案管理。

極限編程的推廣之一為把不同的敏捷軟體實踐和傳統實踐節奏地結合起來，彈性地合用於不同企業開發環境。這就是軟體開發節奏（Software Development Rhythms）的中心思想

## 目標

極限編程的主要目標在於降低因需求變更而帶來的成本。在傳統系統開發方法中，系統需求是在專案開發的開始階段就確定下來，並在之後的開發過程中保持不變的。這意味著專案開發進入到之後的階段時出現的需求變更（而這樣的需求變更在一些發展極快的領域中是不可避免的）將導致開發成本急速增加。

極限編程透過引入基本價值、原則、方法等概念來達到降低變更成本的目的。一個應用了極限編程方法的系統開發專案在應對需求變更時將顯得更為靈活。

## 核心實踐

極限編程實踐作業的核心可以被區分為以下四個範圍（12個實踐作業）:

### 細微回饋

- 結對程式設計
- 策劃遊戲
- 測試驅動開發
- 全隊（原名：在場客戶）

### 持續程序

- 持續整合
- 設計最佳化（原名：軟體重構）
- 小型發佈

### 共識

- 編碼標準
- 程式碼集體共有
- 簡單設計
- 系統隱喻

### 程式設計師的利益

- 可持之以恆的速度

在第二版的《極限編程解析》中，在主要實踐之外，還列出了一系列延伸的實踐。

核心實踐源自被廣泛接受的最佳實踐，並且被推向極致：

- 開發人員和客戶之間的交互是有益的。因此，一個極限編程的小組從理論上要求需要一個軟體使用者在身邊，這個使用者制定軟體的工作需求和優先等級，並且儘可能在各種問題出現的時候馬上就能回答（實際工作中，這個角色是由客戶代理商完成的）.
- 如果學習是好的，那麼就把它做到底：這樣減少了開發和回饋周期的長度，測試也能更早完成。
- 簡單的代碼更可能工作。所以極限編程的程序設計師在一個軟體專案中唯寫出能夠滿足目前實際需求的代碼，這樣或多或少降低了代碼的複雜性和重複性。
- 如果簡單的代碼是好的，那麼把變得複雜的代碼改寫成簡單的。
- 代碼評審是好的。因此，極限編程的程序設計師以兩人搭檔的方式工作。他們共享一個螢幕和鍵盤，增加了隊員之間的交流，也讓代碼在一被寫出的時候就被人評審了。
- 測試代碼是好的。因此，在極限編程中，測試用例在實際代碼之前就被寫出來了。代碼只有在通過測試的時候才被認為完成了。（當然，需要進一步分解來降低複雜性）。整個軟體系統用一種周期化的，實時的，被預先編好的自動化測試方式來保證它的確有作用。參看測試驅動的開發。
- 一般來說，極限編程被認為對於少於12人的小團隊很有用。一些人認為極限編程可以用於大的團隊，但是其它人認為Rational統一過程更適合大的團隊。然而，極限編程很難在一些超過100人的開發小組中獲得成功。並不是極限編程不能夠推廣到更大的團隊，而是很少有更大的團隊來試著用它。極限編程的人員也拒絕去隨便推測這個問題。

## 概念

### 活動

極限編程描述了在軟體開發過程中四種基本的行為，包括

- 編碼
- 測試
- 傾聽
- 設計

極限編程的提倡者爭辯說在系統開發過程的產物中真正重要的只有編碼，並認為沒有經過測試的程式碼什麼都不是。如果你沒有測試，客戶可能感覺不到，很多軟體在發佈的時候沒有經過完整的測試，它們還都在工作（或多或少的工作）。極限編程認為，在軟體開發程序中，如果一個函數沒有經過測試就不能認為它可以工作。

### 價值

極限編程技術以溝通、簡單、回饋、勇氣和尊重為價值標準。

#### 溝通

構建一個軟體系統的基本任務之一就是與系統的開發者交流以明確係統的具體需求。在一些正式的軟體開發方法中，這一任務是通過文檔來完成的。

極限編程技術可以被看成是在開發小組的成員之間迅速構建與傳播制度上的認識的一種方法。它的目標是向所有開發人員提供一個對於系統的共享的視角，而這一視角又是與系統的最終使用者的視角相吻合的。為了達到這一目標，極限編程支持設計、抽象、還有使用者-程式設計師間交流的簡單化，鼓勵經常性的口頭交流與回饋。

#### 簡單

極限編程鼓勵從最簡單的解決方式入手再通過不斷重構達到更好的結果。這種方法與傳統系統開發方式的不同之處在於，它只關注於對當前的需求來進行設計、編碼，而不去理會明天、下周或者下個月會出現的需求。極限編程的擁護者承認這樣的考慮是有缺陷的，即有時候在修改現有的系統以滿足未來的需求時不得不付出更多的努力。然而他們主張「不對將來可能的需求上投入精力」所得到的好處可以彌補這一點，因為將來的需求在他們還沒提出之前是很可能發生變化的。為了將來不確定的需求進行設計以及編碼意味著在一些可能並不需要的方面浪費資源。而與之前提到的「交流」這一價值相關聯來看，設計與代碼上的簡化可以提高交流的質量。一個由簡單的編碼實現的簡單的設計可以更加容易得被小組中的每個程式設計師所理解。

#### 回饋

在極限編程中，「回饋」是和系統開發的很多不同方面相關聯的：

- 來自系統的回饋：通過編寫單元測試，程式設計師能夠很直觀的得到經過修改後系統的狀態。
- 來自客戶的回饋：功能性測試是由客戶還有測試人員來編寫的。他們能由此得知當前系統的狀態。這樣的評審一般計劃2、3個禮拜進行一次，這樣客戶可以非常容易的了解、掌控開發的進度。
- 來自小組的回饋：當客戶帶著新需求來參加項目計劃會議時，小組可以直接對於實現新需求所需要的時間進行評估然後回饋給客戶。

回饋是與「交流」、「簡單」這兩條價值緊密聯繫的。為了溝通系統中的缺陷，可以通過編寫單元測試，簡單的證明某一段代碼存在問題。來自系統的直接回饋資訊將提醒程式設計師注意這一部分。使用者可以以定義好的功能需求為依據，對系統進行周期性的測試。用Kent Beck的話來說：「編程中的樂觀主義是危險的，而及時回饋則是解決它的方法。」

#### 勇氣

極限編程理論中的「系統開發中的勇氣」最好用一組實踐來詮釋。其中之一就是「只為目前的需求設計以及編碼，別為不可預期的未來做太多考慮」這條戒律。這是努力避免陷入設計的泥潭、而在其他問題上花費了太多不必要的精力。勇氣使得開發人員在需要重構他們的代碼時能感到舒適。這意味著重新審查現有系統並完善它會使得以後出現的變化需求更容易被實現。另一個勇氣的例子是了解什麼時候應該完全丟棄現有的代碼。每個程式設計師都有這樣的經歷：他們花了一整天的時間糾纏於自己設計和代碼中的一個複雜的難題卻無所得，而第二天回來以一個全新而清醒的角度來考慮，在半小時內就輕鬆解決了問題。

#### 尊重

尊重的價值體現在很多方面。在極限編程中，團隊成員間的互相尊重體現在每個人保證提交的任何改變不會導致編譯無法通過、或者導致現有的測試案例失敗、或者以其他方式導致工作延期。團隊成員對於他們工作的尊重體現在他們總是堅持追求高質量，堅持通過重構的手段來為手頭的工作找到最好的解決設計方案。

### 原則

組成極限編程基礎的原則，正是基於上面描述的那幾條價值。在系統開發項目中，這些原則被用來為決策做出指導。與價值相比，原則被描述的更加具體化，以便在實際應用中更為簡單的轉變為具體的指導意見。

#### 快速回饋

當回饋能做到及時、迅速，將發揮極大的作用。一個事件和對這一事件做出回饋之間的時間，一般被用來掌握新情況以及做出修改。與傳統開發方法不同，與客戶的發生接觸是不斷反覆出現的。客戶能夠清楚地洞察開發中系統的狀況。他／她能夠在整個開發過程中及時給出回饋意見，並且在需要的時候能夠掌控系統的開發方向。

單元測試同樣對貫徹回饋原則起到作用。在編寫代碼的過程中，應需求變更而做出修改的系統將出現怎樣的反應，正是通過單元測試來給出直接回饋的。比如，某個程式設計師對系統中的一部分代碼進行了修改，而假如這樣的修改影響到了系統中的另一部分（超出了這個程式設計師的可控範圍），則這個程式設計師不會去關注這個缺陷。往往這樣的問題會在系統進入生產環節時暴露出來。

#### 假設簡單

假設簡單認為任何問題都可以"極度簡單"地解決。傳統的系統開發方法要考慮未來的變化，要考慮程式碼的可重用性。極限編程拒絕這樣做。

#### 包容變化

可以肯定地是，不確定因素總是存在的。「包容變化」這一原則就是強調不要對變化採取反抗的態度，而應該包容它們。比如，在一次階段性會議中客戶提出了一些看來戲劇性的需求變更。作為程式設計師，必須包容這些變化，並且擬定計劃使得下一個階段的產品能夠滿足新的需求。

## 實踐

### 策劃遊戲

在極限編程中主要的策劃程序稱為策劃遊戲，本節將通過程序模型介紹這個程序。

策劃程序分為兩部分：

#### 送出狀態—發佈計劃

這一階段涉及成本、利潤和計劃影響這三個因素，包含四個部分：

- 按照價值排序：業務方按照商業價值為使用者故事排序。
- 按風險排序：開發方按風險為使用者故事排序。
- 設定周轉率：開發方決定以怎樣的速度開展專案。
- 選擇範圍：挑選在下一個發佈中需要被完成的使用者故事，基於使用者故事決定發佈日期。

#### 價值排序

業務方按照商業價值為使用者故事排序。它們會被分為三類：

- 關鍵：沒有這些故事系統無法運作或變得毫無意義。
- 重要的商業價值：有重要業務價值的非關鍵使用者故事。
- 最好能有：並沒有重要商業價值的使用者故事；例如在可用性或使用者界面上的改進。

#### 風險排序

程式設計師按照風險對使用者故事進行排序。他／她們將使用者故事的風險劃分成三類：低、中、高。以下是這種方式的一個範例：

- 決定風險索引：依照以下因素給每個使用者故事一個0到2的索引：
- 完全度（我們是否已經瞭解所有的故事細節？）
- 完全（0）
- 不完全（1）
- 未知（2）
- 發散性（可能會發生變化嗎？）
- 低（0）
- 中（1）
- 高（2）
- 複雜度（是否難以建構？）
- 簡單（0）
- 標準（1）
- 複雜（2）

為每個使用者故事增加所有這些索引後，給這些使用者故事指定一個風險索引：低（0–1），中（2–4），高（5–6）。

#### 激勵狀態—發佈計劃

在作業階段開發人員和業務人員可以「操縱」整個程序。這意味著，他們可以做出改變。個體的使用者故事，或是不同使用者故事的相對優先等級，都有可能改變；預估時間也可能出現誤差。這是做出相應調整的機會。

#### 探索階段—反覆計劃

反覆計劃中的探索階段是關於建立任務和預估實施時間。

- 收集使用者故事：收集並編輯下一個發佈的所有使用者故事。
- 組合／分割任務：如果程式設計師因為任務太大或太小而不能預估任務完成時間，則需要組合或分割此任務。
- 預估任務：預測需要實作此任務的時間。

#### 約定階段—反覆計劃

在反覆計劃的約定階段以不同使用者故事作為參考的任務被指派到程式設計師。

- 程式設計師接受任務：每個程式設計師都挑選一個他／她負責的任務。
- 程式設計師預估任務：由於程式設計師對此任務負責，他／她必須給出一個完成任務的估計時間。
- 設定負載係數：負載係數表示每個程式設計師在一個反覆中理想的開發時間。比如：一周工作40小時，其中5小時用於開會，則負載係數不會超過35小時。
- 平衡：當團隊中所有程式設計師都已經被配置了任務，便會在預估時間和負載係數間做出比較。任務配置在程式設計師中達到平衡。如果有一個程式設計師的開發任務過重，其它程式設計師必須接手他／她的一部分任務，反之亦然。

#### 作業階段—反覆計劃

各個任務是在反覆計劃的作業階段中一步步實作的。

- 取得一張任務卡片：程式設計師取得一張由他／她負責的任務的卡片。
- 找尋一名同伴：這個程式設計師將和另一位程式設計師一同完成開發工作。這在實施結隊程式設計中會做更深入的探討。
- 設計這個任務：如果需要，兩位程式設計師會設計這個任務所達成的功能。
- 編輯單元測試：在程式設計師開始編輯實作功能的程式碼之前，他／她們首先編輯自動測試。這在實施單元測試中會做更深入的探討。
- 編輯程式碼：兩位程式設計師開始編輯程式碼。
- 執行測試：執行單元測試來確定程式碼能正常工作。
- 執行功能測試：執行功能測試（基於相關使用者故事和任務卡片中的需求）。

### 結對程式設計

結對程式設計的意思是所有的程式碼都是由兩個人坐在一台電腦前一起完成的。一個程式設計師控制電腦並且主要考慮編碼細節。另外一個人主要關注整體結構，不斷的對第一個程式設計師寫的程式碼進行評審。

結對不是固定的：我們甚至建議程式設計師盡量交叉結對。這樣，每個人都可以知道其它人的工作，每個人都對整個系統熟悉，結對程式設計加強了團隊內的溝通。（這與程式碼集體所有制是息息相關的）.

### 集體所有制

集體所有制意味著每個人都對所有的程式碼負責；這一點，反過來又意味著每個人都可以更改程式碼的任意部分。結隊程式設計對這一實踐貢獻良多：藉由在不同的結隊中工作，所有的程式設計師都能看到完全的程式碼。集體所有制的一個主要優勢是提升了開發程序的速度，因為一旦程式碼中出現錯誤，任何程式設計師都能修正它。

在給予每個開發人員修改程式碼的權限的情況下，可能存在程式設計師引入錯誤的風險，他／她們知道自己在做什麼，卻無法預見某些依賴關係。完善的單元測試可以解決這個問題：如果未被預見的依賴產生了錯誤，那麼當單元測試執行時，它必定會失敗。

### 現場客戶

在極限編程中，「客戶」並不是為系統付帳的人，而是真正使用該系統的人。極限編程認為客戶應該時刻在現場解決問題。例如：在團隊開發一個財務管理系統時，開發小組內應包含一位財務管理人員。

### 單元測試

單元測試是用以測試一小段程式碼的自動測試（例如：類，方法）。在極限編程中，在程式碼編輯前就編輯單元測試。這種方式的目的是激勵程式設計師設想他／她的程式碼在何種條件下會出錯。極限編程認為當程式設計師無法再想出更多能使他／她的程式碼出錯的情況時，這些程式碼便算完成。

### 重構

由於極限編程教條提倡編輯程式時只滿足目前的需求，並且以盡可能簡單的方式實作。有時會碰上一套僵硬的系統，所謂僵硬的系統，表現之一是需要雙重（或多重）維護：功能變化需要對多份同樣（或類似）的程式碼進行修改；另一種表現是對程式碼的一部分進行修改時會影響其它很多部分。XP教條認為當這種情況發生時，意味著系統正告訴你通過改變系統架構以重構程式碼，使它更簡單、更泛用。參見重構。

## 極限編程的特徵

極限編程方法的基本特徵是：

- 增量和反覆式的開發 - 一次小的改進跟著一個小的改進。
- 反覆性，通常是自動重複的單元測試，回歸測試。參見JUnit。
- 結對程式設計
- 在程式設計團隊中的使用者交互（在場的客戶）
- 軟體重構
- 共享的程式碼所有權
- 簡單
- 回饋
- 用隱喻來組織系統
- 可以忍受的速度

## 爭論的觀點

極限編程也有其被爭論的一面：

- 沒有書面的詳細的規格說明書
- 客戶代表被安排在專案中
- 程式設計師以結對的方式工作
- 測試驅動的開發

絕大多數設計活動都匆匆而過，並漸進式的，開始一個「最簡單的可能工作的東西」並當其需要時（測試失敗）才增加複雜性。單元測試促成為了設計紀律。

## 參考文獻

### 來源

書籍

- 肯特·貝克：《極致編程解析：擁抱變化》，Addison-Wesley, ISBN 0201616416
- 阿里斯代爾·寇本：《敏捷軟體開發》，Addison-Wesley, ISBN 0201699699
- 雷劍文：《超越傳統的軟體開發——極致編程的幻象與真實》，電子工業出版社，ISBN 7-121-00657-X
- Lui, Kim Man 雷劍文, Software Development Rhythms: Harmonizing Agile Practices for Synergy, John Wiley and Sons, 2008（http://as.wiley.com/WileyCDA/WileyTitle/productCd-0470073861.html）

## 延伸閱讀

- Ken Auer and Roy Miller. Extreme Programming Applied: Playing To Win, Addison–Wesley.
- Kent Beck: Extreme Programming Explained: Embrace Change, Addison–Wesley.
- Kent Beck and Martin Fowler: Planning Extreme Programming, Addison–Wesley.
- Kent Beck and Cynthia Andres. Extreme Programming Explained: Embrace Change, Second Edition, Addison–Wesley.
- Alistair Cockburn: Agile Software Development, Addison–Wesley.
- Martin Fowler: Refactoring: Improving the Design of Existing Code, Addison–Wesley.
- Harvey Herela (2005). Case Study: The Chrysler Comprehensive Compensation System. Galen Lab, U.C. Irvine.
- Jim Highsmith. Agile Software Development Ecosystems, Addison–Wesley.
- Ron Jeffries, Ann Anderson and Chet Hendrickson (2000), Extreme Programming Installed, Addison–Wesley.
- Craig Larman & V. Basili (2003). "Iterative and Incremental Development: A Brief History", Computer (IEEE Computer Society) 36 (6): 47–56.
- Matt Stephens and Doug Rosenberg (2003). Extreme Programming Refactored: The Case Against XP, Apress.
- Waldner, JB. (2008). "Nanocomputers and Swarm Intelligence". In: ISTE, 225–256.

## 外部連結

- 沃德·坎寧安的網站，極致編程，關於極致編程和相關主題的更多資訊。
- 面對客戶的極致編程介紹
- 羅恩·傑弗裡斯的網路雜誌 XProgramming.com - 極致編程資源
- ExtremeProgramming.org
- 馬特史蒂芬斯的批評網站，對 極致編程的問題的深邃的批評（參見 該頁得到更多對極致編程的批評的連結）
- 馬丁·福勒論極致編程
- 搭檔編程，極致編程實踐
- 敏捷軟體開發的宣言
- 工具：" XPlanner"
- 工具：" XPWeb "
- 來自CiteSeer的引文
- 來自 方法與工具 雜誌的文章 脫離極致編程的極致編程測試：利用敏捷測試實踐的優勢
- 來自 方法與工具 雜誌的文章 結對程式設計真能改進你的專案？