使用案例 (Use Cases) -- 儘管這個名稱令人感到納悶 -- 已經變成物件導向方法中最受歡迎的技術之 一 。 Ivar Jacobson 提出這項技術並獲取廣泛的運用因" name="description" />
MILY: 新細明體; mso-ascii-font-family: 'Comic Sans MS'; mso-hansi-font-family: 'Comic Sans MS'">使用案例(Use Cases) -- 儘管這個名稱令人感到納悶 -- 已經變成物件導向方法中最受歡迎的技術之一。Ivar Jacobson 提出這項技術並獲取廣泛的運用因而引人入勝,也在資訊技術及系統發展中取得核心的地位。由於近來每一位作者於物件導向設計方面都會談及使用案例(use cases)並引發討論。同時,它們也在統一模塑語言(UML)中扮演一個重要的角色。 使用案例的價值來自以下幾點原因。首先,它們協助我們去發現需求;使用案例允許你透過將焦點集中在使用者需要去執行的工作上,以捕獲使用者的需求。使用案例能夠協助我們有系統的闡述系統,並且幫助我們驗證這個使用案例的確可以被建構在此系統中。它們也協助控制反覆式開發(iterative development):在每一個發展階段重覆發生時,你可以進一步的建立使用案例需求的子集。 儘管使用案例被廣泛的使用,然而仍有許多問題點無法被充分的理解。如其基本的定義 -- 系統運作與使用者互動過程中,所產生一連串的活動(actions) – 看起來夠簡單了吧。但是你若立即開始嘗試去捕捉系統的使用案例時,你將跑進死胡同。我曾經看過一些專案在使用案例裡糾纏不清,促使發展過程進退維谷。所以這裡我就列舉一些我所看過誤用使用案例的案子,並且讓我們思考如何去避免這些錯誤。 濫用功能分解(Abuse by Decomposition)我見過數個專案因為將太多的努力浪費在架構使用案例上而陷入困境,仿效 Jacobson 的作法,在UML規格裡於使用案例之間採用以下兩個關係:uses 及 extendsJavaScript" class="msocomanchor" id="_anchor_1" onmouseover="msoCommentShow('_anchor_1','_com_1')" onmouseout="msoCommentHide('_com_1')" href="http://www.uml.org.cn/oobject/OObject102304.htm#_msocom_1" name="_msoanchor_1">[朱子1] (譯註[一])。這可能是有用的,然而我將它們視為是一種困擾 – 特別是使用這類關係。在上述的案例裡,分析者採取相當粗糙的使用案例(use case)並且將它拆解成數個子使用案例(sub-use cases)。每一個子使用案例再進一步的被拆解,通常直到你將它們分解到單元式的使用案例,類似原子的程度為止。 這是一種功能分解(functional decomposition),一種與物件導向開發相對立的設計風格。它導致了以下的幾種問題:首先是使用案例的結構直截了當地反映到程式碼時,造成系統的設計看起來就像這些經拆解的使用案例(use cases)一樣。一般的症狀是去找出行為富麗堂皇的控制項物件(controller objects)來操作沉默寡言的資料物件(data objects),這種作法較之一個經封裝的資料結構而言,是相當瑣碎的工作。 這樣的設計方式也喪失了找到更多有益的物件。系統重複的行為可能跨越不同的控制項,並且資料結構的知識(knowledge)也遍佈這些控制項。基本的問題在於功能的分解促使你思考一種行為,會依循其更高階(higher-level)行為的脈絡。採取這樣的方式,會造成你難以在另一個環境(context)中運用相同的系統行為,就算這兩種環境大部分是雷同的。若你考慮到要讓物件擁有的行為可以運作在不同的環境裡,就不能採用功能分解的方法。 當然,並不需要像使用案例這般在意系統外部的結構[朱子2] (譯註[二]),你只要牢記系統內部的結構就可以避免這個問題。無論如何,對於毫無物件導向開發經驗的開發者而言,這是個困難的概念,所以這些人也就極有可能採功能分解的方式去建立系統。 就算你不會注意到功能分解如何影響你內部的設計,大量地構築使用案例(a set of use cases)終將會陷入這種困擾,因為人們最後還是會花費大量的時間在它們身上。把每一個使用案例往下拆解成單元的步驟裡,對拆解成單元的使用案例進行參數化作業,使它們與更高層(higher-level)使用案例的功能保持一致,然而這些作業所佔用的時間最好能用在其他事物上。在開發階段初期是不需要去捕獲使用案例的每個細節,你會想要在開發初期留意到具有高風險的部分,而大多數的細節會留待反覆式開發(iterative development)最後的階段才進行,那即是反覆式開發的整個重點。 所以我會打消那些對物件(objects)不熟悉的情況下行使 use (使用)關係的主意,同時把它當作是在設計及使用案例之間的一項警訊。「extends」(延伸)關係似乎比較不會造成困擾,但是我依然不會有使用它去做出一件大事的舉動。我曾經看過即使沒有用到這些關係也能很有成效地運用使用案例的專案,所以它們基本上並不具任何意義。 濫用抽象化(Abuse by Abstraction)論及物件就不離抽象化(abstraction)。就算是簡單的抽象化也會發現其效力無窮,它讓複雜的問題易於處理,這就是所謂良好的設計。所以作為一位設計者(designers),我們運用抽象化,促進抽象化,歌詠抽象化。 但是抽象化與使用案例擺在一起運用可能會導致困擾。我記得在一個專案裡與一位使用者交談,這位使用者坦白的說,雖然剛開始他能夠明瞭使用案例為何,然而他現在卻感到迷失在一大堆抽象的使用案例中。「當開發者對我解說它們(使用案例)時我認為我可以理解,但是到最後我卻不能夠記得這些說明內容。」使用案例主要的目的之一是與系統的使用者 –- 客戶 -- 作溝通,抽象化的使用案例已經超越可被理解的程度,所以對任何人都毫無幫助。由於內部的結構不需要與外部的結構相同,所以在使用案例中缺乏抽象化並不會造成危害。我不曾發現在使用案例裡欠缺抽象化就會導致在其內部缺少抽象化,相反的,使用較少抽象的使用案例(abstract use cases)對我們反而有所幫助,因為一個抽象內部的結構會對映到一個具體的使用案例(concrete use case),以協助我們去了解抽象化。 抽象化的(abstracting)使用案例也有可能導致更龐大的使用案例,換言之,在一個反覆式開發過程中,會造成規劃工作益加困難。你可能要花費更多的時間去推導出(arguing)抽象化 – 而這些時間你最好是用在其他地方。 所以我的建議是去違反抽象化的原則,而盡量讓使用案例具體化(譯註[三])。有關上面所述及的,重點在於不要做過多的抽象並讓你的使用者得以領會,使用具體的使用案例進行解說和確認你效用無窮的抽象化作業。 濫用圖型使用者介面(Abuse by GUI)儘管圖型繪製工具問世不久,大多數的人們正使用這些圖型繪製工具來協助自己決定使用案例,理論上是動人的。GUI對使用者而言可以更具體化;它協助我們清除容易忽略(easy-to-forget)細節的障礙;它讓使用者可以明瞭系統看起來應該像什麼;GUI使我們容易去塑造原型;它們合理的展示並解說系統的特徵及功能。 由於上述的種種理由,我過去曾認為GUI原型是一種良好的需求(requirements)工具,但是仍存在一些根本上的問題。當你向使用者展示GUI原型時,就算那只是形同在戲劇後臺留下少量的線路,但它看起來就像是近乎完成品。當然,我們知道那是潛在於後臺裡面極為複雜練習的一部分,但這是非常難以讓客戶了解。GUI導致不正確的進度指示且難以掌握 – 它也許可以正確的將一個按鈕擺放在圖形介面(UI)上,既使如此可能也需花費幾星期的努力。有一條鴻溝介於實際上的努力與感知上的努力之間,使得它難以去成功的跨越,那也就是說將它控制在某個範圍裡是重要的。 儘管事實上GUI工具似乎是如此容易使用,而且總是有許多細微的調整功能使得它看起來正確無誤。這些美好的調整功能在某些方面也限制了人們的預期,造成當一個簡單的設計構想浮現時卻很難處理這些改變。 所以我現在告訴人們,如果無法完全寫好程式碼之前不要展示任何GUI,使用筆和紙所繪製出來的GUI原型仍不失為是好的製作方式,這種方法可以讓你避免不正確的進度指示。 濫用否定可供選擇的項目(Abuse by Denying Choice)以一個高消費階層的(high-end)[朱子3] 文字處理器為例(譯註[四]),想像一下有關這個文字處理器的使用案例(use-cases)。你大概會包含「變更樣式」、「應用樣式」及「從另外一個文件裏匯入樣式」的功能?問題在於這些使用案例並非直接點出一個使用者的需求。使用者實際上所需要的東西應該像是「確保文件內前後格式的一致性」,或者「製作一份文件類似另外一份」。我將前者的描述視為系統的使用案例,而後者則視為使用者的使用案例(譯註[五])。 這個問題在於直接採取系統使用案例的舉動,將否定你提供其他系統的使用案例以處理類似問題的機會。無論如何,你不能夠單單運用使用者的使用案例,因為它們無法充分地符合反覆式發展程序中排程(iterative scheduling process)所需。 對此問題我承認無法提供一個完整的答案,我將注意力放在系統的使用案例,最主要地在於他們對反覆式規劃及系統測試這些方面相當有用。無論如何,伴隨每個系統使用案例的背後,我會考慮到是否另有其他使用者的使用案例存在,我對此保留一段註解,並且嘗試去提供系統使用案例的替代方案。 使用案例是相當有價值的技術之一,且適合我們使用。我長期運用它們在我的開發工作上,而且但願我過去一開始就使用這項技術。但是需要謹記,你使用它們有何目的,並且小心提防這些陷阱。除此之外,期盼某些人寫一本有關於「怎麼製作一個好的使用案例」的好書,至少有一位積極進取的開發者(active developer)確實地想要去閱讀它。
|
[一] UML 1.1 的規格已經作了變更,使用案例之間的關係包含 include、extend 及 generalization。
[二] 若想了解這句話的意思,就必須了解 use case 是以參與者(actors)的觀點,去尋求系統的需求這一個關鍵。有關此可參考 Scott W. Ambler 編著「最佳的 UML 使用案例模型技術」一文。
[三] 作者原文為「So my advice is to err on the side of being too concrete.」,其中on the side of 代表「在一端的...」,從這篇文章而言,一端指的是「具體化」,另一端指的就是「抽象化」,軟體分析及設計其主要的目的,就是必須將具體化的事實,透過抽象化的方式將其轉化為利於程式設計的過程。具體化利於描述現實,但卻不利於軟體的設計,反之亦然。作者一開始說明了抽象化對程式設計有多少好處,並讚揚抽象化,接著描述抽象化如何帶來對客戶於說明系統設計上的種種不便,也談到具體化的優點,及抽象化在規劃工作上的缺點。最後,作者選擇具體化 Use Case 並解說它的原因。
所以,作者是在權宜之下,站在 Use Case 是以使用者的觀點來描述系統這一點,並為了便利對客戶說明、工作規劃,及可以用來確認抽象化的結果是否符合使用者所需,選擇具體化 Use Case。因此,我將這句話想成「權衡之下,棄抽象化,擇具體化」,也是根據這一連串的考量。另外,ARECA(盈學兄)對我建議他的看法,我將之補充於後,較我的翻譯他的說明更為貼切。
至於『So my advice is to err on the side of being too concrete.』譯法可能需要從side這個字為中心來討論。作者使用side這個字應有兩方面比較的意思(也就是抽象與具體),也就是兩者權衡(至於權衡的標的是甚麼應看前後文,也就是過度抽象及過度具體的缺失)。所以我的說法會變成『過度抽象及過度具體兩者皆有缺失,我建議還是選擇犯過度具體的缺失而盡量具體化』。
[四] High-end 一詞在此代表高度地與最終客戶相關的,然商業上的說法指的是高消費階層的客戶,我個人比較偏愛前者解釋,然字典的用法卻偏向後者,所以再三思考,還是採用字典上的通用解釋。
[五] 系統的使用案例指的是偏向以系統的觀點,所做出的使用案例,例如「複製」、「貼上」。而使用者的使用案例則偏向使用者的觀點來看系統,所製作出來的使用案例,例如,「將文字或圖片複製到相同文件的另一處或不同文件的地方」。系統的使用案例具體的說明系統要達成此目的所應採取的方式,因此可以據此作成計畫排程及系統測試之用,然而卻以規範限制了達成此目的的其他可能方式,例如「採用拖曳的方式」。然而使用者觀點所製成的使用案例又過於籠統,缺乏如何實作的方式,因此難以評估及排定時程,兩者各有利弊。