在《敏捷軟件開發(fā)》上中下系列的上篇里,我們探討了開發(fā)人員做法,也回顧了技術(shù)優(yōu)勢如何大幅提高軟件質(zhì)量。第一部分把重點主要放在了測試-編碼-重整循環(huán)上?,F(xiàn)在我們轉(zhuǎn)到中間一個圓環(huán),看看敏捷開發(fā)做法如何在小組這一層次發(fā)揮作用。

讓小組高效工作——小組做法
一旦每個開發(fā)人員都在緊密圍繞中心圓環(huán)的反饋循環(huán)工作時,我們就可以看看整個開發(fā)小組能夠如何以更加敏捷的方式工作。小組這一層次的做法是敏捷開發(fā)的核心,因為它們能夠顯示出小組成員可以如何更加高效地一起工作并推動共同進行技術(shù)決策。我們將分別從四個方面來討論小組的這種改變——設(shè)定基調(diào)、基于小組的代碼編寫標準、提高和保持效率、采用“統(tǒng)一小組”方式(包括與開發(fā)小組直接相關(guān)的東西)的首要步驟。我們給你舉的例子來自于3Q Solutions公司,這是一家生產(chǎn)財物管理系統(tǒng)并完全使用敏捷開發(fā)方法的軟件公司。
設(shè)定基調(diào)——第一步
敏捷軟件開發(fā)的一個中心思想是小組朝著一個共同的目標工作。盡管很多流程都提倡小組工作,但是敏捷開發(fā)(真正)融合了支持小組工作的做法,并將小組工作放到了日常做法里。在開始討論小組做法之前,我們需要先為小組設(shè)定一個基調(diào),讓他們開始感覺更像是一個真正的小組。
開放的工作空間
為更加開放的、基于小組的敏捷開發(fā)方式設(shè)定基調(diào)的一種最佳方法是為小組創(chuàng)造一種開放的工作空間(open workplace)。這意味著要建立一個或多個開放的區(qū)域,并盡最大可能進行溝通和合作。你想要專門了解什么樣的環(huán)境能夠讓配對編程更容易。小格間和辦公室是與敏捷開發(fā)開放工作空間格格不入的,所以應該避免其出現(xiàn)。在一家與Exoftware有合作關(guān)系的公司里,開放空間區(qū)域只被用于工作,里面只有用于配對編程、集成和構(gòu)建軟件的機器。其它的所有區(qū)域都留給帶有Internet連接和電話的個人計算機。如果你有這樣的空間,這就是應該考慮的東西,因為它有助于清楚地表明“當我們在工作區(qū)的時候,我們在工作”。
不要低估開放的工作空間對于小組的重要性——這就是為什么我們將其作為第一步的原因。下面的一幅照片就是是3Q Solutions開發(fā)小組的工作空間。

