問題:敏捷式軟體開發 (Agile Software Development)精彩問答
問:敏捷開發如何融入到現在在推行的CMMI中?
答:首先,我想說一下為什麼會在CMM的基礎上提出CMMI。Barry Boehm在其新作《Balancing Agility and Discipline: A Guide for the Perplexed》一書中對此進行了比較深入的闡述。從總體上來說,有兩個主要原因:1、對CMM中那些容易導致官僚的部分進行了大幅度的更改;2、把風險驅動作為一個核心內容納入到CMMI的架構之中,這樣在CMMI的架構中就可以比較順暢的制定出一些可以非常敏捷的過程了。但是,CMMI的敏捷性是很難刻畫的,因為作為一個流程改善參考模型,它更加貼近一組需求而不是一組實踐。也就是說,我們只能刻畫那些為滿足這些需求而開發出的過程。一般來說,CMMI在需求方面的約束少於SW-CMM。如果以更為寬廣的觀點去解釋需求就可以擷取更多的敏捷性。然而,如果在實施時採用了全面保守的做法並且使用了由SW-CMM所提供的重量級成熟度等級評估方法,那麼所得出的CMMI相容過程將是重型且非常計劃驅動的。因此,我覺得敏捷本來就可以非常順暢地融入到CMMI的模型中。如果說有問題的話,我覺得更多在於實施者對敏捷的排斥,而非其他。
問:敏捷開發流程是如何應對各種可預知和不可預知的風險? 例如:人員流動和變更,項目周期的變更,客戶代表的變更等風險。
答:人員流動和變更、項目周期的變更以及客戶代表的變更等風險是任何一個軟體開發項目都不可避免要面臨的。一個好的過程方法應該能夠使得這些風險導致的損失最小化。敏捷方法試圖營造一種非常舒適的開發環境,這是一種典型的craftsmanship文化。在這種文化中,人們都一自己的技藝為榮,以開發出高品質的軟體為榮,並且不斷追求技藝的提高。在這樣的環境中,人員流動和變更的頻度被大大地降低。另外,敏捷方法對面對面溝通、結對程式設計以及高品質代碼和文檔的強調也使得由於人員變動所導致的風險大大降低。
對於項目周期的變更,我想再也沒有比快速、短的迭代更有效應對方法了。正是這些快速的短迭代為我們帶來的大量的反饋資訊,使得我們對於項目的狀況具有全面、深入並且是真實的瞭解。有了這個基礎,我們在最小化項目周期變更風險方面就處於一個非常有利的位置。而快速的短迭代正是敏捷的重要特徵。什麼是敏捷呢?敏捷就是:“short cycles that are test-driven and feedback-driven, yielding constant improvements.”對於客戶代表的變更,我不想多說。因為無論是對于敏捷方法還是計劃驅動方法,客戶代表的變更帶來的風險都是一樣的。如果,沒有一個好的客戶代表,那麼肯定是一個失敗的項目。
問:敏捷開發流程是否適用於大型、複雜的應用系統?因為對於一些架構比較簡單,代碼量小的系統,可以通過不斷的代碼重構進行改進,但對於一些體繫結構比較複雜的系統在投入運行後,短時間內,由於客戶業務的擴張導致的資料容量的增大或者網路訪問量的增加, 而導致原有的核心架構設計已經不能滿足使用者的需求,而這些重要的架構在系統核心服務中起重要作用而很難進行變更。這種情況,變更這些方面的代價會很高,因此需要早期花費精力預期此類變更。而且這類軟體的複雜性和規模會導致嚴格的代碼重構代價過高而且容易出錯。
答:首先我們得在什麼是大型、複雜的應用系統這個問題上取得共識。Scrum方法應用的最大的一個項目是一個醫學映像資訊系統,共有800人。XP方法應用的最大一個項目是一個企業資源綜合管理系統,共有50人。當然,在人數增多時,就必須要採取一些變通的實踐(否則就不敏捷了)。對於架構方面的問題,我覺得應該這樣看。如果是一個相對成熟的領域,那麼可以借鑒很多業界已有的經驗,特別是一些相關的模式。這一點很重要,否則是要走很多彎路,付出很多代價的。比如:我覺得在並發、分布式通訊領域,一個合格的系統工程師必須應該知道並理解《Pattern-Oriented Software Architecture, Volume 2》中的所有模式。但是,這隻是為你提供了一個方向,一個防止你犯重大錯誤的方向。這些模式為你代碼的重構和系統的演化提供了一個指引。如果不瞭解這些模式,基本不可能做出一個優秀的架構。瞭解了這些模式後,是不是就可以在一開始就把它們堆砌起來以形成一個能夠適應未來的架構呢?當然不行。要想構建一個能夠適應未來的架構,有兩種途徑,一種需要天才的系統架構師,一種是在領域模式的引導下,通過TDD和Refactoring的方式不斷、逐步地修改。顯然,第2種方法是一種切實可行的方法。
問:敏捷開發流程是否不支援建立可複用產品?對於一個工程型,可複用的產品對於節約成本和提高效率是極其重要的!
答:關於可複用性的問題,一直都是軟體界討論的熱點。一般來說,有機制層面的複用,比如:一般的函數庫或者類庫,也有應用領域邏輯的複用,比如:各種領域相關的應用程式框架。第一種複用方法相對比較容易,但是帶來的好處也相對較低。而第二種複用方法能給我們帶來最大的好處,但是非常的困難。也正是因為這一點,在業界一度有“複用神話”的說法。無數實踐表明,要想得到一個相對可用的領域架構,必須要經受至少3個同質領域實踐的錘鍊。並且,失敗的數目要遠遠大於成功的。而試圖在一開始就把可複用性作為目標的項目基本上沒有取得成功的(這樣的架構一般具有這樣的特點:本來一件簡單的任務,但在使用了該架構後卻變得非常複雜。)。因此,現在業界比較一致的看法是,首先應該針對你開發的領域搭建一個特定於項目的、簡單的架構。一開始不要考慮複用性,而關注於系統的清晰性和簡單性。在另一個同質的項目中,通過重構、演化的方法在對這個架構進行修正,使之更具通用性,如此迴圈往複。在經曆過多重專案後,可能你就得到了一個比較具有可複用性的架構。也就是說,應該關注於建立那些比較容易演化為可重用架構的東東,這個東東應該具有兩個特點:1、針對具體問題;2、非常簡單清晰。敏捷方法非常注重這種架構的形成,但是不會刻意去這樣做,它的思路是在不斷的迴圈、迭代中把它演化出來。在這個迴圈迭代中,敏捷方法以DRY(Don't Repeat Yourself)原則來逐步建立起更大規模重用的基礎。
問:敏捷開發流程的品質保證機制是否足夠滿足開發有嚴格安全性和可靠性要求的軟體?對於在電力,電信系統中一些有嚴格安全性要求的軟體敏捷開發流程支援的品質控制機制似乎並沒有證明來說服使用者軟體是安全的。是否還需其它措施進行補充?
答:首先我要說的是,安全性和可靠性是屬於使用者需求的範疇,而敏捷方法中把客戶滿意放在了非常重要的位置上,單從過程方法的思想基礎方面來說,沒有那種方法能比敏捷方法更關注客戶的滿意度了。其次,安全性和可靠性不是通過一些條條框框說出來的,那些在系統方案中空洞地羅列一些安全性和可靠性方面的術語的做法,對於保證系統的可靠性和安全性沒有任何用處。保證安全性和可靠性的唯一方法就是去檢驗,隨著系統的演化,不斷地檢驗。把使用者在安全性和可靠性方面的需求通過測試案例的方式編寫出來,頻繁地去驗證系統是否能夠通過這些測試,如果不通過,就是一次整合失敗。不知大家在保證系統可靠性和安全性方面是如何做的?
問:目前的項目和部門的組織架構,內部客戶和外部客戶離開發人員都很遠,怎樣能夠達到零距離? 雖然單個客戶和開發人員在一起工作可以有效對需求變更進行跟蹤,及時響應需求變更,但如果系統面對的客戶是不同的,如何避免開發期間一些需求變更的單一性和獨特性?
答:無論項目採用任何方法,它對於客戶都有同樣的要求,就是這個客戶必須是CRACK(Collaborative、Representative、Authorized、Committed、Knowledgeable)型的客戶。鑒於目前我們所處的各種環境,完全的CRACK和現場客戶可能不太可能。但是一個能夠合格地擔當其客戶角色,並且能夠比較頻繁的參與到項目開發中來的人員對於項目的成功來說是必須的。另外,應對需求的變化正是敏捷方法的強項,如果這些變化是客戶真正需要的,那麼為何要避免呢?此時,我們應該利用這些變化取得優勢。
問:如何避免開發人員利用夠用文檔這個借口偷懶少寫文檔?
答:處于敏捷文化中的人以高品質地完成任務為榮,如果寫文檔是高品質地完成任務的一部分,那麼他肯定會高品質地寫出這份文檔。否則,寫再多言之無物、只滿足格式的文檔又有什麼用呢?敏捷實踐都是能夠真正提供開發人員技能的實踐,敏捷方法強烈反對那些僅僅是為了防止開發人員“偷懶”而制定的規程。
問:開發人員面對面的交流過頻繁,導致大會小會不斷,如何把握這個度?
答:面對面交流不是開會。只要覺得需要就去交流。
問:簡單設計的粒度如何把握,如果強調前期架構的簡單設計,如何應對軟體投入運行後,短時間內,由於客戶業務的擴張導致的資料容量的增大或者網路訪問量的增加,而導致原有的設計已經不能滿足使用者的需求?
答:請參見前面那個關於架構的回答。首先,你要有豐富的經驗和知識,這些東西可以為你提供一個架構演化的方向。如果沒有這些東西,基本上沒有可能首次就找到正確的方向。有了方向後,下面就是TDD+Refactoring不斷演化。
問:簡單設計如何能保證實施測試驅動開發?如果設計的不夠詳細,如何對介面編寫測試案例和測試代碼?
答:首先,不是簡單設計保證實施測試驅動開發,而是測試驅動開發可以促使你得到一個簡單的設計。其次,是先有測試案例,然後才有設計和介面。
問:《敏捷》書中把建立驗收測試作為一種設計系統架構的重要手段,也作為對終端使用者的一種功能示範,但本質上還是對系統特性的一種類比整合測試,並不能完全代表實際系統,這種驗收測試與傳統意義上的驗收測試不同,這種驗收測試可靠嗎?
答:這裡所指得傳統意義上的驗收測試是什嗎?是指有測試人員進行的測試嗎?一般在敏捷方法中(特別是XP)所指的驗收測試,都是由QA和客戶代表共同編寫的,如果通過就表明實現了客戶需求。我覺得沒有其他方法能比這個方法更可靠了。
問:測試驅動開發的例子中,開始也做了簡單的設計,然後再編寫測試案例,最後形成另外一種設計。開始時需要設計嗎?如果需要,應該達到什麼程度?開始不進行設計而純粹依靠測試來驅動設計可能嗎?我的理解是,測試驅動開發更適合於詳細設計階段,測試驅動開發適合於架構設計嗎?文章中的測試驅動開發例子中,軟體需求好像來自個人“隨心所欲”的想象,這種測試案例的產生方法是否缺乏系統性和完備性?或者說,測試驅動開發的測試案例的產生是否也需要嚴密的設計呢?
答:什麼是設計?這是一個必須首先達成共識的問題。TDD的核心就是持續設計,不斷關注設計品質,這種關注是建立在頻繁的、真實的反饋的基礎之上的,而不是一些臆想。達到的程度就是“tuned to today and poised to strike at tomorrow.”通過一些想象畫幾張UML圖,那不是設計,設計應該是可驗證的,並且要通過反饋持續修正的。設計的驗證正是通過測試案例進行的。測試案例可以是客戶需求,這是驗收測試。也可以是Team Dev內部實現上的需求,這是Team Dev內部的測試(一般也成為單元測試)。測試案例應該來自客戶,這是勿庸置疑的。測試活動本來就是一項風險驅動活動,在測試投入到達一定水平後,它的效果會迅速降低。對於“系統性”、“完備性”以及“嚴密性”,我不知道具體指得是什嗎?能不能詳細說明一下,並介紹大家是如何做到需求的“系統性”、“完備性”以及“嚴密性”。
問:敏捷設計開始設計的程式也可能是最簡單,不具有靈活性,直到需要變化時,團隊才抓住機會應用敏捷設計原則去改進設計。這裡有幾個前提,團隊應該對不良設計足夠敏感,才能抓住改進設計的機會;團隊有足夠的時間去改進設計。如果這兩個前提不成立,如果進行敏捷設計?
答:怎樣才具有靈活性呢?把東西做簡單,簡單的東西最具有靈活性!Kent Beck在《eXtreme Programming》一書中對什麼是簡單做過明確的定義。用一句話來說,就是:“clean code that works.”如果這些前提不成立的話,那麼什麼設計都做不了。很多敏捷實踐的目的就是協助我們通過學習、實踐來培養這種敏感性。
問:測試驅動開發過程中如何把握“前進的步伐”,即,每個測試案例的粒度如何把握?粒度大,可以加快開發速度,但又可能漏掉某些bug;粒度小,又影響開發進度。如何看待測試驅動開發過程中的測試案例?是單元測試嗎?還是粒度很大的整合測試?如果是單元測試,至少也不應該是傳統意義上的單元測試,此時的單元測試是屬於黑箱測試還是白盒測試,或者既不是黑盒也不是白盒?如何理解測試驅動開發可以改進設計?有何理論根據?能夠從黑箱測試的理論闡述這個問題嗎?
答:粒度就是一個獨立的、可以驗證的東西。Kent Beck在其《Test-Driven Development》一書中對使用TDD開發的節奏有詳細的描述,我就不再贅述。寫測試覺得不會影響開發進度,越是在時間壓力大的情況下,越是如此。我想大家都有過這樣的經曆吧:“花20分鐘完成了一項功能,然後花2個小時甚至更多的時間去調試。”在TDD中,測試案例只用兩種,面向客戶的驗收測試用例,和面向Team Dev內部的自我裝載用例(一般也稱為單元測試)。為什麼一定要那麼清楚地區分黑盒和白盒呢?測試驅動開發能夠改善設計的思想基礎在《Test-Driven Development》有詳細闡述。這和黑箱測試沒有任何關係。TDD更是一種設計方法,一種有反饋、有驗證的真正的設計方法。
問:關於“軟體之美”:對軟體設計者來說,被簡單、直觀地分割,並具有最小內部耦合的內部結構就是美的。美的系統是靈活、易於理解的,構建、維護它們就是一種快樂。在軟體領域,如何審美?“靈活、易於理解的”這個概念含有很多主觀性,對某一具體的軟體審美,不同的人的評價是不一樣的,大師層級的人當然更準確些,但大師層級的人太少了,那麼,有沒有一些客觀的、可以量化的指標?使得沒有很多經驗的人,也可以以此為指引,改進軟體使之向美的方向發展?
答:《敏捷式軟體開發 (Agile Software Development):原則、實踐和模式》一書中給出了很多原則和實踐方法,可以作為很好的參考。
問:極限編程只適用於輕量級團隊和項目,還是也適用於重量級團隊和項目?和CMM等有無矛盾?在推行極限編程哪些可行(如測試驅動開發),哪些不可行(如結對程式設計)?在重量級團隊和項目中如何運用?
答:極限編程對於小型項目(10~20人)來說肯定沒有問題。對於大型項目來說,照搬XP中的實踐,肯定是會出問題的。所以需要一定程度的根據具體情況進行修正。關於和CMM有無矛盾的問題,這方面的討論和文章有很多,基本上是見仁見智。不過,在提高開發品質這個目標上是肯定不矛盾的。其實,關於CMM本身該如何實施方面也存在很多不同意見,不同的評估師給出截然不同的結論的案例就有很多。其實也沒有必要非得全盤照搬XP不可,我覺得可以在不更改團隊現有運作流程的情況下,先引入小部分實踐,TDD應該是首選。
問:5個重要的原則“單一職責原則、開放-封閉原則、Liskov替換原則、依賴倒置原則、介面隔離原則”雖然在此把它們表述為物件導向設計的原則,但是事實上它們只是軟體工程中一直存在的原則的特例而已。那麼,軟體工程中一直存在的普遍性原則是什嗎?有哪些?在結構化編程還大量應用的嵌入式開發中,如何運用?“為使用而使用”設計原則會導致不必要的複雜性,設計原則是經驗的總結,它必然是思考某個問題而得到的解決辦法指導,那麼,在編程當中,時刻要思考的問題有哪些?
答:首先我得說一下,越是具有普遍性得原則,越不具有可實施性,只有針對特定context和force的原則才具有更多的實際意義,這也是模式為何在傳播優秀的設計經驗方面得到普遍認可的重要原因。如果非要給出一個普遍原則的話,我覺得Grady Booch曾經說過的一句話可以作為參考:“The entire history of sw enginerering is one of rising levels of abstraction.”不論你使用結構化編程還是物件導向編程,瞭解多種編程範型肯定會對你的開發帶來好處。設計原則和模式只能為你指引方向,最為重要的是要保持(設計)代碼簡單,時刻思考的問題就是,這段代碼是不是清晰地表達了我的意圖,也就是要intentional programming,要“Keep It DRY, Shy, and Tell the Other Guy.