和業務建模時期不同的是,我不再花費筆墨討論需求要如何做,因為做法、注意點和業務建模時期并沒有什么太大的區別。而在完整的流程上,像RUP、XP之類的方法學可比我講的要好的多。因此,我會把焦點集中在我在實際工作中的一些困惑,以及一些思考。
1、"和其它階段的關系"的再思考。
上一篇的末尾我們簡單的討論了細節需求階段和其它階段的關系。對于軟件過程的各個階段,不同之處只是注重的焦點不同而已。在業務建模階段,我們關注于系統的整體需求;在細節需求階段,我們更關注于需求的細節部分。其它的階段也是一樣,架構階段,所關注的當然是如何設計出一個合適的架構;到了設計階段,注意力就轉移到了如何設計方面。 當然,焦點的不同,導致了各個階段所需要的技能和工具也不盡相同。業務建模階段需要你有整體的把握能力,你可以使用簡單的用例圖,基本的用戶素材等工具。細節需求階段則要求你能夠充分的挖掘需求和進行良好的溝通。相應的,在架構、分析、設計等階段,也會有不同的需要。
各個階段的實質就是注重點的不同,這對于大多數的軟件開發而言都是一樣的。不論你采用的過程是傳統的,還是迭代的。
2、架構
Martin Fowler在他的ISA中寫到:
I'm using architecture to mean the important design decisions, the ones that shape most aspects of a software system. These are often the harder decisions to change later on in the project (although often not as hard as people think). As a result these are ones where it's useful to start in the right direction, and thus knowing about architecture is a valuable skill for any software developer.
架構并不神秘,無非是一個決策而已,只是這項決策對軟件特別重要就是了。軟件開發人員可能根本沒有主動的進行架構設計,但是他的行為,已經潛移默化的進行了;而還有一些人,總在談論著架構,但是并不了解這個詞的含義。 春運就要到了,學生也要趕著回家。如何選擇回家的交通工具就是一個重要的決策。路程的遠近、不同交通工具的價格都是顯式的,比較容易知道的。而以往的經驗也告訴你,火車票比較便宜,但是比較緊張,花費時間較長,整個過程也不舒服;飛機票比較貴,但是容易買到,花費時間少,整個過程很舒服。這時候你就要做出正確的決策,為回家選擇一個正確的架構。你可能考慮的因素有哪一些?以下就列出了一些可能的因素:
擁擠程度,大家都知道春運時那種情況;
購買票的難易程度,火車票需要很早就要預定了;
是否有額外的渠道,比如你能夠買到飛機的學生票;
經濟實力,經過了一個學期的花銷之后,現在還剩多少生活費;
根據這些因素,以及這些因素對你的影響程度,即優先級,你可以自己估算出一個或幾個可能的架構方案。而這種架構的選擇,直接影響到你之后的行為,也影響到行為的結果。
開發軟件和買票回家又能有什么區別呢?一樣要考慮成本、結果、時間。所不同的只是復雜了:需要專業技能,有很多不確定的因素。
那么我這里談論架構的問題,和需求有什么關系呢?在上面的例子中,大家可以看到架構是根據什么決定的?是因素。因素的本質是什么?就是需求。因素,就是需求。所以,需求決定架構。上一篇中,我談到說,在進行細節需求之前,一定要定出架構。當然,這時的架構可能只是一張草圖。為什么?因為我們已經進行了業務建模,對項目有了一定的認識,對用戶的需求也有一定的把握,成本、范圍、時間等要素也都清楚了(如果你還不了解這些,請你回到業務建模階段,你的工作還沒有結束)。這個時候,決定架構的因素已經形成了,可以進行架構的設計了。 需求能夠決定架構,架構反過來也能夠影響需求。最明顯的一個例子就是用戶界面的設計。雖然用戶界面主要來自于需求,但是不同的架構對用戶界面也會有影響,例如基于瀏覽器的客戶端,和基于Windows界面客戶端能夠提供的界面就不同。
在XP中,這種的架構設計,被稱為Architecture Spike。為什么叫做Spike呢?就是說你需要專研,解決一些主要的問題,但你并不是提供一個完整的解決方案。例如,在項目的初期,如果你對新近的服務器和操作系統不了解,你肯定會花時間去了解,去試用,去測試;如果對數據庫不了解,你也肯定會試著使用看看。這種行為,就是Spike。所以呢,架構的設計只是很初步的設計,而不是一個完善、定型了的設計。這一點要注意。
架構的選擇和開發人員的經驗和能力非常有關系。一般來說,它需要開發人員具有相關的經驗。提供架構的廠商多如牛毛,如何選擇,也是一項學問。比如,數據倉庫的平臺,選擇的品種就很多;而Web Server的選擇也是五花八門;操作系統也是一樣。這些又都是和架構息息相關的。
3、模式
武功有招式,下棋有棋譜。不論是招式,還是棋譜,都是針對某一種問題的特定解決方案。在軟件開發領域,這種解決方案就被稱為模式。
"每一個模式描述了一個在我們周圍不斷重復發生的問題,以及該問題的解決方案的核心,這樣,你就能一次又一次的使用該方案而不必做重復的勞動"[AIS,77]
這句話源自模式的鼻祖――Christopher Alexander。而在軟件開發領域,最值得一提的著作,就是GoF寫的『設計模式』一書。在該書中,作者描述了23種的設計模式,可以說,這些模式奠定了面向對象設計的基礎。而另一本值得閱讀的著作,就是Martin Fowler所著的『分析模式』。
在軟件設計中,我們遇到各種各樣的問題,我們可能缺乏經驗,或能力有限。這非常的正常。但是現實是,我們生產出的代碼由于設計方面的缺陷,往往不夠清晰,容易出錯,難以擴展。相信只要是開發過軟件的人,都遇到過這種問題。于是,我們就希望能夠看看其他人,是如何處理這種問題的。這里的"其他人"指的可能是技術專家,也可能是經歷過同種問題的人,他們對你遇到的問題有能力,有經驗來解決。他們提出的解決方案往往是非常成熟的,能夠解決你目前遇到的問題,也能夠解決你目前尚未遇到的問題。
這對你的吸引力是很大的。那么,我們談論模式,模式來源于何處呢。注意,模式是針對某一類的問題的解。這里的問題,所指的就是需求。比如說,客戶希望能夠在軟件中實現不同的稅率計算方法,那么,我們很自然的就可以想到Strategy模式;當客戶的產品有一個很復雜的單位換算機制的之后,我們也能夠很自然的想到Quantity模式。使用模式,能夠使我們迅速的把握需求的解決方法。另一方面,模式往往告訴我們比目前的問題更多的方面,因為模式都是大家的經驗沉淀。如上所說,它還可以解決你目前沒有遇到的問題。因此,我們還可以從模式中發現出更深的需求。
另外一點也很重要,雖然它和需求的關系不大。模式往往都有一個模式名稱。這就形成了一種溝通的語言。比如我們在下象棋的時候,只要說"馬后炮",誰都知道這是什么意思,絕對不需要呢詳細的解說每一步棋子的走法。對于軟件開發也是一樣的。我和我的同伴會心的一笑,說:"Factory Method。"兩個人都能夠理解這是什么意思,因為這是一種共通的語言,它代表了背后隱藏的各種類的關系和代碼實現。這在軟件開發中非常的重要。當然,這有個前提,大家都對模式有一個通透的了解。
4、簡單設計
模式屬于設計的一環,所以前面我們討論的其實就是設計和需求的關系。這一小節我們還是討論這個話題。但是側重點有所不同。XP中有一個原則:KISS。不是kiss哦。它是Keep it simple and stupid的縮寫。除了XP,其它的敏捷方法都提倡簡單設計,反對過分設計(over build)。也就是說,針對目前的需求,設計目前的軟件。
很多的軟件人員都是完美主義者,他們喜歡完美的設計,然后把這種設計提供給用戶。這種思想就是過分設計的開始。不必要的功能浪費了客戶的投資。我們在做需求的時候,很經常發現開發人員隨意的向客戶推銷一些新功能,或是在設計時,過多的考慮未來可能出現的需求變動。 所以,簡單設計的意思,就是要針對目前客戶提出的需求進行設計,不要過多的考慮目前沒有提到的功能。
5、如何統一
細心的讀者看到這里可能已經是疑竇叢生了。一邊是鼓勵使用、設計最完美的方案;另一方面,又強調簡單。似乎是自我矛盾。不錯這其中是由矛盾的地方,但也有一致的地方。因此,在使用先進的模式和保持設計的簡單性之間,我們需要權衡。 一次,我們看到了一個關于權限設置的模式,我們覺得這個模式非常的好,它提供了類似于UNIX操作系統那樣的權限控制,可以很隨意的增加組、用戶,并能夠在文件級別上設置權限。我們如獲至寶,覺得這是一個非常有用的模式。于是,我們花了一些時間將之實現,并打算應用于新的軟件中。
在實際中,我們發現沒有一個用戶需要如此強大的功能,他們所需要的可能僅是密碼控制,或是簡單的用戶管理。如此復雜的功能對他們來說沒有任何的意義。完美的模式在現實中遭到了冷遇。
實際上,用戶目前不需要這項功能,并不意味著他以后不需要這項功能。用戶的計算機程度提高的很快,我們估計,再過那么一兩年,用戶可能就非常需要這項功能來管理他那日益龐大的員工隊伍了。但是目前,這項功能對用戶來說,設置復雜,所以他們并不愿意接受這個"有價值"的功能。
最后,我們想到了一個解決的辦法,我們為這一項功能定義了一個通用的接口。通過這個接口,你可以實現復雜的功能,也可以實現簡單的功能?傊,你只要是實現了接口的方法就行了。接口的方法很多,但是在目前的簡單的實現中,可能就僅僅是一個返回語句,并沒有很多的實現。相應的,用戶的也僅僅需要使用簡單的方法,諸如addUser(),updatePasswd()等。界面也做了簡化的處理。
通過這種方法,我們可以在用戶需要的時候,替換掉權限模塊,對其它的應用并不影響。當然,其中有很多的細節需要注意。在完成之后,我們還發現了另一個副產品:整個的權限控制模塊是高內聚,低耦合的。
模式,就好比螺帽的設計圖紙,它規定了螺帽的技術規格,但是沒有規定具體的尺寸。對應于不同的需要,我們可以設計出不同大小的螺帽以供使用。圖紙只需要一份就可以了,并不需要為每一種尺寸的螺帽畫一張圖紙。
因此呢,一個經歷了實踐檢驗的模式,往往功能強大。但是它可以有多種不同的實現。有哪一條法律規定你必須完全的實現一種模式呢。在實際使用中,你需要權衡模式使用的成本和效益。你會發現,在很多情況下,你還是實現了模式,但只是模式的一個框架,或一部分,但是這在目前就夠用了。而當需求變動,或新的需求出現的時候,你可以很方便的在原有搭起的框架上添磚加瓦。一切都是那么的自然。比如,在一個進銷存的軟件中,存在一個運輸選擇算法,目前的運輸途徑就一種,但是很有可能會增加新的途徑。這時候,你就決定采用Strategy模式。但是你只是實現了一個簡單的框架,只有一個具體子類,來實現目前的算法。當新的運輸途徑出現時,你需要增加一個算法,你就可以再增加一個子類,只要實現的接口相同,改動是不會影響到系統其它的部分的。
6、測試
測試是非常重要的,是軟件成敗的關鍵。但是目前國內對測試并不關注,或是假裝關注。這樣就無法保證軟件的質量。測試有很多種,我們這里要說的是和需求息息相關的測試,就是接收測試(Acceptance Test)(關于這個詞,可能不同的文章會有不同的譯法)。
Surely you aren't going to assume you're getting what you need. Prove that it works! Acceptance tests allow the customer to know when the system works, and tell the programmers what needs to be done.
上面這段話摘自『XPInstalled』。接收測試有兩個作用:首先是讓客戶明白系統能夠做什么,然后是讓程序員明白該讓系統做些什么。
有一種測試的方法是把測試留到最后才做,讓客戶去發現錯誤。千萬別這么做。原先花費1塊錢就可以改正的錯誤,到了這個時候,可能需要花費1000塊錢才能解決。這是軟件開發的放大效應。因為很多的工作已經基于這個錯誤建立了,開發人員也已經對這個錯誤沒有映像了。
XP中有一個很重要的價值,叫做反饋(Feedback)。Kent Beck在Extreme Programming Explained中有句話講得非常好:"樂觀是編程的職業病,反饋則是其處方。"從需求的識別,到根據需求構建的系統交付給客戶,客戶提出意見。這就是一個反饋過程。反饋過程所花費的時間越少越好。接受測試就是解決客戶反饋的一個有效的手段?蛻艟帉懣芍貜偷測試腳本,開發人員開發出的軟件要經受這個測試腳本的考驗。這種的反饋速度是很高的,能夠有效的解決反饋的問題。
因此,客戶在要求實現需求時,同時也有義務提供相關的接收測試:
if it's worth having the programmers build it, it's worth knowing that they got it right.
一個有價值的功能一定是可測試的,如果不是,那么這個功能要么是沒有價值,要么是尚未描述清楚。 要注意,這個測試必須是可重復的。這是因為需求的易變性。需求在不斷變化,這就意味著代碼在不斷的變化。因此,原先已經用接收測試證明過了的代碼還需要再次證明。這就要求測試是可以重復的。
大量的測試,甚至重復的測試引出了一個新的問題:全憑手工進行測試會浪費大量的時間。因此,易變的需求對測試提出了一個新的要求:自動化測試。只有自動化的進行測試,才可以完成如此大量的測試工作。目前,最好的自動化測試工具,應該就是Xunit系列。關于這方面的問題,大家可以參考相關的資料,這里我們不作深入的討論。
接收測試最可能的一種形式就是自然語言的說明,外帶一組的測試數據。需要強調的一點是,這個測試數據一定要包括輸入和輸出。這樣才可以做出比較。如果只有輸入沒有輸出。測試很可能就是白費勁。所以,計算這個輸出是手工計算的,它也是必要的。
除了接收測試,還有一個很重要的概念就是單元測試(Unit Test)。但是單元測試和設計的關系比較大,和需求沒有過多的關系,我們這里就只是點一下。大家如有興趣,可以參考相關的資料。
7、分解
對于需求來說,需要用到的最多的技能可能就是分解的技能了?梢哉f軟件科學最重要的思想就是"分而治之"的思想。不是嗎?面向對象是不是一種分解的思想。類、組件、包,這種層級結構不正是體現了"分而治之"嗎?當然我這里可能把包和組件弄混淆了。但我的主要目的是要指出這種分解的方法在軟件開發中是無處不在的。對于需求也是一樣。我們最早做的業務建模就是為了得到一個系統的概貌圖。然后到了細節需求階段,我們會把這張圖放大,細分,一直到我們有把握處理為止。
如何把100塊磚累起來呢?如果一塊一塊的累,那很容易就倒了。一種比較好的做法,就是先10塊10塊的打包,這樣,100塊磚就變成了10個磚包,再把它們累起來就容易的多了。面向對象其實就是這么做的,當然,面向對象的實現比累磚要難多了。 我們看看XP中是如何處理分解的。XP中最大的周期叫做發布版(release),一個發布版需要一個月或幾個月的時間,一般不超過6個月。發布版的末期,需要向客戶提供一個可以運行的軟件的發布版。然后,XP還定義了次級的周期,稱為迭代(iteration),一次的迭代大概需要一周或幾周的時間。每一次的迭代都是一個"偽發布版"(pretend release),就是說,迭代的最后也必需要提供一個可以工作的軟件,這個軟件隨時都可以發布。為了定義一次迭代中要處理的事情,XP還定義了素材(story),一份素材代表了客戶希望在軟件中出現的一項功能(feature),一份素材是很小的,它只需要花費一個開發人員幾天或幾周的時間。素材已經很小了,但是還需要細分到任務(task),一項任務只需要1到4天的工作量。這并不是最小的單位,XP還把任務劃分到測試(test),但這已經到個人級別上了。
我們看到,XP從客戶到每一個開發人員,定義了5級的單位,并把時間精確到了天、小時。所以我有時候聽人說,XP好像對開發人員的要求不嚴格。錯了,XP可以說是目前要求最為嚴格的方法,這種分類方法可見一斑。這種分類有什么好處呢?
首先,我們來看發布版,發布版的最短時間是一個月,也就是說,最頻繁是一個月向客戶交付一次軟件。這樣,就在很大程度上保證了反饋的迅速進行。避免了傳統的開發方法中最后客戶發現問題時已經太遲了的現象。
再看迭代,迭代之所以被稱為偽發布版,就是因為它的產出物的性質和發布版是一樣的。都是可以交付的產品,但是迭代的功能比較少,沒有必要交付給客戶。我們知道,在傳統的軟件開發中,整合是一個大問題。整合必然會出現問題,但是沒人知道問題在哪兒。所以呢,XP通過不間斷的整合,避免了這個問題。
但是,迭代的周期如此之短,能夠做些什么呢。這就是素材出現的原因。素材由客戶提出,由客戶決定優先級,由客戶決定放在哪一次的發布版和迭代中。同時,如上面我們談到的,客戶需要為素材制定接收測試。
一份素材的周期是幾天或幾周,而一次迭代的時間也就幾周。這說明素材對迭代而言,單位過大了。所以要把素材再次分解為任務。每一個任務都需要一個開發人員認領,簽字。在分解素材的過程中,我們可以發現有一些任務是多個素材共享的,這個概念和用例中的使用的概念是一致的。開發人員會估計自己的任務所需要的時間。從而得出一個迭代周期的總時間。這個時間的估計是基于以往的經驗的,因此隨著項目的進行,這個估計往往會越發的準確。
我們這里講XP的分解哲學,并不是要求大家也依樣畫葫蘆,你真要那樣做也不行。因為XP的各項實踐都是一體的,只有實現了所有的實踐,才能體現其威力。我們這樣斷章取義是行不通的。但是其中的思想我們是可以借用的。分解、歸類、排序、估計。這種分析問題的方法,也是我們值得借鑒的。這里有幾點要注意:
最早的分解依據往往是客戶要求的時間。例如,客戶希望在3個月內看到什么什么。在客戶和開發放商議之后,決定制定兩次的發布版。這個決定雖然開發方可以提供參考意見,但是決定權在客戶方;
素材的提出,素材的優先級,素材的安排,這些都是客戶的權利?蛻粢灿袡嗬∠、增加、修改素材,或是改變其優先級;
客戶投入多少,就能夠看到多少的軟件?蛻粢部梢匀∠壳暗捻椖,而且,先前的投資也會有相應部分的軟件產出;
對于開發時間的估計是開發人員的權力,其它任何強加于開發人員的時間安排都是不對的;
任務的選擇也是出于開發人員自愿的原則;
如果開發人員估計出的總的時間和迭代的預計的時間有出入,絕對不能犧牲開發人員的額外時間換取迭代在限定時間內完成。這種做法無異于飲鴆止渴。比較好的做法是去掉一些任務。
8、客戶如何參與
這是一個純粹的補充問題。一次,一位讀者寫信來問我,中國的客戶素質比較低,對計算機不了解,XP強調的現場客戶現實中根本做不到。
XP要求開發人員在開發軟件的過程中隨時予以支持。誠然,要做到這一點是很難的。我自己也遇到過這種難題,知道問題的棘手程度。我想,這個問題可以分為兩個方面。
一種是定制的軟件。對于這種項目,你需要解決用戶的參與問題,往往客戶方的老總愿意投入資金,但是卻不愿意投入支持的人力。我也曾見過客戶方專門招了一個應屆生來對付需求的情況。遇到這種情況,如果你沒有能力克服它,那么這個項目絕對是失敗的。即便項目最后成功了,申請了什么"重大攻關"之類的獎項,你我都很清楚,這只不過是表面功夫而已。造成這種問題的原因有很多,你需要分析它們,列舉出最深層的原因,并且保證列出的這些原因之間并不會相互影響。然后再試著來解決它。一般而言,如果客戶方是真正愿意實現這個軟件的話,事情并不是不可解決的。
另一種是產品化的軟件。我們可以把這種軟件的客戶分為三類:市場人員、領域專家、最終用戶。市場人員往往對軟件有最初的認識,但是這種認識往往不夠深入。所以,在開發產品化的軟件時,一定要配備專門的市場人員,他們對客戶的需求最了解,是需求的第一手來源。既然你的老板想要開發這個軟件,說明對軟件的未來市場有期待,市場人員加入的要求應該是可以得到滿足的。其次是領域專家,現在很多的軟件公司都配備有領域專家,他們的作用可不小,和市場人員相比,他們也同樣熟悉需求,因為他們自己就是資深的用戶,并且他們還熟悉理論,能夠為軟件開發出大力氣。最后是最終用戶,前面的兩類人的參與還不夠,如果最終用戶不認可軟件,那還是沒有用。所以,要求市場人員找尋可能的目標客戶,試用軟件,提出意見,是非常重要的。我們常說的Beta測試也就是這樣做的。
9、結語
最早這片文章的想法是來自于一個信貸系統(以文章的觀點來看,這個系統是一個失敗的案例)。除此之外,還加上了一些以前的項目的經驗,以及朋友的一些經驗。最后綜合成了這一篇文章。 這個系列的文章的寫作時間的跨度很長。在這個期間,我的思想也經歷一個很大的轉變,所以在寫作中也出現過對已經完稿的部分大肆刪修的情況。這篇文章雖名為『需求的實踐』,但所提到的各種想法、方法,都有理論的依據。當然也是參考了很多的資料。而我個人的能力又極為有限,所以有些時候是心有余而力不足。在這樣的情形下,文章難免會出現很多的錯誤。還希望能得到讀者們的諒解和指正。
在寫作的過程中,也有很多的熱心人寫來信件,其中好些還成為了好朋友。曾經想把里面的問題整理出來,但是由于疏忽,其中的一部分已經找不到了。希望還能有機會做這件事情。 參考資料:
Karl Wieger:《Software Requirements》
Scott W. Ambler: AgileModeling: http://www.agilemodeling.com
Scott W. Ambler: The Object Primer 2nd Edition
Jacobson, I., Booch, G., and Rumbaugh, J. (1999). The Unified Software Development Process
GOF:《Design Patterns: Elements of Reusable Object Oriented Software》
Eric Gamma, Kent Beck: Junit: http://www.junit.org
Kent Beck,Martin Fowler:《Planning Extreme Programming》
文章來源于領測軟件測試網 http://www.kjueaiud.com/