本文的目標是:第一,重點描述實時系統規格的確定和用例之間的關系;第二,描述我們如何開發用例模型以及應用用例給我們帶來了哪些益處。
要說明的第一件事情是為什么我們需要類似這樣的一篇文章,然后我們再說明用用例來描述實時系統有哪些特殊之處。
在敘述為什么需要本文之后,我將描述一個具體項目和它的用例模型。我將重點描述用例模型的一些有趣的和有意義的特性,然后看看它們是如何有益于項目的。最后,我將討論一些經驗學習,并給出一些建議。
CCE2>為什么我們需要這篇文章?
有一種看法認為用例只對你描述高度交互的系統有用,這些系統以IT系統為代表,如銀行系統。例如,在銀行中你可能需要處理一個抵押應用,它會有大量的用戶交互。對于實時系統來說,并不存在那么多的用戶交互。但是,如果實時系統具有有意義的外部可視的行為,用用例描述仍然對定義它們的規格是有用的,即使在一些用例中用戶只是選擇一些設置以及告訴系統完成一些功能。
在為客戶工作了這么多年來,我發現用例被廣泛地誤解。盡管有很多與之相關的書籍、文章和培訓課程??赡苓@些書籍、文章和培訓課程都只關注于問題,因此它們提供大量的不同的方法。在這些著作中經常提到的一個例子是自動柜員機(ATM)。類似這樣的例子對于說明一些問題是有用的,但在處理很大而且很復雜的實際系統時卻通常沒有明顯的幫助。在實時系統中你將怎樣處理出現的問題?有一些實際的例子可以對你有所幫助,本文恰恰可以給你提供這樣一個實際的例子。
什么是實時系統的特點?
實時系統就是時間是最關鍵因素的系統。如果一個系統不理會它的時間需求,將可能導致生命危險,例如造成飛機失事。簡單來說,對于這樣的系統,對于時間需求處理的失敗將可能導致產品的損害和上百萬美元的損失。
實時系統也有最小限度的用戶交互,對于這類系統怎么樣定義它的用例是一件值得考慮的事情。實時系統通常都是高度算法化的,用例可能并不是最好的描述算法的文檔方法。典型地,一個用例將引用在其它地方描述的算法。
如果你的系統具有有效的外部可視行為,那么用例能夠極大地幫助你文檔化你的系統需求。下面我描述的系統就有大量外部可視行為。在IT系統中應用用例的規則在這里仍然適用。
產品傳送系統(PT)項目
用戶是一個全球最大的鐵礦生產商,它在澳大利亞西北的Headland港擁有一套鐵礦傳送工廠。鐵礦從傳送帶網絡傳送到火車車廂,然后分類,稱重,保存在倉庫。最后鐵礦從倉庫中運出,再通過傳送帶運送到船上。
這個系統中每個東西都很大。有的傳送帶有7公里長,需要15分鐘才能啟動。運行傳送帶網絡需要一個復雜的控制系統。對控制系統的一個需求是減少運行系統需要的人數。另一個需求是降低對運行系統的人的培訓需求。圖1是工廠的航拍圖。
在左上角有一個船泊位。你可以看到有鐵路線從右邊連過去。卸貨場在接近于中間的垂直線附近。在這個線的頂端是粉碎機。你可以在北面和南面的院子里看到倉庫。傳送帶運行在卸貨場和粉碎機,以及粉碎機和倉庫之間。 你可以看到運輸機從倉庫裝上鐵礦,把它運到船上。運輸機的容量非常大。在這個系統中,傳送帶可以在一小時內傳送10000噸的鐵礦!
有一些能夠增加系統復雜度的需求非常值得關注??刂葡到y在避免溢出的情況下要達到最大的生產能力。出口容量在2004年從每年67M(百萬)噸增加到81M噸,到2011年將擴大到90M噸。
基本概念:作業(route)
一個作業(route)由一系列傳送帶、定位和反饋設備組成,這些設備被選擇和調配以便把鐵礦從源位置運送到目標位置。作業可以是單獨的,也可以共享設備以便允許把鐵礦分開運輸,從一個源位置運送到多個目標位置,或者組合運輸,從多個源位置運送到一個目標位置。這些作業由操作員創建、維護和刪除。一旦操作員啟動作業,系統就開始工作,按照正確的順序啟動每個工作,以及處理一些異常狀態例如有不合適的產品已經在傳送帶上。
為了達到生產力的需求,控制系統采用激進的啟動和錯誤處理策略。盡管已經存在的系統在一個時間點一個作業只能啟動一條傳送帶,當它達到最大速度后,再啟動下一條,依此類推。 新的控制系統在一個作業中將同時啟動所有的傳送帶--注意我們的傳送帶的長度不同,啟動時間和容量也不同。在出現問題時,新的系統試圖盡可能關閉最少數量的設備以避免溢出,因為啟動一個長的傳送帶需要15分鐘。無論什么可能情況,設備都將保持運行,直到鐵礦有可能溢出為止。系統需要同時運行作業,以便礦石能夠傳送到多個目標位置或者把礦石從多個源位置組合到一個位置。
設備失敗的處理是全自動的。當一個傳送帶一小時可以傳送超過10000噸礦石時,你可以想象出現問題時不能很快停下傳送帶的后果。這個結果并不是你可以用獨輪車能夠清理干凈的!你將不得不使用一些重型設備來清理那些溢出的礦石,而且需要花費很長的時間。甚至有更壞的結果,比如一個錯誤導致礦石已經倒進了船的甲板上。
PT系統的用例模型
本文的工作基于IBM(r) Rational Unified Process(r) (RUP(r))和一本名為“用例建?!钡臅?,這本書由Kurt Bittner和Ian Spence合著。用例是一個可供選擇的寫需求的方法。在過去,我們基于一個詞"shall"來書寫這些聲明。在幾年前我曾經在一個國防項目工作,它包括22卷需求文檔,沒有人能夠真正全部理解它們。確認所有的需求描述是正確的和一致的是一件非常困難的事情。用例可以幫助我們處理這類問題。用例把需求放在系統提供給用戶和有關人員的上下文中。 按照順序描述每個用例以消除上下文的冗余,這些冗余在用傳統的基于"shall"的需求描述方法中是必然包括的。
這里僅僅描述用例模型的一些特點,因為全部模型太大,也太復雜。用例的規范非常長,也非常細致。
識別角色(actor)
在整個操作開始前主要工作集中在識別角色是非常重要的,因為它可以確定系統的邊界,清楚地指示哪些是在系統范圍內,哪些在系統范圍外。我們不想開發那些我們沒有必要付錢的東西。在PT系統中,運輸機是一個我們需要交互的系統。這里我們只需要知道運輸機干什么工作,并不需要控制它如何工作,我們也不需要修改它。既然我們不控制運輸機,它就在我們的系統范圍之外,作為一個角色模型存在。我們有Ship-Hatch Loaders, Stackers, Sampling Stations 和Dust Control Systems - 所有這些外部系統都作為角色模型。圖2顯示部分這個系統的角色。
在圖2中,角色使用UML 包分組。在左邊是角色包。最重要的一個在左上角。CRO 就是Control Room Operator,中央控制室操作員。其它重要的還有在左下角的RSMT(Root System Maintenance Technician,根系統維護技術員)。
其它的包包括所有不同的設備角色。一些用例提到我們管理的通用設備,另一些將提到特定的不同類型的設備。
在圖的下方有一些與我們交互的外部設備。左邊的一個是PMAC,一個已經存在的系統用來處理我們的用戶界面。如果它僅僅是與我們的系統相關的用戶界面,那么我們不需要把它看作角色,因為實際上角色是CRO。但是它實際上是我們相關的角色,因為我們給它傳遞信息,并且從它那里收集信息。
電力負荷管理系統Power Load Management System (PLMS)是值得關注的。在Headland港,港口工廠有自己的電站。當你啟動7KM長的傳送帶,并在上面運行數千噸的礦石是,它需要大量的電力供應。因此,傳送帶的啟動實際上是錯開的,以便降低電站的負荷。只要你想啟動傳送帶,PT系統都將詢問電站并得到電站的許可。
確定用例
用例是一種簡單的可選擇的定義需求的方法。首先,讓我們再次回顧一下用例的定義:
用例定義一個由系統完成的操作序列,它給操作者和相關人員提供可觀察到的有價值的結果。
在識別IT系統的用例時,牢記“可觀察到的有價值的結果”是非常重要的,這一點在這里仍然適用。我們將看到系統提供給操作者和相關人員的值。在我們的例子中,中央控制室操作員是一個角色,但是整個公司實際上都可以看到系統把礦石從一個地方移動到另外的地方?!坝上到y完成的操作序列”聲明了在用例中系統怎么做的描述。這些每個都是我們系統的需求。最后,用例是一個完整的有意義的事件流。把“完整的有意義的事件流”和“可觀察到的有價值的結果”這兩個概念組合起來可以幫助避免識別出不完整的功能片斷并把它稱為用例。
用例和角色在用例圖中以圖形化的方式描述。圖3顯示了 PT系統的頂層用例圖。你很快就能看到 PT系統的用例分為4組:Operation, Administration, Configuration 和System Startup。
PT系統中用例相關的操作在圖4中顯示:
PT的主要用例是“傳送產品”。正如這個用例的名字那樣,你可以看到在這里系統提供給用戶和有關人員的價值是把產品從一個地方運送到另一個地方的能力。這個軟件也能夠用來運送其它物品,不僅僅是鐵礦。例如它能夠用來在制藥廠傳送藥片。傳送產品是一個很大的用例,但它抓住了最根本的因素,即我們的系統存在的原因,即給我們的操作者和相關人員提供的價值。
在圖4中我們看到與電源管理系統(PLMS)的交互,請求啟動設備,我們也看到了用例與我們控制的設備的交互。我們可以顯示每個設備角色,但那樣的話,圖就顯得太混亂了。
在圖4中,從CRO到傳送產品的箭頭,表示這個操作員發起或者啟動這個用例。用例到設備和PLMS操作者的箭頭表示這個用例或者系統與設備和PLMS交談。從船艙裝載系統(SHLS)的箭頭表示SHLS發起與系統的交互--特別地,SHLS可以請求鐵礦流暫時中斷以便裝載機移動到另一個艙室。
有關管理、配置和系統啟動的用例在圖5中描述。
在這里我們可以做的一件事情是在對系統的操作影響最小的情況下更新系統軟件。因此我們有"Perform Software Upgrade" 用例。我們也有"Start System" 用例 -這個用例經常被忘掉。系統有人身安全優先的規則,Start System 用例包括在系統啟動時進行的所有安全檢查的規格說明。你一定不想在服務人員在傳送帶上工作時偶然地啟動它!
Route System Maintenance Technologist (RSMT)是一個負責創建作業或者預定義作業的人,預定義的作業稍后由CRO使用。我們可以在系統中添加新的設備,定義新設備的種類以及定義系統傳送產品的特點。港口工廠處理來自不同礦山的不同類型的鐵礦,它們有不同的顆粒大小、不同的礦石成分等級。我們要非常小心的一件事情是避免把錯誤的礦石裝到船上去。
關于用例圖這里要警告一下:用例圖只是冰山的一角。直到你開始寫用例規格之前不要去重新分解、重組和調整用例模型。用例的規格大約95%來自用例模型。用例圖僅僅給你一個模型的總體、全面的概要描述。
正如我前面提到的,用例描述“事件流”。圖6顯示不同種類的事件流和它們是如何在用例規格中描述的。
從頂部到底端底藍色粗線條表示主事件流(Basic Flow)。它表示每件事情都按照正確的方式發生。有很多種分支流(Alternate Flow)。描述處理設備故障的分支是一個很好的分支流的例子。另一個例子是描述操作員取消了前面請求的動作。
這里一個非常重要的結構是子事件流(Subflow)。子事件流就象子程序調用。我們試圖保持主事件流簡單易讀,沒有子事件流是很難做到這一點的。例如,我們使用子事件流來描述我們啟動或者安放設備位置時發生的細節。這些過程每個都相當復雜,如果我們都在主事件流上描述,那么它將變得很長并且很難理解。
圖7顯示一個主事件流的片斷:
在第二步,系統檢查作業是否有效。如果系統確認作業無效時會發生什么?這在分支流中描述。在用例規格中我們使用腳注來指示分支流,腳注文本包括指向相關文檔章節的交叉引用。這將減少描述事件流的混亂,使得它更容易讀。在這里我使用 "§" 符號指示存在一個分支流。我也用高亮的紅色表示這是項目術語表--一份很重要的文檔--中的定義。
在第3步,系統檢查選擇的作業的啟動策略。"Starting/Positioning Stragegy 2.1"表示交錯啟動,它需要在啟動作業前所有的設備都到位。這個啟動策略在分支流中描述。最后系統向PLMS詢問是否允許啟動作業。如果不允許時發生的事情也在分支流中描述。
在圖8中,我們將看到分支流和子事件流的例子。
分支流定義當基于某種原因設備不到位,因而這個作業不能啟動時應該發生什么。系統給操作者發一個消息,建議在我們實際啟動作業前把設備移動到相應的位置。在這個點上,用例就結束了。
子事件流的例子提供我們實際上如何啟動作業的更詳細的信息。系統檢查全部作業設備是否暢通(傳送帶上沒有其它物品)。如果正常,系統同時移動所有需要定位的設備到相應的位置,包括作業自己需要的設備和要與其它作業共享的設備,然后我們交錯啟動所有的設備以避免電力過載。當全部設備都運行起來后,我們告訴操作員作業已經啟動,然后用例結束。第16步的 "a", "b" 和 "c" 也涉及了子事件流。
特殊需求
有很多需求,特別在實時系統中,不能歸結到用例的事件流中。通常它們是非功能需求如性能、可用性等等。那些與給定用例相關的特殊需求可以歸結到與用例規格定義相關聯的"特殊需求"一節中。有時為了方便,甚至功能需求也可以放到這一節中。圖9即為一個示例。
第一個例子可以作為一個分支流,但是為了使主事件流基于閱讀,我們可以簡單地說:“系統檢查是否有特殊需求的xyz節中規定的不能啟動的狀況發生”。在這個特定用例中,如果我們在碼頭傳送帶上還有東西,而傳送帶由于完成了往甲板上卸礦石已經停止工作,那么我們將給操作員發出一個警告。
第二個例子是一個算法的詳細描述,這個算法用來調整傳送帶的傳輸量和傳送速度。這里,主事件流可以簡單地描述:“傳輸量和傳送速度按照特殊需求中的uvw節進行調整?!?/P>
結構化用例
用例的結構化是一個高級課題。你也可以不使用這項技術來完成一個系統的需求文檔。用例的結構化可以讓你避免冗余信息,保證用例文本只存在一個單獨的可維護的位置。關于結構化的重要的一點是,你必須避免讓用例模型和用例變得難以理解。
結構化技術在圖10中顯示。
在圖的左邊,我們有一個用例,它有一個主事件流,一個分支流和一個子事件流。子事件流和分支流都可以作為單獨的用例分出來。分支流變成一個新的用例,擴展了原始的用例。子事件流也變成一個新的用例,它包含在原始的用例中。一般來說,包含關系僅僅用于一個分支流共用于多個用例的情況。這就是我們如何確保僅僅寫一個分支流,僅僅有一個維護地點的方法。通常,當需要在已經存在的用例上增加新功能而且你又不想修改原始用例時,可以創建一個擴展流
把這些結構化技術用到我們的產品傳送系統后,改變后的用例如圖11所示:
這些新的用例稱為“抽象用例”,因為它們沒有操作者,你不能直接調用它們。如果我把這些抽象用例隱藏起來,你仍然可以相當清楚地看到系統的主要功能。
一系列的錯誤處理用例都以這樣的聲明開始:“當系統檢測到設備故障”或者“當系統檢測到超載”等。然后用例繼續描述系統在這些情況的響應。
在圖11的頂部,我提煉出了兩個抽象用例:一個是啟動作業,另一個是停止作業。從技術角度來說,我在這里破壞了規則:包含用例應當被多于一個的用例共享。我之所以這么做是因為,如果我在“傳送產品”用例中寫出所有的內容,文檔將超過300頁。把它分開可以讓很多人同時在系統的不同部分描述需求。
補充需求
我們有很多補充的需求,它們不適合放在任何用例中。因為特定的需求與具體的用例相關,這些都是典型的非功能性需求。在你在用例中的需求和補充的需求之間存在一個平衡。當你進行實時系統工作時,你可能發現會比你進行IT系統開發時有更多的補充需求。這是由于在實時系統中有更多的有時間要求的需求,它們都在補充需求中描述。
下面是放在補充需求中的非功能需求的例子:
功能需求也可以包括在補充需求中。當有些功能用用例寫還不如用補充需求描述時,可以把這些需求放在補充需求中,而不用寫一個完整地用例規格定義。下面是一些這樣的例子:
用例的益處
用例有以下益處:
另一方面,關于用例有很多不正確的觀點。第一個是,象當前多種書籍和文章中指出的,傳統的書寫需求的方法能夠更嚴謹和精確。實際上并不是這樣的,我們在這個項目中也能寫出非常嚴謹而精確的用例。
另一個看法是任何沒有經過專業培訓的人都可以寫用例。寫傳統需求文檔的原則在這里仍然適用。你需要從外部視角來看系統做什么。你不需要寫出系統是怎樣做的。象傳統的需求一樣,你寫的用例需求也應該是可測試的。新手經常繼續使用老的諸如功能分解的習慣。有開發背景的人經常傾向于從系統內部而不是用外部視角描述。
用例貫穿整個項目
我前面提到,用例在整個項目中都有用。
項目計劃
在這里我們沒有足夠的空間討論分配用例迭代的準則。只能簡單說,這些準則基于RUP的風險評估。下面是分配的迭代:
迭代1 | 啟動、停止和處理一個獨立作業上的一個設備故障。 維護設備和作業。 |
迭代2 | 啟動、停止和處理覆蓋作業和作業組上的設備故障。 維護計劃和約束。 維護產品。 |
迭代3 | 創建產品產品差距。 改變作業所有權。 直接命令設備 刪除作業。 修改負載數據。 |
用例分析
用例分析是一個用來識別對象、類、類屬性和類方法的過程。 由于這個項目的實現方法是非面向對象的,我們使用一個映射把面向對象的分析模型轉換到過程設計模型。圖12顯示對啟動作業用例進行分析的部分結果:
測試計劃
我極力推薦下面的一篇文章:June 2001 Rational Edge,Jim Heumann,"Generating Test Cases from Use Cases"。在我們的PT系統中使用這種方法識別測試用例。圖13顯示啟動作業用例的迭代2的測試用例。注意在測試用例和用例需求之間的連接。它可以幫助保證需求都被測試,以及測試用例隨著需求變更而更新。
經驗學習
1. 集中在外部可視的行為上。這一點怎么強調都不過分,這就是我為什么這里再次重復的原因。在這個項目中,我經常告訴那些需求分析人員,讓他們想象它們是飛翔在港口工廠的用戶,讓他們問自己他們想要看見發生的事情。如果你寫的描述一些事情的需求不可見,那么你將不能對它進行測試。
2. 不要引入設計。這與經驗1相關。下面是一個例子
每個作業都擁有一個使能信號,這個信號來自于作業的運送源。使能信號在操作間內部驅動作業運送來源的物理信號。(用例在這里描述了系統內部信號。)
有很多原因使你不應該這么做。首先,它使得測試很困難,因為描述的行為在外部不可見。第二,如果你把設計信息放到用例中,你就需要照著這些信息實現,因為那是需求,因此你不僅必須照著它來進行演示說明,而且它也限制你的設計人員的實現方式。
3. 不要為內部監控過程寫用例。在這個系統中,由于是實時系統,有很多在系統內部運行的過程用來檢查、監控和輪詢其它設備。你不應該在你的用例中描述這些,因為它是設計,它僅僅是一種可能的實現方式。
除非過程與系統的目標相關,例如在建筑監控中的“監控建筑”用例中,你應該把它們寫在補充需求規格中。例如
在用例的分支流或者擴展用例中,都可以描述如果系統檢測到問題時發生什么事情。這些需求可以使你設計諸如輪詢設備或者設備產生中斷等的過程,然是它們屬于設計應該考慮的事情,不屬于需求的范圍。
4. 不要太早"凍結"用例。在項目中太早凍結用例將會導致很多問題,因為在你和你的客戶更好地理解需求時,你可以找到機會重新組織用例,或者你將引出新的用例,或者你要修改現有的用例。需求變更會發生,但這需要在一個迭代過程的管理和限制下進行,以便進行適當的影響評估,以及合適的預算和計劃日程的變更。如果你使用迭代過程,你至少有在后面的迭代中改正的機會。
5. 不要過于追求完美的用例模型而超出項目計劃日程。這是經驗4的必然結論。你從來都不可能得到一個完美的用例模型。在某個點上,你將不得不停下修補完善用例模型的工作,開始實際的系統開發工作。即使用例模型并不完美,你也可能開發出符合用戶需求的系統。最后,圖14顯示PT用例模型的實際樣子。
你將看到選擇作業、啟動作業和停止作業是主要的用例。這里并沒有圍繞著傳送產品用例把所有其它用例聯系在一起,我們不得不在附加需求中描述其它的需求。來自操作員和相關者的選擇、啟動和停止作業的需求并沒有進行評估。用例模型不完善的主要原因在于,需求必須在某個點凍結,以便開發者不會頻繁地面對不確定的開發目標,系統應當被實際開發測試和部署。
6. 不要害怕收集細節信息。用例假定容易被每個人閱讀,但是這并不意味著你在大街上隨便找一個人,給他一個描述復雜系統的用例,就能夠期望他能夠理解。
需要問你自己的問題是:你的客戶需要多大程度的細節?你想給你的開發者多大的范圍?如果你在用例中沒有給出很多細節,你就讓你的開發者自行作出決定。你想這樣做嗎?你的開發者可能有豐富的經驗而你也很高興這么做。另一方面,如果你正在進行實際的開發,沒有充分的細節不一定是可以接受的。你需要給開發者和測試者描述以足夠的細節信息,說明什么對于客戶是重要的。
如果有大量的細節信息,可以考慮把它們放到特殊需求或者附加需求中,或者用活動框圖(Activity Diagram)來補充用例。(參見經驗9)
7. 不要引入用例間的直接交互。用例不能相互交互。它們可以相互影響,但是只能通過操作系統狀態來影響。
8. 不要把有關解決資源爭奪問題的架構決策放到用例中。這一點與第2課有關,例如,當操作員使能一個作業的來源時,同時第二個作業共享同一個來源因此得到一個來源不可用的錯誤時,會發生什么情況?
這些狀況應該在不同的用例中描述。在每個用例,你只需要簡單描述在給定環境下你想要系統做什么。在這個例子中,系統內部如何工作,什么信號發到設備,這些都屬于架構或者設計問題。系統架構需要解決這些問題,諸如保證信號在非常接近情況下接收、不同順序接受或者高頻率地接收。
9. 使用活動框圖以便使得復雜的用例能夠易于理解?;顒涌驁D可以作為用例的規格創建。
總結
在PT系統中使用用例給項目帶來很大的價值。只要有外部可見的系統行為,就應該使用用例來定義需求規格。
對任何系統來說,在確定用例時,要集中在系統的目標上以及系統給相關人員提供的價值。在寫用例時要維護一個系統的外部視圖。
對于實時系統,附加需求在整個系統需求中占有更大的百分比。
原文轉自:http://www.anti-gravitydesign.com