請注意,兩張大桌子(下面沒有文件柜)被擺在一起,構(gòu)成了最適合配對編程的辦公桌。
集體主義主人翁精神
我們想要介紹的下一個思想是集體主義主人翁精神(Collective Ownership)。敏捷編程的這種中心思想是讓每一個人都對整個系統(tǒng)負責,每一個人都有更改代碼的自由。這是一種重要的思維方法,因為它讓小組的注意力都集中到了項目上,從而確保有一個共同的目標。與配對編程相關(guān)的其它步驟也強調(diào)這種思想,但是盡早引入這種思想是非常好的。
簡單設(shè)計
敏捷開發(fā)崇尚簡單的漸進設(shè)計,而不是劇烈的顛覆式設(shè)計。其目標是(首先)只指設(shè)計我們所了解的項目的那些部分,僅此而已,然后讓該設(shè)計隨著時間的推移而逐漸改進,這有助于提高靈活性并將變化導致的成本最小化。
我們就從3Q Solutions公司舉一個例子,有一個客戶要求獲得一個規(guī)則引擎(rules engine)。小組傳統(tǒng)的做法是花上數(shù)月時間開發(fā)規(guī)則引擎,然后可能還是無法把它賣出去。在與客戶共同協(xié)商的情況下,小組決定設(shè)計一個滿足規(guī)則引擎工作要求的最簡單系統(tǒng),并為每一條規(guī)則創(chuàng)建一個瘦垂直系統(tǒng)(a thin vertical system)。這就給予了客戶他們真正需要的東西——可證明的規(guī)則——并確保投資抵消了投入的時間。這樣小組可以在保持靈活性的同時從一開始就不斷改進設(shè)計。簡單設(shè)計是一個復雜的領(lǐng)域,研究它的最佳方法是獲得外部的幫助。
重要的成功因素
- 贊同——整個開發(fā)小組堅持嘗試使用敏捷開發(fā)以及開發(fā)小組圓環(huán)里的做法極其重要。如果不能這樣堅持,開始甚至保持這樣的做法都是非常困難的。
- 溝通——這一點怎么強調(diào)都不夠。保證小組里高層次的溝通和對諸如集體主義主人翁精神這樣的概念的理解非常重要。
- 配對編程——配對編程為很多小組做法提供支持,并將加強小組的溝通和凝聚力。
- 行政——如果沒有行政上的支持,創(chuàng)造開放工作空間將會非常困難。在某些情況下,當行政機構(gòu)的官僚主義作風盛行的時候,我們只用進行一些改變就行了。
- 每日例會——這一個每天早上進行的簡單會議,供開發(fā)人員討論當日面臨的工作和問題。這樣的會議應該是站著開的,因為其時間不應該超過幾分鐘。
小組編寫代碼——第二步
既然我們已經(jīng)安置好了工作空間,并設(shè)定了小組的基調(diào),我們現(xiàn)在就需要看看小組是如何處理代碼的。我們這里的目標是確保所有通過配對編程編寫的代碼都能無縫地集成在一起,并且符合小組所承認的標準。通過推動第二步的進行,我們?yōu)橹С值谝徊竭€有很大一段路要走。
代碼編寫標準
無論你是否決定采用敏捷編程,代碼編寫標準(coding standard)是一個非常好的最佳做法。這一步驟涉及讓小組創(chuàng)立一套他們能夠完全理解和堅持使用的代碼編寫標準。代碼編寫標準給予我們下列優(yōu)勢:
- 它讓我們能夠輕松地讀懂別人的代碼,這樣所有人都可以進行(代碼)交換。
- 代碼為未來接手的小組提供了一個絕佳的信息源,即使有小組成員離隊。
- 新的小組成員有一套指導方針——而不是瞎猜。
大多數(shù)小組都會利用已有的框架,并圍繞其構(gòu)建自己的一套標準。這里的關(guān)鍵要素是開始,立即解決小組正在奮力解決的問題,然后根據(jù)需要向前推進。也不要為了標準而去強行推行標準——這畢竟是整個小組需要共同認可、相信和使用的東西。下面是3Q公司代碼編寫標準文檔的一小段。
CamelCase
CamelCase里的一切、類名稱都以大寫字母開始,而方法和字段的名稱則不需要。
任何內(nèi)容都不要放在有大括號的那一行。
字段以下劃線開頭: | _fieldname |
變量名不以下劃線開頭: | variableName |
方法: | public void methodName(String stringValue) |
?
接口公開
公共方法在類的最上部,后面跟有受保護的方法,然后才是私有方法。將所有繼承自抽象類或者實現(xiàn)結(jié)構(gòu)的方法都靠前放置,這是一個好主意。
盡可能做到立即就能找到一個類,并馬上可以感覺到其功能以及它如何實現(xiàn)該功能,而不需要滾屏。
方法和類的名稱
讓其名稱能夠說明其功能。注意,不同的開發(fā)人員對于什么樣的方法可讀有不同的看法,他們更喜歡從周圍的類,甚至是方法里的參數(shù)看出其作用。對這一點還存在爭議,但是從名字來判斷一個方法的作用是肯定可行的,因此:
doIForAllX()
就不理想,但是:
setupAllTableRowItems()
就很好。
而:
createRows()
可能更好。
[getVarvscalculateVar, 直接的getter對方法]
[不要將查詢與作業(yè)混在一起]
方法的抽象
方法里的代碼的抽象程度應該與同一個方法里其他所有代碼的相同。這樣的話,事件的自然過程能夠被弄清楚。例如:
public void initializeDataBase()
{
??_connection = createConnection ();
??setUpTable();.
??For (inti=0;i<tableRows;i++)
????SetUpTableRow(i);
}
你稍稍一瞥,不用費什么功夫就可以讀懂它。我們在3Q的時候非常珍惜視力,所以把這段代碼變成了幾個清晰明了的步驟,就像下面這樣:
public void initializeDataBase()
{
??setUpConnection();
??setUpTable();
??setUpTableRow();
}
這就有可能:
1.感覺到事情進展得怎么樣
2.很容易就瀏覽到我們希望找到的類的確切部分(如果我們對表格行的設(shè)置感興趣,我們就按住Ctrl點擊setUpTableRow())。
得墨忒爾法則(Law of Demeter,即最少知識法則)
類應該只能夠訪問那些可以直接從其字段或者變量訪問到的方法。對送進來的對象或者類自行實例化的對象的參考也是如此。
一般情況下,不要這么做……
publicintcalculateRetirementFund()
{
return getClient().getRetirementDetails().getRetirementFund();
}
……而要這么做:
public void calculateRetirementFund (RetirementDetails details)
{
return details.getRetirementFund();
}
這有助于為類設(shè)定范圍并減少不必要的方法調(diào)用和委派。
順序選擇迭代
一般可以將方法分為下面三種類型。一系列事件,一個接一個;對集合的搜索或過濾;以及對集合或者數(shù)組的迭代。
收集方法、向量創(chuàng)建、向量設(shè)置、向量功能(vector dosomething)
集合一次又一次地出現(xiàn),每次都是同樣的問題,主要同類型有關(guān)。如果在集合里有一個任意的運行庫強制轉(zhuǎn)換(casting),那么總有出現(xiàn)錯誤類型的機會,導致強制轉(zhuǎn)換異常的出現(xiàn)。
讓集合變成可以針對具體類型,這使得在編譯的時候檢查往集合里加入的內(nèi)容成為可能,同時還讓根據(jù)類型來適應自定義的集合方法變得更容易。
不要使用臨時變量——用查詢來替代臨時變量
在有關(guān)重整的書上查找這個內(nèi)容——“用查詢來替代臨時變量”,最好不要抱著臨時變量不放,它會增加代碼的復雜性,給閱讀者帶來困難,同時減少了對算法作進一步重整的可能性。
測試打破常規(guī)
過多的設(shè)置意味著不佳的模式。你應該只需要設(shè)置那些與你正在測試的類直接相關(guān)的對象。
盡量讓單元測試精細化,這將帶來可移植性更強的代碼,并將它推向更加清晰、更加獨立的實現(xiàn)。
通過回調(diào)制針測試
回調(diào)制針(backpointer)完全就是個麻煩事,應該避免其出現(xiàn)。它會帶來相當多的異常,狀態(tài)模式就是其中一個。一定要了解自己實現(xiàn)回調(diào)指針的理由。如果理由是“它會起作用”,那么你就在失去什么東西。
視圖測試——將測試三要素實例化
在一個構(gòu)造完好的應用程序里,視圖層應該從域抽象出來,達到一種不需要創(chuàng)建視圖就能夠測試該應用程序的程度。不夠精細的測試需要更加經(jīng)常地更改。見上文測試打破常規(guī)。
這只是來自一個不斷改進的小例子。我再提醒一遍,從簡單的開始,保持其基本框架,得到所有人的同意。
?
連續(xù)集成
瀑布式方法的一個缺陷是代碼庫的集成往往每隔數(shù)周或者數(shù)月之久才進行一次。新的錯誤常常會隨著代碼的集成而不斷暴露出來,我們不得不花額外的時間來更正錯誤并重新集成。如果集成不是頻繁進行,那么反饋就不可能像應該的那么緊密。敏捷開發(fā)要求進行更加頻繁的集成——在3Q的案例里,這意味著每天要集成一到兩次。
大多數(shù)小組一般都會有一臺構(gòu)建計算機,成對的開發(fā)人員能夠利用其檢查在測試-編碼-重整循環(huán)里編寫好的代碼。每對開發(fā)人員都有確信其代碼在被集成到代碼庫之前就已經(jīng)經(jīng)過測試和重整。一旦檢驗完畢,自動化的構(gòu)建計算機就會編譯所有的代碼,運行所有的測試,并通過顯示器(向小組)顯示出來——構(gòu)建過程是否需要引起注意——例如:新加入的代碼有沒有破壞什么東西?
這會做兩件事情:
- 從代碼被集成(進代碼庫)到小組意識到存在問題之間的時間間隔會被減到最小。
- 構(gòu)建顯示器將信息傳達給整個小組——不論是集成成功完成——還是需要引起注意——這讓小組可以立即作出相應的反應。
像這樣頻繁的集成意味著軟件的構(gòu)建是不停進行的,任何人在任何時候都可以參與構(gòu)建過程。構(gòu)建過程需要被自動化,以便使集成盡可能地容易,這是十分重要的。下面就是3Q公司的構(gòu)建監(jiān)視器的向小組傳達信息的一個例子。



