一、用例基礎
1.1用例簡史
用例技術大體上經歷了萌芽、成熟和發展3個階段[12],最早可追溯到上世紀60年代末UML(統一建模語言)、RUP(Rational統一過程)之父Ivar Jacobson(伊瓦·亞克申)博士在著名的瑞典愛立信公司領導程控電話交換機開發時採用的traffic case(話務案例),1986年前後亞克申博士在OOPSLA大會上發表的論文[4]標誌著用例的正式誕生。1992年,亞克申博士在其名著《物件導向軟體工程:用例驅動方法》[3]中正式推出了當時已相當完善的用例方法,用例驅動成為了Objectory過程(RUP前身之一)的核心內容,從此用例在國外軟體工程界得以迅速普及,並於90年代中後期被RUP和UML吸收為核心要素,亞克申博士在《統一軟體開發過程之路》[4]和《統一軟體開發過程》[5]中對此作了精彩的闡述,這些書因為成為了解其用例思想的重要著作。如今,作為必不可少的關鍵內容,用例技術總是被所有的當代需求工程名著所引用,而“用例”本身也幾乎成為功能需求的代名詞。(注:考慮到歷史上的淵源關係,為了方便起見,以下我們用術語“亞克申方法”或“亞克申用例”來統稱RUP、UML及其支持者所採用的用例方法,儘管它們彼此之間可能存在細微的差別,而且也不一定全部是由亞克申博士本人所提出或贊成的。)
用例另一支主流派別代表人物Alistair Cockburn(阿里斯代·寇本)上世紀90代初從亞克申那裡學習了用例,隨後通過十年認真廣泛的實踐對其進行了繼承和發展。寇本於1995至1997年間提出了著名的“基於目標的用例”方法[2],他的方法和思想集中體現在《Writing Effective Use Cases》(以下簡稱為WEUC)[1]中,以結構化/半結構化文字用例為中心是寇本方法的一大特色,該書可以說是迄今為止最為詳細的一本用例教材,對於指導實踐者如何寫好文字用例具有很高的價值。
1.2用例定義
下面,先讓我們從什麼是用例開始討論。亞克申定義[7]強呼叫例是系統執行的一個動作序列(注:這其中也包括與使用者的互動),這些動作必須對某個特定的使用者(Actor)產生可觀測的、有價值的結果。(注:Actor實質上是使用者所扮演的一種角色)
那麼到底什麼結果叫“可觀測、有價值”呢?雖然兩種用例本質上是一致的,但亞克申定義對此沒有明說,而寇本定義[1]則更加完善和明確。它首先強呼叫例是各種系統受益人(Stakeholder,又譯“干係人”)之間的一種行為契約(注:行為包括物件的活動、動作和物件之間的互動等),建立契約的目的是為了達成某種目標,因此每一個用例及其名稱實際上都應代表一個使用者目標,這個目標是否得到真正滿足正是判斷我們抽取的某個用例是否“有價值”的關鍵。寇本還點出了要通過用例的具體執行來展現Actor的目標是如何實現或失敗的,而一個用例其實就是多個在不同條件下執行並可能導致許多不同後續狀態的情節(scenario,又譯“場景”)的疊加,這就是用例結果的“可觀測”。
因此綜合起來,我們只要抓住這樣幾個關鍵詞:目標、行為契約、行為(事件)序列(動作和互動)、情節、可觀測、有價值,就可以比較準確地描述出用例的本質特徵。
1.3用例的重要性
為什麼用例如此重要?一言以蔽之,這是因為用例是一種普遍存在的客觀現實,而實踐證明,用例技術是迄今為止最為深刻、準確和有效的系統功能需求描述方法。
功能需求是指系統輸入到輸出的對映以及它們的不同組合[9],任何功能必然要通過外部環境與系統之間的互動才能完成,這不正是用例所要反映的內容嗎?因此,我們可以在內容和形式上把用例和系統的功能需求等同起來,並且得出推論:只要是軟體,必然都存在用例(雖然有時候不一定非要用某種具體的用例格式來描述),其中即包含資料流,也包含控制流,既包含訊息傳送和資料交換(互動),也包括活動/動作的執行以及狀態的變遷。這些就是用例的本質(現象背後那個真實的、抽象的“胚”),而各種格式文字、UML圖形(我們至少可以用4種UML動態圖來描述用例)不過是用例的外部表現形式。所以,與其說亞克申博士發明了用例,還不如說亞克申博士早在20年前就發現了用例這種客觀現實,並最終發明了用例表示和用例驅動軟體過程的方法。
那麼,什麼情況下不太適合採用用例方法?主要有兩種情況:(1)使用者很少或沒有,介面也很少,如科學計算/模擬軟體、殺病毒軟體、編譯程式、記憶體管理程式等[9];(2)功能需求非常簡單,非功能需求和約束占主導地位。顯然,如今絕大部分的應用軟體、系統軟體,尤其像電信、銀行、保險、稅務、製造業、企業資訊化等領域的複雜系統,都是符合用例適用條件的,這從一個側面反映出用例技術的廣泛適用性。請注意,即使在上面兩種情況下也並不是說這些軟體的用例就不存在了,而只是表明它們的功能需求很簡明或不太重要,除用例之外可能還有更加適用的方法。
正確有效的軟體需求必須是可測試、可驗證的。過去我們描述功能需求可能採用了很多種方法,除嚴格的形式化方法外,普遍的缺點就是粒度太粗、精度不夠,大多停留在受益人要求(request)和特性(feature)這一層[9]。比方說,針對某個“列印報表”功能,通常僅用一段話來描述它的靜態輸入和輸出是不夠的,還應該描述出使用者列印報表的具體操作流程,它有哪些特殊條件和選項設定,以及它與其他需求的依賴關係等等。很多團隊在需求尚未細化到用例這一層次時就開始匆匆編碼了,結果往往導致大量需求風險乃至架構風險被隱藏到構造、移交階段才發現,這必然造成頻繁的返工和嚴重的資源浪費。及時準確地抓住需求契約——用例這一關鍵,可以幫助我們在不失實用性、靈活性的情況下,有效地避免專案後期大量非正常的需求變化,為進度愈來愈緊的專案贏得寶貴的時間,提高專案的成功率。
1.4相關譯法
藉此機會,順便談談對use case有關術語翻譯的看法。
筆者認為“用例”是目前較好的譯法,這個詞可能來源於大家熟知的“測試用例”。有人認為把use case翻譯成“用例”是錯誤的[11],理由是:“‘例’是被列舉出來以說明某種情況的個別事物,use case是對一項系統功能使用情況的普遍適應的描述,而不是對個別actor或者在個別條件下使用這項功能才適應,它也不是通過舉例的方式來描述的”,所以不能叫作“用例”。此種說法不盡全面,而且有些牽強(先不管它正確與否),其實use case到底是個別的,還是群體的(普遍適應),取決於我們的視點。雖然對於單個的scenario來說,use case是多個情節的疊加,是一個整體的複合概念,但是我們知道,一個系統的功能必定是可數的、有限的,而每一個功能都可以表示為一個use case,所以在觀察系統提供的所有功能需求的集合這個層面上,use case又是一個一個可數的個體(“橢圓”),每一個都代表了不同的使用者目標,適用於個別的actor和個別特定的前置條件。同一個事物既是個體的又是整體的,這種現象並不足怪,例如在UML物件-類-類元關係中,通常物件是類的例項,而類又是類元的例項,對類元來說,類、介面、子系統、use case等等就是一個個個體的概念,類既是其物件例項的集合又是其類元集合的個別元素。可見,把use case的“case”譯成“例”並沒有錯。
有的地方把use case翻譯成“用況”,即“使用的情況”之意,意思的確不錯(use case的另一種說法是“使用的方式”)!可我總感覺這個詞比較突兀、拗口,類似的還有“用案”,把scenario叫作“案況”,大概這些詞讀起來不太符合大家的習慣(類似地,既然可以叫“用況”,為什麼不能叫“用情”呢?),所以現在“用例”的叫法還是越來越多了。
其實“用例”這個譯法還有個附帶的好處,通過它我們很容易把原本就存在緊密聯絡的use case和test case(test case來自於對scenario的分析,而scenario是用例的一次執行)從中文名稱上也方便地統一起來。不過,這裡我們需要做一個小小的改進。中文的“測試用例”到底是指test case(帶定語的名詞片語)呢,還是指對用例進行測試(testing the use cases,動賓片語)呢?顯然這兩者不易分辨,而且若“用例”和“測試用例”兩個詞同時出現在一囉個句子或一段話中,常常會讓人感覺嗦和便扭。為了消除歧義,乾脆以後把test case都叫做“測例”,這樣不但比以前的叫法更加簡潔明瞭,而且無論字面上還是語義上都很貼切。當然,用例和測例是不同層面的“例”。
現在市面上Actor也有多種譯法,常見的包括“參與者、執行者、主角”等等。“參與者、執行者”的問題主要是不準確。首先,“參與者” 通常讓大家馬上想到的詞是participant,而且請注意,一個用例的真正參與者決不是隻有外部的Actor,它們必然還包括系統本身及其內部的各種元素。“執行者”的問題與此類似:一個用例的真正執行者應該是系統本身!因此嚴格地講這樣譯是錯誤的,興許叫作“外部參與者”、“外部執行者”才更為恰當。“主角”的譯法同樣存在著矛盾。如果把Actor叫作“主角”,那麼Primary Actor就應該叫作“主主角”了。看來Actor的譯法中是不能含有“主”的,那麼就剩下“角”了,而UML已經有了一個專門術語role(角色),我們又不能把Actor直接叫作“角色”。
目前看來,把Actor意譯成“使用者”是比較妥當的。在大多數情況下Actor的的確確就是使用者(確切地說是系統使用者所扮演的一種角色),所以我們可以用“使用者”這個詞從字面上與“使用者”(user)進行區分,但同時又保持兩者語義上的聯絡。我們還可以把為系統服務的Supporting/Secondary Actor(見下文)叫做“被使用者”(為了簡化可以省略“被”字)或“輔使用者”。除了指系統的使用者之外,“使用者”還有另一層含義,即Actor是use case的使用者(或被使用者),這種關係在UML用例圖上應該視覺化地表示為它們之間的連線(關聯)。這樣解釋不但說的通,而且更便於不熟悉軟體技術的業務人員理解。
當然,我們也不排除將來會找到“use case”、“actor”等術語更好的譯法。
二、統一用例方法
2.1 理由
為什麼要提出統一用例方法(UUCM),有這個必要嗎?
我們發現,雖然寇本用例起源於亞克申用例,但兩種用例方法各自經過十多年的發展,彼此之間逐漸出現了一些顯著的差異,而且由於商業或其他方面的原因,目前我們尚未看到兩者將要融合的明顯趨勢。兩種方法各有優缺點,寇本強調基於目標的文字格式,亞克申用例則更突出UML的作用,如下文所示,兩者的差別至少有10處之多。對於實踐者來說,如何處理好這些明顯差異,避免使用上的誤區,再者能否巧妙地做出取捨,實現熊掌與魚兼得,這些都是非常現實的在實踐中必須面對的問題。
筆者認為採用統一的用例方法,把亞克申和寇本用例兩者結合起來,甚至融合其他的用例方法(據說已知的各種用例表示方法多達18種以上[2][6]),在理論和實踐上均是可行和必要的,這可能是我們目前可以採取的最佳策略。但是,UUCM本身並不是一種全新的用例方法,而只是一種特定的處理方案。它是在對亞克申、寇本用例方法繼承的基礎上,試圖消除這兩種經典方法的不一致和矛盾,並探索可能的優化改進和後續發展,所以UUCM起到的作用與亞克申、寇本用例方法相比是次要的和微小的。
以下我們對兩種方法的異同進行比較分析,並同時給出UUCM的建議。
2.2層次
明確提出用例的層次和範圍劃分,是寇本“基於目標的用例方法”的精華所在[2]。顯然,每個用例存在的意義是為了完成一定的使用者目標。寇本把用例劃分為3個目標層次:概要層、使用者目標層和子功能層,並通過引入巧妙的Why/How技術幫助分析者找到合適的目標層次,從而可以有效地把握用例的粒度(真正的用例最終應落實到使用者目標層),防止用例情節的爆炸。
亞克申方法及其相關文獻在介紹如何有效地控制用例的粒度方面,大體上只有這樣兩條基本的判定規則:(1)通過判斷內容是否有價值可以防止用例過小(例如,“輸入發貨地址”的粒度就太小,這不是一個真正的用例,相當於寇本的子功能層用例);(2)通過判斷具體內容是否可觀測,可以防止用例過大(例如,“使用者管理”就比較空洞,這不是一個有效的用例名稱,相當於寇本的概要用例)。但如前所述,究竟什麼叫“有價值”,什麼叫“可觀測”,如何把握好這個度,亞克申方法對此語焉不詳,給RUP和UML的使用者帶來了不少困惑,而寇本方法恰好出色地回答了這個問題。
UUCM:
通過寇本的分析,我們發現用例有縱向(層次)和橫向(範圍)之分,這些是非常有價值的概念,它們是對亞克申基礎用例方法的豐富和完善,兩者是不衝突的,完全可以在RUP相關的實踐中加以運用。
值得注意的是,我們在實踐中應該尤其關注使用者目標層用例。寇本引入概要層用例的主要目的是為了包含一個或多個使用者目標層用例,為系統提供全域性功能檢視,提出子功能層用例則是為了表達使用者目標層用例的具體實現步驟。雖然有時為了簡便,我們也把後兩者叫做“用例”,但其實它們都不是真正的用例。
可能是為了防止濫用、誤用用例的分解(這很容易引誘人倒退到結構化的功能分解),亞克申方法沒有提及甚至有意迴避用例的層次問題。亞克申博士在最近的一篇文章中[12]引入了用例片段的概念,這意味著我們應該把寇本方法中的子功能層用例叫做用例片段以避免名稱上的混淆,看來這是今後一種比較好的處理辦法。
2.3範圍
關於用例範圍的處理,兩種方法基本上是一致的,都可分為業務用例、系統用例兩種,區別在於寇本強調在格式上用圖示或文字顯式地表示出每個用例的範圍,並且在用例層次劃分的基礎上提出了最外層(或最外圍)用例的概念[13],這在亞克申方法中是沒有的。
UUCM:
用例的本質就是物件之間的一種協作和互動,這些內容是屬於需求還是屬於設計,關鍵就看你劃定的討論邊界。我們不僅可以用它來描述發生在系統邊界上的功能需求(用例的常規定義),而且還可以同樣的方式描述系統內部發生在子系統、構件、介面或類/物件邊界上的黑盒互動,不過後者往往涉及到系統設計範疇,屬於用例的特殊用法,在做專案的需求分析時一般不予考慮。
正如寇本所提到的,同樣一個用例名稱,比如“取款”,可能實質上代表著兩個截然不同的用例:一個是ATM取款(系統用例),另一個是銀行櫃檯取款(業務用例)。所以在一個用例中明確標記出它的範圍,是很有必要的。我們既可以用特定的圖示,也可以用專門的格式欄位來表明用例的範圍,還可以對用例的名稱加以修飾以便區分,比如“櫃檯取款”,“ATM取款”。
當前的討論邊界(SuD,the System under Discussion)一般比較容易確定,那麼如何從用例的範圍上判斷一個用例是系統用例,還是業務用例呢?(這是一個出現率很高的FAQ)。有個小竅門:如果某個SuD或者用例的範圍包含了人以及由人組成的團隊、部門、組織的活動,那麼針對這個SuD寫出的用例必然是業務用例;如果該SuD僅僅是一些軟體、硬體、機電裝置或由它們組成的系統,並不涉及到人的業務活動,那麼根據這個SuD寫出來的肯定是系統用例。
由於系統(注意,這裡的“系統”是指由軟、硬體組成的IT系統)往往是業務的一部分,我們還可以得出推論:對於某個系統用例suc,通常總是可以找到一個業務用例buc,buc的範圍要大於或等於suc的範圍;當這兩個用例的範圍相等時,buc就是suc,或者buc的層次要高於suc的層次。
2.4 包含與擴充套件
由於各方面複雜的原因,如何更好地表示用例之間的關係一直是個爭議不斷的問題,而且恐怕在將來較長的一段時間內對此還難有定論。我們發現,寇本與亞克申方法在用例的擴充套件、包含、繼承等關係的使用細節上存在著一些明顯差異,其中很大一部分原因可能是由於現有文獻對用例關係的定義不夠精準和完善,導致大家在應用時各取所需、各自解釋造成的。如果我們在實踐中對這一情況不加以留意,就可能給需求的溝通和交流帶來障礙。
2.4.1一頭霧水
同樣一對用例之間的關係,在寇本用例模型中是包含關係,在亞克申模型中卻可能被表示成擴充套件關係。例如:
圖1、寇本畫法[1]
圖2、《UML參考手冊》畫法[10]
UUCM:
為什麼會有如此差別?為了說明問題,還是讓我們先看看這幾個用例的文字描述。《UML參考手冊》寫道:
基用例ATM會話:
顯示當天廣告 include(識別顧客) include(驗證賬戶) -------------------------- <可能的事務>(擴充套件點1) 列印憑條標題 -------------------------- <憑條細節>(擴充套件點2) 登出 擴充套件用例取款: 收到取款請求 指定取款數量 -------------------------- <產生的請求>(擴充套件點3) 付款
看到這裡,我們就不難解釋為什麼圖2把ATM會話與取款之間的關係畫成擴充套件了(注:這本身可能不符合亞克申擴充套件用例的原則[4])。由於在身份驗證通過後,顧客具體執行什麼操作是不定的,可以是取款、存款、轉賬、查詢等事務中的任何一個,將來甚至還有可能新增(擴充套件)新的功能,而ATM列印的憑條根據使用者操作的不同,內容也將有所不同。這些內容的發生都需要具備一定的條件,屬於可能的情況,這一點似乎很符合擴充套件用例的定義。考慮到這些因素,作者於是採用了圖2的策略,把可能的操作和列印內容都從基用例中抽走。
然而不要忘了,除了擴充套件用例只有在特定條件下才能被觸發之外,把一段內容提取為擴充套件用例還要求即使在沒有該擴充套件用例插入的情況下,基用例本身的執行也不應受到任何影響。因此,如果我們把上段文字中的兩個擴充套件點拿掉(只看左邊的文字)並參照寇本目標用例的標準,可以發現該基用例完全不是一個目標得以完整執行的用例。上述寫法是有問題的,它不完整,而且效率不高,似乎模仿了一些程式語言的寫法和思路,在實踐中不值得推廣。
下面再讓我們看看寇本版的“使用ATM”[1]:
1. 顧客插卡,輸入PIN。
2. ATM驗證顧客賬戶和PIN。
3. 顧客執行下列任一事務:
取款 存款 轉賬 查詢
顧客執行以上事務直到選擇退出。
4. ATM退卡。
在這裡,取款、存款等事務操作明確地出現在用例的基本流中,顯然它們都是被“使用ATM”所包含的用例。注意,在寇本用例中每個動作步驟不一定都是順序執行的,可以有迴圈,有選擇,甚至可以是任意順序,例如上面的步驟3。在WEUC中寇本還指出,實際上取款、存款、轉賬等操作都是顧客執行一次交易事務的特例和具體化,所以還可以進一步畫成類似圖3的形式。。我們可以看到圖1其實是圖3的簡化。
圖 3、更為準確的畫法
應該如何判定一個用例關係是包含關係還是擴充套件關係?有些情況還是比較明確的,例如對於“驗證身份”和“吞卡”,大家可能都毫無異議,一致認為它們分別是“使用ATM”的包含用例和擴充套件用例。但是,一旦出現上例的情況時,就較難處理了。不過,我們通常可以據此判定:如果觸發條件中含有基用例負責的事物,即基用例知道附加用例何時、何處、為什麼發生,那麼基用例應該包含(呼叫或引用)它;如果觸發條件中含有附加用例負責的事物,即附加用例知道它應該何時、何處、為什麼發生,那麼應該讓附加用例擴充套件基用例[1]。這兩條規則還是很管用的。此外,根據筆者經驗,還可以參考這樣一條簡單法則:凡是在用例基本流中出現的附加用例都應作為包含用例,而在擴充套件流中出現的附加用例必然是擴充套件用例。顯然,圖3符合以上規則。
問題似乎得以解決了。然而,在UML 2.0上層結構規範草中,我們卻看到了類似圖4的方案:
圖4、另一種近似的畫法
有人要問了,為什麼針對同一段用例文字描述,卻存在兩種矛盾的UML畫法,同一個用例“取款”在圖3中是包含,在圖4中卻是繼承,到底哪個是對的?其實,圖4與圖3這兩種用例模型在整體上所描述的內容是完全一致的,問題就出在用例名稱上。分析、比較用例之間的關係,請務必關注用例的內容——動作步驟。我們可以發現,圖4中的“取款”用例與圖3中的“取款”用例所包含的實質內容是不一樣的,一大,一小。所以,假使我們把它們的名稱分別改為“取款交易”和“取款(事務)操作” ,並約定前者“大於”後者,就可以在一定程度上消除二義性,這樣兩個圖就近似等價了。不管如何,圖3、圖4都一致地沒有把“取款”、“存款”、“轉賬”等用例作為基用例的擴充套件。筆者認為,經過改進,這兩種畫法目前都是可行的,而圖3可能更好一些。
關於用例包含、擴充套件和繼承關係方面的更深層探討,值得寫一篇專述文章,在這裡不可能展開。在目前眾說紛紜的情況下,建議大家像寇本建議的那樣,如果實在搞不清兩個用例到底是什麼關係,不如干脆都先定為包含關係,這樣做並不影響後續的系統分析設計和使用,因為用例本身的內容寫得如何才是問題的實質、真正的關鍵。總之,實踐者不要指望只通過看幾個用例的名字就能準確地判斷出它們之間的關係。可靠的依據來自於用例內部,不必在弄清用例的關係上浪費太多時間,這個問題可以留待學者和研究人員來解決。
2.4.2 sub use case之爭
寇本在WEUC中把包含用例稱為sub use case,即subordinate use case之意,但其實subordinate use case(筆者將其譯為“分用例”)在亞克申方法中有專門的用途(在亞克申博士早就提出的對大規模系統建模的SystemOf InterconnectedSystems模式中,有超系統/超用例和分系統/分用例之分[4])。而寇本採用的sub use case叫法很容易被直譯成中文“子用例”,從而造成新的誤解,因為我們知道“父子”一說在OO方法中通常是用來形容物件類之間的繼承關係的,子類是父類的派生類,顯然這與包含用例的真實語義不符。
在UML[10]中,把包含用例、擴充套件用例統稱為附加(additional)用例,被包含、被擴充套件的用例叫做基用例,在用例的繼承關係中則採用父用例、子用例的說法,這樣做是妥當的。
UUCM:
建議在實踐中儘量迴避寇本sub use case的說法,可以用“包含用例”或“附加用例”來代稱,同時明確約定在中文中凡是提到“子用例”的地方,就是指用例的繼承或一般化。
2.5 Actor
寇本用例的Actor型別有7種之多,包括[1]: Actor(something with behavior)、 External actor(an actor outside SuD)、 Stakeholder(an external actor entitled to have its interests protected by the system)、 Primary actor(a stakeholder who requests that the system deliver a goal)、 Supporting/secondary actor(a system against which the SuD has a goal)、 Offstage/tertiary actor(a stakeholder who is not the PA)、 Internal actor(either the SuD, a subsystem or an active component of the SuD)。 RUP關於Actor的定義[7]是: Someone or something, outside the system or business that interacts with the system or business。UML的定義是: An actor specifies a role played by a user or any other system that interacts with the subject。
UUCM:
亞克申用例與寇本用例對於Actor的定義存在著明顯區別。亞克申及UML的Actor是系統之外的人或物,而寇本Actor的含義(可能來自早期的亞克申版本)比較籠統,其範圍要大得多,有內外Actor之分。既然我們確定Actor的主要目的之一是為了劃定系統(或業務)的邊界,那麼應該始終把Actor當作系統外部的事物,這樣才比較妥當,內部Actor是不必要的概念。而且,在實際應用中Actor即重要也不重要[1],識別Actor的主要目的是為了幫助提取用例,通常不需要對各種Actor型別加以如此細緻的區分。
另外,寇本關於stakeholder的定義與通常的理解也有所差別。寇本認為stakeholder是一種外部Actor(注:這本身與寇本自己對用例的定義明視訊記憶體在矛盾[1]),這不對。按常理,所有利益相關人包括內部Actor、外部Actor都應該屬於stakeholder之列,尤其當我們討論的是業務組織的時候。
2.6後置條件
與亞克申用例相比,寇本對用例的後置條件進行了細分,提出了最小保證、成功保證等概念,這樣做是有意義的。最小保證描述了系統不管在任何情況下,尤其當用例失敗、目標未達成時,都應滿足的起碼條件和應採取的措施。
UUCM:
建議採納寇本方法的最小保證和成功保證劃分。此外,在前置、後置條件(最小保證和成功保證)中除了說明必須滿足的條件外,還可以分別說明系統在用例開始前和結束後的狀態,包括各種成功和失敗狀態以及對失敗狀態的處理。
2.7動作步驟
寇本用例步驟採用獨特的編號方式,基本流採用1,2,3…順序編號,擴充套件流的條件和擴充套件步驟採用數字、字母間隔的方式,如1a、1a1、5c、5c3b1等等,而且還可以使用巨集代符*,可以指定任意數目步驟的條件,如1-9a、2,7-9c等等,使用起來非常方便。RUP的基本流、擴充套件流步驟完全採用自然分節的順序編號,如1.1、2.3.4.1等等,不便於閱讀者找到用例具體的引用位置,在指定擴充套件位置時顯得較為麻煩。 另一方面,RUP用例的每個步驟都可以附上一個名稱,這叫做“命名步驟”。
如果一個步驟內容較多,用一個短語標記來概括說明該步驟執行的大致內容,確實比較方便,而且將來需要畫用例的活動圖時也可以作為快速參考。
UUCM:
建議採納寇本的步驟編號方式和RUP的命名步驟方法。
2.8文字與UML
亞克申用例方法與UML、RUP三者之間有著天然的緊密聯絡。用例驅動、視覺化建模是RUP的兩大特徵,若用例和UML缺席,RUP也就稱不上RUP了。在亞克申方法中,除了可以用RUP的格式文字描述用例外,還推薦適當地選擇利用UML用例圖、序列圖、協作圖、活動圖和狀態圖5種圖示從各個角度來描述用例,可謂手段充足、武器齊備。
寇本代表作WEUC的主基調是用結構化/半結構化的文字描述用例。雖然他也提到了UML,但討論主要集中在如何正確對待UML的用例圖和相關CASE工具等問題上,對UML用於描述動態行為的其他4種圖的作用和意義強調得不夠充分,其實這些圖的作用遠比用例圖要重要得多,也是UML強大描述能力之體現。
UUCM:
如前所述,文字用例本質上是對物件互動過程的執行步驟的羅列。用例本身即每個“橢圓”內部的東西才是最為關鍵和重要的,用例之間的關係相對來說要次要些,在這一點上,可以說亞克申方法和寇本方法的看法是一致的[1][4]。實踐中,我們發現很多時候,先寫文字系統用例,後照著已有的文字說明畫UML圖比先畫圖或完全依賴於圖形來描述系統用例要容易得多。可見對於軟體需求分析,我們應該首先把更多的精力放在寫好文字用例上(這正是寇本方法的強項)。
但是,寇本認為“Sequence diagrams are not a good form for expression use cases”[1],這種說法有失準確和全面。縱觀全書,寇本主要是從工具使用的角度來分析的,他在書中對當時那些不那麼先進的CASE工具頗有微詞,認為它們不如文字寫作更加便捷和有效。然而,事實上這只是問題的一個方面,UML工具的缺陷並不能簡單地等同於UML語言本身的缺陷。正確地使用UML及其工具不僅僅是為了獲得形象直觀、交叉引用、超連結、名稱自動變更等一目瞭然的好處,更重要的一個原因是,通過合適的UML圖形,比如SSD(系統序列圖),來精確地定義和描述系統事件與作為其響應的系統操作(也就是系統的輸入和輸出)[8]之間的契約,這正是後續系統分析和設計的起點。序列圖在用例分析中其實起到相當關鍵的作用,在實踐中用它來刻畫每一個重要的系統用例也是非常普遍的做法。
而且,在分析複雜的業務流程/業務用例時,人們好像更習慣於首先畫活動圖(可能與人類自身的思維習慣有關),反而不太願意採用繁瑣的文字說明。對於複雜和關鍵的用例,除了一些必要的文字描述之外,再輔之以UML活動圖、序列圖或狀態圖進行視覺化,是行之有效的好做法,有助於澄清問題本質、迅速抓住要領。對於複雜的用例模型,通過用例圖描述用例之間的關係,提供全域性瀏覽檢視,也是非常必要的。
用例的UML圖形與文字描述之間不是誰取代誰的關係,而是相輔相成、優勢互補,應該因地制宜地加以運用。不僅如此,同時擁有用例的結構/半結構化文
本和UML圖形,往往還有助於彼此之間相互比對、確認,能顯著提高用例描述和分析的正確性。根據本人經驗,把兩者結合起來運用效果才是最好的,沒有必要過份地強調某一方面。
2.9黑盒白盒
亞克申博士發明的用例實現(UCR,Use Case Realization)[5]在RUP、UML中是一個非常重要的概念,它描述了內部物件如何相互協作共同實現一個用例,理論上每一個用例都應該至少有一個UCR與其對應,因而UCR在亞克申方法中起到了聯接問題域和解決域、貫穿整個軟體分析設計過程的關鍵作用。在寇本方法中,不存在UCR這個術語,只有黑盒用例(需求)、白盒用例之分(需求的實現)。
UUCM:
首先,既然談及基於用例表示的功能需求,那麼它就應該是黑盒的、透明的。如果我們看到了系統內部的情況(白盒、不透明),那麼這其實已經是需求的一種實現了。所以,我們應該在需求分析時儘量避免“白盒用例”這種矛盾的說法。嚴格地區分UC和UCR,有助於專案團隊在實踐中消除需求和實現不分的情況。這一點過去在被拉來寫需求的程式設計師當中比較普遍,受習慣性思維的影響,他們往往寫到最後就變成寫軟體設計方案了,這是很糟糕的。
2.10格式模板
寇本在WEUC中一共列出了5種主要的用例格式模板:完整型、簡易型、單列表式、雙列表式和RUP樣式。在此,我們推薦以完整型(寇本本人最喜歡的)為基礎,結合了單列表式和RUP樣式特點的UUCM模板:
用例名稱: 層次: + | ! | - 範圍: 簡述/背景: 主使用者及利益: 其他受益人及利益: 受益人1: 受益人2: 最小保證: 狀態1: 狀態2: 後置 條件 成功保證: 前置條件: 條件1: 條件2: 狀態1: 狀態2: 觸發事件: 基本流: 1. 步驟1 2. <可選名稱>.步驟2 … n. 步驟n <結束> 擴充套件流: 1a. 條件1: 1a1. 步驟1 1a2. 步驟2 擴充套件點: 名稱1:位置1 名稱2:位置2 技術和資料變化: 1a. 2a. 非功能需求: 業務規則: 備註: 其他必要欄位 …… 表1、UUCM模板v1.0
雙列表式較多地被用來描述使用者介面需求,有些人偏愛它,但我們發現雙列表不夠簡潔,比較佔空間,而且很多情況並不適用,比如參與者多於兩個的情況。
三、結語
寇本用例方法以基於目標的結構化/半結構化文字描述見長,亞克申用例方法更重視UML視覺化建模和用例驅動過程。兩者儘管同宗同源[1],卻在一些使用細節上存在著明顯差異,而且各自還在沿著既有軌道繼續向前發展。 本文提出的統一用例方法並不是一種全新的方法,UUCM僅僅是個符號或代稱(也許可以有其他更好的名稱),它實質上代表了一種解決方案和思路,目的是吸收亞克申和寇本用例方法的長處,消除兩者的不一致,從而幫助實踐者儘可能規避使用上的誤區,發揮用例和UML方法“1+1〉2”的聯合優勢。這既是實踐的選擇,也是現實的需要。
話說天下IT之勢,合久必分,分久必合。UUCM不是句號,而是一個新的起點。出於商業、私人或其他方面的原因,國內外許多技術流派分呈的局面會長久持續下去,這本身是一件好事。不過,對於我們實踐者來說,選擇實用的工程技術時不應有門派分割的障礙。對於特定的場合、特定的專案,企業人往往只有一個明智的選擇,那就是:用最小的成本創造最大的客戶價值。所以,對於實用型技術我們完全可以採取拿來主義的態度,防止guru-locked-in,適用的即是最好的!
|