就如上面圖畫所顯示的,構(gòu)建服務器能夠向小組提供額外的信息。
重要的成功因素
- 自動化——這需要成為一個自動化的過程。否則你將不得不專門找一個開發(fā)人員來維持構(gòu)建過程——這可不是一個有意思的工作。首先就要營造環(huán)境,取得設(shè)備和實現(xiàn)自動化。
- TCR和配對編程——對于這一層次的集成工作,小組必須按照測試-編碼-重整循環(huán)來進行,這樣他們才有信心保證所有的問題只會發(fā)生在集成過程里。如果沒有TCR循環(huán),這一部分的過程將會非常困難。
- 按部就班——就像這個小標題說的,不慌不忙地從簡單的地方開始,然后隨著時間的推移來逐步改進——尤其是在代碼編寫標準這一塊。
保持高效率——第三步
就如我們在《上篇》里說的,敏捷開發(fā)過程是一項工作強度很大的編程方式。除此之外,軟件開發(fā)本身就壓力重重,而小組累垮的可能性非常高。
可持續(xù)的步伐意味著開發(fā)小組現(xiàn)在和未來的工作都將非常艱苦。加班不是我們希望鼓勵的事情,盡管有的時候需要如此。如果小組不得不加班工作,那么我們想要嘗試將可持續(xù)步伐里的加班時間控制在一到兩周而不是一到兩個月。再強調(diào)一遍,敏捷開發(fā)是一項強度很大的工作;配對編程要求很多交互和重視,測試-編碼-重整循環(huán)也是如此。盡管敏捷開發(fā)會引發(fā)我們小組的最大潛能,但是我們需要清楚很多時候的大量加班會累垮整個小組的風險。
重要的成功因素
這是管理者必須十分清楚的一個領(lǐng)域。確保小組在整個項目里保持合理的步伐是其主要職責。
開始轉(zhuǎn)移到統(tǒng)一小組——第四步
有的人可能認為Metaphor的概念應該來得更早一些,但是我們建議在這一階段快結(jié)束的時候才引入它,因為這是我們首次提到客戶/業(yè)務方(customer/business)。Metaphor是客戶與開發(fā)人員之間系統(tǒng)的通用語言。它看起來可能不重要,但是以Exoftware的政府顧客為例,開發(fā)小組一般都把業(yè)務方(也就是定義系統(tǒng)需求的人)當作客戶。但是對于業(yè)務方而言,“客戶”指的是最終用戶。這就導致開發(fā)人員和“業(yè)務方”之間的困惑和挫折。
Metaphor的作用不只是一門通用語言——它還與上下文和對系統(tǒng)是什么的高層次理解有關(guān)。在這里我們能夠采取步驟做到真正地與我們的業(yè)務合作伙伴溝通并共享共同的目標。3Q公司使用一種叫做Adaptor Tree Hierarchy體系,它通過一門客戶/業(yè)務方共同認可的語言給予開發(fā)人員一個廣闊的系統(tǒng)視野。例如:
ThreeQData
- todaysDate
- marriage
- spouse
- economicindicators
- client
- lossofincomestory
- annualincome
- coveramortisationeroision
- ...
- managedfundstory
- pensionstory
這個樹形結(jié)構(gòu)的每一部分都可以擴展出更多細節(jié),能夠輕易地改變,并提供一個很好的系統(tǒng)視角,同為整個小組提供一門通用的語言。
?
重要的成功因素
- 堅持到底——只有當你堅持使用的時候Metaphor才會有效。它將會成為日常語言的一部分,但是適應它需要花時間。
- 從基本的開始——從Metaphor的基本框架開始,了解它,使用它,然后以此為基礎(chǔ)來創(chuàng)建它。
- 取得幫助——讓盡可能多的相關(guān)業(yè)務方/客戶參與Metaphor的創(chuàng)建——讓其他人盡早參與進來是至關(guān)重要的。
敏捷開發(fā)的小組做法的目的是幫助小組把重點放在集體工作上,并理解其共有的做法和目標。盡管有的做法,比如代碼編寫標準,能夠在隔離的情況下完成,但是如果與具體的開發(fā)人員做法,例如測試-編碼-重整和配對編程結(jié)合起來,那么這些小組做法將發(fā)揮最大效用。
本系列的最后一部分將探討開發(fā)人員小組如何開始同客戶方/業(yè)務構(gòu)成“統(tǒng)一小組”。
?
Brian Swan是Exoftware公司教授敏捷開發(fā)的指導老師。他在敏捷開發(fā)的技術(shù)和管理方面具有相當豐富的經(jīng)驗,曾經(jīng)帶領(lǐng)很多小組成功地轉(zhuǎn)換到了敏捷開發(fā),并以敏捷開發(fā)的思想和做法來培訓開發(fā)人員和管理人員。他在Exoftware公司和在敏捷開發(fā)方面的工作使他到過很多公司,并對其開發(fā)小組產(chǎn)生了持續(xù)的、積極的影響。Brian先前的經(jīng)驗還包括擔任Napier大學的講師,講授軟件開發(fā)和人機互動。Brian可以通過電子郵件聯(lián)系上。