2008年2月29日 星期五

L13 系統的製程(12)──Use Case的執行流程

Activity List的Interface Method產出後代表所有的Activity都已經有了統一的入口,接下來要做的是依前述的原則產生Use Case Interface(這通常會在我定義的Service Module那一層),並依照Activity Diagram的內容產出Use Cases層級的Sequence Diagram。

在我的設計方式裡,每個Activity都會指到一個Interface Method,這使得在製作Sequence Diagram時有簡單的對應規則,變成只要專心於流程的製作。在Rose上的作法是在Logical View裡建立對應的Package與其中的Use Case Realization,再依選擇的劇本建立Sequence Diagram,圖表裡呼叫的方法就是之前建立的Interface Method。

在這裡記錄的內容維持在Use Case與Activity之間,未來流程會在Use Case Method的實作進行,利用Activity Diagram與Activity Interface Method就可以交得資淺的Programmer實作出我們想要的功能。Activity的內部要如何實現動作的功能則是SD階段應該做的工作。

不越權的使用能夠侷限住使用關係的層次,不會使Use Case Method直接使用到較低層的物件(通用API除外, 這是給所有層次使用的簡單通用功能)。

2008年2月28日 星期四

L12 輔助的文件(4)──產生Module Interface與Method

在這裡要產生的是Interface與其中的Method宣告,我的作法是從上一篇的Activity List設定轉出。首先要先檢視轉出時需要參考的資訊是否都已經設定到Excel表格中。

產生Interface本身需要Package與Interface Name,Module的可見範圍可以預設為public,不過還是建設設定一個欄位來放置以便應付不同設定的場合。轉換的程式可以依Package確定檔案產出的資料夾,Interface Name產生檔名;同時檔案的內容可以產出package與Interface的宣告。

接下來是Method的部分。Method Name、傳回值與傳入參數型態、名稱都可以從Excel表格取得,再加上Method的可見範圍就能夠產出完整的Method宣告;Excel裡擁有的資訊越完整就可以在不同的需要時設定不同的內容。傳入參數都會有帶入多個的情況,由於傳入時大多彙集成Interface,目前還沒有多過五個的發生,可以定義足夠的輸入欄位在表格。

直接使用Rose製作Interface內容時Interface是散落在Package裡不容易取得清單作比較分析的,但是使用Excel的同時除了得到同樣的產出之外,我們還能有包含所有Activity對應的所有Interface Method,這在檢視與討論時都比較方便。這份文件加上Use Case的Activity Diagram是在SA階段所歸檔的設計文件。

將Excel的格式固定並撰寫對應轉出程式後,未來的任何改變可以在Excel檔案裡修改就能直接匯出為Interface宣告,實作程式若有需要同時修正的都會自動在Eclipse裡註記紅色錯誤標記。這樣的作法不是便利許多嗎?

2008年2月27日 星期三

L11 替代的作法(4)──Module Interface Method

接下來所要做的,是在負責的Module裡為每一個Activity定義負責處理的Method Name;這個Module Method會是未來實作該Activity的程式碼所在。在L04裡所用的Excel表格是此時必須去完成的,我們優先填入對應層次的Module Interface Name,再填入適當的Module Interface Method Name。

以上只是起點,決定Interface與Method後還會發現表格裡還需要更多方法資訊:可見度、傳回值與傳入的參數類型、名稱等等,這些都可以加入更多的column來記錄。其實在這裡所做的意義與在Rose裡定義方法是完全相同的,但是我們可以發現直接在UML上設定Interface後資訊都在各自的Interface裡,而在這裡卻擁有系統所有Activity方法的總清單。

詳細地定義好方法的所有資訊後,接下來需要再一個手續把資料產出為真正的Interface。

2008年2月26日 星期二

L10 系統的製程(11)──Module Interface Method

接下來所要做的,是在負責的Module裡為每一個Activity定義負責處理的Method Name;這個Module Method會是未來實作該Activity的程式碼所在。在Rose裡的所要做的就是逐一在對應的Interface裡加上對應該Activity的Method;對應Interface的意思除了要找出正確負責的Module之外,還要決定方法要被放置在哪一個層次。

決定好放置的Interface後就是加入Method的動作,定義方法的可見範圍(由於Module分別放置到不同Package,所以都是用public)、與傳入的所有參數等等。要記得不管是傳回值或是參數裡所用到的系統物件都必須使用Interface;不過這時完全沒有Class,要用也沒得用。

在決定Activity對應的方法時有一個決策,就是必須決定在API上要將Module傳出去直接使用Module Method,或者是只在API上定義可使用的方法再由內部轉呼叫Module Method。前者的作法需要定義的方法比較少,但是外部呼叫的程式有可能沒有釋放掉取的Module而產生後續的問題;後者的作法因沒有把物件傳到外部相對會比較安全,可是必須在API建立一大堆的對應方法。

如果可以嚴格規定外部只在需要時取得Module並不得記憶下來的話,我比較推薦直接傳出Module的作法,因為在以最短時間完成系統的需求下還是以達成功能的最快作法為優先。

2008年2月25日 星期一

L09 系統軟體架構的層次(1)──Package、Class與Method

在我設計的系統裡,軟體架構的堆疊分為三層,由下而上分別是Package、Class、Method;設計的時候是由下而上一層一層堆積起來的。如果設計上面層次時發現要改變下面層次的結構,這多少反應出下層原先的設計帶有缺失。

Package的設計上,我使用Module的概念加以區隔。把系統比喻成公司的話,Module就等於公司組織的部門,每個Module都有自己應該負責的工作範圍。Use Case藉由數個Module的分工來完成,而Module為Use Case而定義的Interface Method集合,就是它應該負責的全部工作。(Component的設計概念與Module相同)

Class的設計是Package裡的物件佈置,在公司部門裡的人員同樣需要分工,有經理負責管理,有人要負責對外窗口,然後每個人都負責不同的業務項目。在Class的設計上也是如此,依不同的目的放置不同功用的Class。Package與Class放置的時候都同時要考慮Interface與繼承的特性。

Method是唯一為如何做事情而設計的,不管是流程控制或是系統動作都是在這裡面完成;我依照這個方式把方法分工為流程與動作兩類,努力不讓一個Method混用這兩類的意義以避免難以拆解與改變。這到SD的章節時再作詳細的說明。

只要依序執行過功能所需要的動作方法就一定能完成它,但是藉由Package、Class的佈置,讓各個方法依特性集合起來,在應付不同需要的時候可以提供群組化後的重用單位(元件化)或是快速地更改進行流程(需求變更),這是彈性設計的主要目的。

2008年2月24日 星期日

L08 某個專案裡的Module Diagram產出

說真的,光是佈置Module與Interface就需要不少精力去佈置與討論,在去年底專案進行時對於系統架構陸續花了將近五個工作天才算定稿。不過當時所有人都有共識:要確認所有系統模組後才允許作進一步的設計。

我所做的這個專案是單機執行的系統,只有一個Layer的情況只需要一張Module Diagram就足夠。第一張圖是專案層級的圖,當然比範例圖複雜許多。第二張圖是加上Interface層次後的圖,到這個情況時如果沒有人說明,一定是沒有人看得懂的。

切記Module的意思是要把Activity所要做的動作加以分類,至於Module要如何佈置就要依賴專案團隊予以詳細地討論並確認,在取得共識後才能得到最適合開發的系統結構。


2008年2月23日 星期六

L07 系統的製程(10)──Module Interface的層次

如果製作的只是單次使用的性質,而且功能需求特別到未來幾乎不會再reuse,那麼之前所獲得的Module Diagram就是我們開發的基準。但是想要做一個可以reuse的系統的話,勢必要再為通用Module製作不同reuse基準的Interface關係。

我會為所有的通用Module Interface準備四個不同reuse基準,分別是基本、行業用、系統用與專案專用。專案專用是只在這個客戶才需要的功能,現在的Module Diagram裡的Interface都是專案專用的;系統別是特定行業的特定系統才會使用的;行業別是在那個行業的所有系統都適合的;其他在任何場合都可以使用的功能則放在基本。

分層的好處在於未來的reuse可以直接繼承符合自己需要的那層,但相對的現在得佈置四層Interface(當然未來也有四層class等著實作),同時每一個定義的方法都要逐一確認應該放置到哪裡。大多數人會認為因為未來不確定的需要而在現在花時間去做是很不值得的,所以都只做出專案專用的這層;這樣的作法在未來真有reuse的需要時,就絕對只能copy-paste形成另一套系統再作修改,所以我寧可多花少許時間佈置好這些架構以避免未來更難維護。

哪些Model要切分多個層次是見仁見智的,不過基於要做就一次做到好的念頭,我都會全部一次定義。下圖是兩個Module的範例。

2008年2月22日 星期五

L06 系統的製程(9)──佈置API與Service

對於Subsystem有幾個思考的方向:整個Environment 重新設計?整個Environment全部沿用?或者沿用相同的Factory、Preference、Message等支援Module而只改變MVC的部分?每一個決定都會帶出不同的作法。為了達到最大的彈性最好假設兩者都會被採用,只是每一種作法都會額外多出一些需要設計的管理方式。

在重新設計的情況時,使用Subsystem就像使用一個完全不同的系統,全部Module都要重新設計是免不了的。在沿用相同的支援Module時,所有Subsystem的MVC要實作同一組Interface使之能在Environment裡抽換;此時甚至要在Environment裡加上管理機制來允許多組MVC同時存在。

在系統必須提供一些功能給外部呼叫的時候,需要額外準備稱為API的Module,將系統提供使用的功能都集中定義在這裡;API被系統管理的,裡面定義的會是與Module提供的動作有關。另外會有Service的存在,在這裡放置的則是跟服務有關的功能,也就是使用者想要系統執行的功能;這在未來可以加掛將XML轉換為data model的模組讓Web Service可以使用系統提供的服務。

對應之前提過的兩層式邏輯,Service可以說是系統流程(對應為Use Case),而API裡的是動作流程(對應為Activity)。在我的設計裡,Service可以指定不同的Environment,讓同樣的一套服務程式碼可依設定的不同在不一樣的系統動作。

2008年2月21日 星期四

L05 Rational Tool(7)──使用Package Diagram描繪系統Module

做完上一篇的步驟我們可以得到Class Module List與Server Module List,擁有所有的Module後接下來就是安排每個Layer裡所有Module的組織圖。

首先要篩選出支援性質的Module,像是Preference、Resource Management、Log、Message、Data Model Factory、Data Model Serialization等等,先行安排這類必須要有的後勤Module,這些Module都適合作為Environment下的獨立機制。再來就依系統功能需求安排與Data Model有關的Controller、View、Listener、Event Notifier等執行用的Module。Module若有進一步的說明可以寫在Package Documentation裡。

兩個以上的Module有合作關係時首先找出誰應服從誰的指揮,把指揮者放在使用另一個的位置,如果彼此有相互使用的情形就多安置一個Cotroller Module來負責控制的責任。在我的理論裡,每一個Module都會安置在不同的Package,而操作它們的管道唯有經過定義出來的Interface而已。在安置好一個Module後同時給予一個Interface,再依使用關係拉上線條。

依責任的描述佈置好所有的Moudle就形成了系統的基礎結構。下圖是一個簡單的系統Module組織圖範例,其中虛線所表達的是Module的從屬關係(帶有管理的意義)而非使用關係。

2008年2月20日 星期三

L04 系統的製程(8)──決定每一個Activity的所屬Module

Activity List裡是系統必須要具備的所有動作,在這裡我們要做的是定義每一個Activity負責處理Module。把系統比喻為公司的話,Module就等同於部門的意義,因此在這裡應當去劃分所有的工作到它應屬的部門裡。

儘量把內容相近的Activity編排在同一個Module裡,如果數個Activity屬於同一個Module的定義但是在意義上有所差異,可以為該Module定義附屬的Module。比如說有些Activity都是與系統設定有關,但是部分在系統讀入後就固定下來,有些則允許使用者在執行時設定,那麼就可以分成兩個不同的Module來負責。

理想的情況是一個Activity都可以找到一個負責的Module,如果在安排的時候發現需要兩個以上的Module才能達成一個Activity的話,就需要研究那個Activity是要再加以切割或者這樣就是最適合的,在後者的場合我會將它們都配置到一個稱為API的Module並略為註明需要哪些Module的動作來達成。

分派Module的結果可以填寫在Activity List的表格裡,依Activity所在的Swimlane放在對應的Module Name欄位。

2008年2月19日 星期二

L03 系統的根源──管理所有Module的Environment物件

總需要有個源頭,可以以這裡作為起點取得整個系統;就像是粽子一樣只要提起所有線的根源,就能拿到任何一個粽子一樣。這樣的一個Module我稱之為Environment(只是我用的慣稱,沒其他的意義)。

Environment一定會定義一個Interface來描述它的規格與可以做的事,通常只有存取其他Module的動作,因為對於Environment我只將之定義為管理系統Module的總管,本身不實作任何系統功能。

物件的實作採用Singleton的方式而不使用static method,這是為了未來的彈性,因為static的作法不管對物件或是方法都是固定的,它就只在存在於那裡無法再有變化。如果未來需要多個系統同時存在時,只要修改constructor並在Environment上再加一個管理Class就可以達成變更。

2008年2月18日 星期一

L02 以理想的軟體架構為目標

我自己的理想軟體結構之基本觀念只有一句話:靜態物件與動態方法全部都要一一對應。這句話說起來很簡單,但是要在系統設計時落實時勢必要多費不少時間。

我所用的作法是在2007/11的專案進行時領悟出來的,當時我必須留下系統架構的空殼給三位工作不滿兩年的工程師,讓他們逐一把Use Case的實作填進系統。如果依照以前自由堆疊的寫作風格,等拿到手裡時鐵定是無法動彈的僵化結構,因此我擬定的策略是努力把系統結構鋪到所有可能會放置程式的地方。

現今留存下來的系統是四個人花費兩個多月完成的,然而當初我費盡心力建設起來的軟體結構卻沒被他們作過任何調整──除了一個當初我自己偷懶將應分成五個對應卻合成一個的Module之外;他們都覺得一開始的系統架構已經滿足之後製作功能的全部需要。所以這個設計方式我將會一直沿用下去。

在一一對應物件與方法時,我同時兼顧了一個目的:在設計結構上進行更細部的設計、實作與重構時,如果實行的內容只有Method的垂直或水平的抽取與移動的話, 就是理想的架構。垂直的定義是:方法往父類別(Generalize)或子類別(Specialize)移動,或將相同的程式區段另抽出Method重覆使用;水平的定義是執行方法的責任往呼叫自己或自己呼叫的方向(Delegation)移動,或者是合併或拆解Method。

2008年2月17日 星期日

L01 架構設計像鋪路, 涵蓋越廣就讓後人越方便

系統的設計是把一個一個的Use Case與其中的Activitiy依照順序放置到軟體的結構裡,並利用程式的邏輯把它們串連起來以達成完整的功能。對一個Use Case來說,只要按照規則執行過所有的Activity都可以做到,但是要如何放置Activity卻也是需要設計的。

Activity不管怎麼放都能達成功能,但是能輕易地reuse或是快速配合需求的變更卻不是容易的事。我們可以回想自己寫過的程式裡,有過多少次對於介面、物件與方法的合併、拆解與抽取呢?有時候以為某個方法的作法應該不會再有變動而固定下來,卻在不久的將來發現某個問題或是變更需要將那個作法一分為多而硬生生地重新拆解內容;拆解的同時又會發現許多原本也使用這個作法的其他功能又得再想過一次,為了符合新作法的幾個變更結果又造成更多地方需要調整……。

就自己而言類似的問題時常遇到,有時剛寫好的程式在回想時就會隱隱感覺遇到某些情況時將無法應付,修改後也沒法解決全部而以功能可以正常就好來安慰自己。設計的彈性是在維持功能正常前提下同樣必須具備的,把所顧慮到的可能變更納入系統的設計是有能力者應盡的責任, 不做的話其他更沒有經驗的人是完全沒有辦法做出來的。

2008年2月16日 星期六

K16 令人感到麻煩的設計(9)──把固定數據提出成Constant

在程式寫作時常會有一個要求:要求把所有放置固定值的地方都另外使用常數來放置。對於寫作的人來說這是感到麻煩的地方,因為明明可以直接放置固定不變的值卻變得必須額外指定一個常數,無形中浪費了一點時間,而且有時無法快速找到定義的內容。

很多額外多做的行為都是為了一個目標──把相同意義的東西抽出到同一個地方。異中求同是在這裡是必須具備的能力,大至從Use Case裡把相同子劇本提出的sub Use Case、佈置系統架構的Module、為完成特定功能的Component、Class特性的分析與定義、決定完成指定功能的Method、直到將使用的Constant拉出到通用的變數,每一個提取動作的目的都是為了“完整的reuse”。

在遇到第一個可能會被reuse的部分時,會有人因為想少做點事而沒作提取的動作,但在接連遇到同樣的情況出現後,還是無法避免去做;而且等到後面才做時,必須得找出之前沒有提出的地方做出少許破壞程式改用共同部分的舉動,感覺上像是把之前沒做的事堆在後頭一次做完,而且可能會有漏失的風險。

所以我的作法是:該做的地方就在遇到的時候處理掉,即使它可能只出現一次。

2008年2月15日 星期五

K15 令人感到麻煩的設計(8)──每個設計項目有各自的Data Model Interface

曾經接觸過一個系統,裡面的Data Model實作是一個巨大的Map,它提供了兩個最單純的存取方法:getData(String name)與setData(String name, Object value)。系統裡所有需要存取Data Model的地方只都經過這兩個方法。

這在存取的時候既方便又好學,作出來的功能也不會有什麼問題,但麻煩來自於後面的一個需要:有個專案有其中一個模組的需求,詢問是否能夠reuse我們設計好的模組。我回答不容易,因為這個Data Model沒有設計Interface所以使用的模組只能用它,而且沒有根據Module來定義它所能存取的Data,變成必須要去追所有程式碼才能找出用到哪些名稱的Data。最後當然沒人要去作這種追溯而情願重新寫一個。

這就是沒有Interface並加上多合一設計的糾結。沒有定義介面變成使用時一定要依賴該Class、沒有定義該Module專用的Interface就難以快速得知它使用的資料範圍、入口的合併造成不容易分辨執行時要存取什麼資料;Data Model像是無形的鎖鏈, 將明明分開設計的Module綁死在一起。這使得要記得Interface是一個規格,定義時以能夠只觀看Interface就能明白它提供了什麼樣的功能為目標。

2008年2月14日 星期四

K14 系統的製程(7)──Data Model Interface

需求階段的後半段要建立系統使用的Data Model,這部分可以使用CRC方法得到的定義,根據內容定義Data Model Interface與對應的Method。這個部份的設計可以使用Class Diagram忠實地呈現CRC Card裡的責任與合作。

在設計Data Model時並不刻意描述儲存的媒體是什麼,期望的是不管存放在哪裡都會在使用時變成Data Model物件。應用資料庫正規化的方法來設計將會使Data Model的佈置更為理想,養成這個習慣會讓自己的設計在更多的地方符合通用的標準。

如果熟悉的是ER Model(Entity-Relationship)的作法當然可以應用,先設計好所有Entity與Relationship後再依照結果建立Data Model Interface。設計好ER Model後再使用DFD(Data Flow Diagram)設計同樣可以完成系統功能,因為程式存在的目的都是為了處理資料。

要記得在這裡定義的Data Model Interface是配合系統動作定義的,要使用具有Domain意義的Method名稱;例如取得使用者編號是getUserId()、設定使用者名稱是setUserName()之類的,即使已經知道未來全都是用setProperty()來存放資料。因為使用getProperty()是把多個系統對Data Model的操作合併到一個方法裡做,在這種多對一的對應關係下,想進一步地在系統裡分析出多個中的一個之關聯勢必要再參照參數實際值而無法只看Method Name就有答案,這將會埋下未來難以處理的盲點。

2008年2月13日 星期三

K13 令人感到麻煩的設計(7)──入口、流程與動作

Use Case與Activity的製作其實就是最high level流程與動作的分離,藉由將Activity定義為Interface Method將之固定為完成特定動作的目的,此時的Use Case可以被限制到只是用流程串連必要Activity的規則。

當然我們可以把Use Case用一個Class甚至是一個方法來完成,在功能上所有作法得到的結果都是一樣的,但是把多個動作組合在一個方法裡所付出的代價就是它被限制住只能有組合後的結果。雖然加上參數後可以應付多種不同的需要改變內部,但是當出現要增減動作的需要時就會發現改動不僅不容易而且還要考慮很多相容的問題。這是把流程與動作合併在同樣方法的問題。

雖然重點在於流程與動作的分工,但是入口卻是一個容易被忽略的地方。即使在很多地方很明白地表示進入後就是要達成某件事,不過仍有可能會在進入後參考某些設定而改變要做的事;而有時會只需要在其他地方處理同樣的功能,倘使把流程跟入口綁在一起又會形成再加工切割的後果。我們必須記得的是:預留好事後切割的空間會比重構結構來得容易而且少很多風險。

在每一個特定功能的設計裡,我的作法都會是:使用入口(有時的確不需要存在)、流程與動作三個層次合作完成指定的功能。(D06的圖也是類似的概念)

2008年2月12日 星期二

K12 替代的作法(3)──定義Use Case與Activity的Interface Method

在Activity List所需要的資訊,當然會有它自己的Name、Description以及對應的Method Name、所屬的Interface。雖然在製作Activity Diagram的同時,Activity至少都會被歸屬到一個Use Case下,但我認為Activity會與多個Use Case對應,所以其間的關係並不是絕對的而不需多加記錄;但是要記錄屬於哪一個Subsystem。


在Use Case的這一頁,基本上還是記錄Use Case Name、Description與所屬的Subsystem,再接下來所要記錄的是每個Use Case的進入點、起始狀態與結束狀態;安排這幾個欄位的目的是希望簡短地記錄一些SRS裡的資訊,以便快速地參考必須的資料。如果有Client與Server多個層次時,每個層次都要定義一組欄位來記錄,因為這裡註明的是Activity Digram裡跨越swimlane動作的資訊。
此時沒有好的方法在Excel裡描述Use Case裡的執行流程,因此暫時不在此記錄而放在其他地方,這會等到後面適當的步驟時說明。

2008年2月11日 星期一

K11 系統的製程(6)──定義Use Case Interface Method

Activity Interface Method是系統功能的入口,而Use Case是使用者操作的入口,對於系統而言這就像是把系統功能再用客製化的邏輯包裝而形成更上一層的應用。在此同樣也需要定義Use Case Interface Method。

與定義Activity Interface Method類似,在這裡需要決定每一個Use Case對應的方法,而且同樣必須每個Use Case使用自己的Method Name。不過還有一點需要特別留意:在Activity Diagram裡如果使用swimlane將系統切割為Client、Server等多個層次時,必須每個層次都為這個Use Case定義方法,這是未來藉由硬體橋樑設計時對另一端的操作定義。

在這裡我們會得到Use Case與Activity的關聯,我們可以發現每個Use Case會使用至少一個Activity,每個Activity也會被至少一個Use Case所使用;這在系統裡會對應真正執行時程式的呼叫關係。此時只需定義到Interface與Method,因為暫時以功能定義作為目標,Package要等到架構設計將之佈置妥當後再安放Interface。

2008年2月10日 星期日

K10 系統的製程(5)──定義Activity Interface Method

在製作Use Case時努力所製作的Activity Diagram其實是為了一個重要的目的──收集全部的系統動作,這在實際的作法是收集所有Activity Diagram的Activity List。之前對Activity所做的分析與重用都是為了得到系統動作的最佳集合。

理想的Activity是每個都對應一個特定目的獨立系統動作,範圍太大會使得一個Activity裡包含了數個系統動作,範圍太小則會令多個Activity才達成一個系統動作;在定義時務必讓它們形成一對一的對應才是理想的設計。此時必須強調Activity的意義是達成Use Case的分解動作,而Activity Diagram是組合分解動作的Use Case Controller。

我認為Activity才是代表系統功能的真正入口,因此收集Activity List之後,就給每個Activity自己專有的method name作為Entry Point, 並設定其所屬的Interface。定義System Interface Method時要參考設計準則仔細思考, 務必把類似的動作封裝在一起不要造成混亂。

記得每個Activity都要一個自己的方法,而不要認為數個動作接近的Activity未來可以利用不同的參數來使用同一個方法,那時設計時才需要去思考的。唯有這樣一一對應才能在執行某方法時肯定那是為了一個特定原因而進入的,我們也才可以肯定在這方法上的變動不會影響到其他Activity。

2008年2月9日 星期六

K09 做事的方法(10)──使用工具記錄減輕頭腦負擔

以前開會時總不喜歡帶筆記本,一些在會議時發派的工作就努力地記在腦子裡於會後逐一進行。年輕時感覺沒什麼不好的,雖然偶而會在主管問起時才驚覺忘記有那回事,不過卻也沒有什麼不好;當然也不會感覺到會議記錄有多重要而視記錄為苦差事。

一方面由於年歲漸長發現遺忘的項目越來越多,一方面也因為領悟到做事應有目標清單與執行內容,那些只要有缺少幾乎都會造成結果的不完整,因此慢慢養成將這些項目記錄下來的習慣。如此一來,除了可以追蹤各個項目的進度之外,還可以快速地提供我手上所有應有的工作項目。

其實頭腦的工作就像是CPU與記憶體,雖然功能強大而且容量充足,但是也偶而會發生想不起來的資料遺失狀況;在系統中為了長期保有執行的資訊,我們會使用儲存裝置來放置重要的資訊,而文字與圖表對於我們正如儲存裝置的重要。我們可以把腦袋裡暫時匯出到記錄裡,一方面可以清除腦中的記憶,另一方面可以期望未來在看到以前的記錄時立即回復到當時的記憶;然而更好的是可以把自己的記憶藉由這個方式複製到別人的腦中去。

人腦中的資料還無法複製,口述雖然快速卻有遺忘的風險,只有依靠足夠的記錄才能確保記憶的傳承。這便是我願意花時間去記錄的原因。

2008年2月8日 星期五

K08 系統的製程(4)──Activity的抽取與拆解

在Activity Diagram裡應該定義swimlane來定義Activity是誰要做的動作,這樣才能在觀看Use Case動作的同時知道各個參與者的動作與控制流向,並可以立即檢視該參與者的全部動作。通常我會用到的swimlane定義有User、Timer、System、DB與Extenal System幾種。

使用Rose製作Activity Diagram時有個好處:所有曾經製作出來的Activity都存放在Use Case View裡,在需要引用的時候只要用滑鼠拉到現在的圖表裡就能使用它。如果在引用時發現有多個Use Case都會使用到某個Use Case裡固定的幾個Activity,那表示它們應該被抽取出來成為一個include Use Case;如果在引用時發現需要的是只是某個Activity的部分內容時,這表示該把這個Activity再作切割,拆解出更適合單獨引用的Activity。

這是在系統分析時很重要的步驟,因為每個Activity代表了一個完整的獨立動作,同時若有相同意義的Activity存在,絕對要去使用它而不能另外再創建一個;而且在應該抽取或拆解的時候就要去做,雖然有點麻煩,但是該修正的地方務必要花時間去修正。這是因為每個swimlane的Activity集合就是它的所有動作集合。

看過不少人使用Visio畫出流程圖來取代Activity Diagram,最大的原因是因為美觀。但是一個純粹繪製流程圖的工具是沒法幫助我們進行上述的系統分析動作的。

2008年2月7日 星期四

K07 系統的製程(3)──Use Case的操作劇本

Use Case定義為系統提供完成獨立功能的計量單位,想要完成一個目的時會有達成目標所需要的分解動作與執行順序,這是在基本觀念裡所提到的規則。在Use Case裡的Activity Diagram就是用來表達這些內容的重要圖表。

每張圖會有一個起點,在SRS裡應記載系統在什麼樣的狀態下,於發生什麼樣的條件時會由起點開始進行;同時也會有一個終點,SRS裡也應註明結束這個Use Case後系統在什麼樣的情況會變成什麼樣的狀態。系統從起點到終點之間的落差,正是在這個Use Case裡應該完成的事情。

動作與流程的描述就如像畫流程圖一樣,動作全部由Activity圖示表示,流程控制則有branch node、merge node兩個再加上parallel line。關於流程控制的觀念大家應該都差不多,不過重點還是在Activity的定義上。Activity定義的是從概觀觀點上的一個完整動作;例如功能中需要列印資料,則Activity可以命名為列印資料,而不需要定義成open printer、print data、close printer三個Activity,因為列印的作一定需要這三個小動作一起執行的。

由於Activity Diagram可以明確地同時表達流程與動作,這是在Excel裡用文字敍述所沒法達到的,因此強烈建議使用Rose製作;如果時間很趕,可以只先畫swimlane與Activity而不畫出流程。即使用文字表達出劇本或是另外夾流程圖圖檔可以勉強表達出Activity Diagram的意境,但是接下來卻會難以完成一個很重要的程序。

2008年2月6日 星期三

K06 替代的作法(2)──Actor與Use Case的關係

由於關係沒有辦法從Excel快速地轉換到Rose裡,基本上在這時我會直接在Rose編輯Use Case Diagram。在Rose上編輯另有兩大好處:一是圖形化的介面易於檢視並釐清各個物件的關聯,一是接下來要製作的Activity Diagram是附屬在Use Case物件裡的圖表。

如果系統的規模很小或者對開發的系統熟到不能再熟,當然是可以直接寫在Excel檔案裡作為記錄。在2007/11起的這個專案由於是重寫舊系統,在爭取時間的前提下就設計了一份表格盡量記下最多的資料,不過當時思考的還不是十分清楚。下圖是根據上面提到過應有的資訊而調整過的表格,把Subsystem、Use Case與Actor的內容與關係都儘量 定義在同一個Sheet裡。

2008年2月5日 星期二

K05 系統的製程(2)──Actor與Use Case的關係

在Actor與Use Case之間的箭頭中包含了二者的使用關係,在UML裡這層關係是使用Use Case Diagram來表達的;我的習慣是以一個Subsystem的Use Case畫成一張圖來表達與Actor的關係。這裡所需要的資訊是從使用者那裡得到的,如果在畫圖的時候感到迷惑就要儘快再與使用者確認。

在製作Use Case Diagram時可以明顯拆解的Use Case要先拆開,該平行列示視作數個Use Case或是垂直使用像include、extend關係的也要確定,接著就依需求拉妥Actor與其能操作的Use Case使用關聯。Use Case大致分為兩種,一種是與Actor有直接關聯的,另一種則是與Use Case有關聯的,這些都會在繪製Use Case Diagram的同時建立在Rose Model裡。

這層是系統直接與使用者有關的最High Level關聯。垂直關係表示系統的Actor各自可以操作哪些Use Case以及Use Case允許被哪些Actor使用;水平關係則表示了各個Use Case之間的關聯。

2008年2月4日 星期一

K04 保持Excel與Rose間的一致

由於Rose與Excel之間的內容並無法藉由簡單的方式百分之百的轉換,所以我們得另外花功夫才能維持二者資料的一致。但是從另一方面來說,採用把Excel內容使用Robot輸入Rose的方法時,如果可以的話盡可能地在Excel上整理資料,等到有接近十成的把握時再做轉換的動作可以有效延後開始維護兩份資料的動作。

如果很不幸地在轉換後發生了改變,維護通常會有兩種方式:一種是將改變在Rose上與Excel裡都做一次,另一種是先在Rose上修改變更並在告一段落時使用SoDA產生對應的段落,再將內容貼回Excel保存。之所以要在Rose上操作是因為把Excel的改變傳入Rose幾乎是無解的,所以不應該在Excel裡操作。

在初期的Actor與Use Case列示出來後,理應要有二者間追溯關係的記錄。不過接著我們會作Use Case Diagram的Refine,雖然可以使用初期得到的對應關係再作擴展,但是基於節省時間的前提,我會等到所有Actor、Use Case都定義妥當時再花時間一次做好。

2008年2月3日 星期日

K03 輔助的文件(3)──用Robot模擬大量UI操作

曾經遇到需要大量建立Actor與Use Case的情況,詢問公司內負責推廣Rational的人Rose是否有提供程式使用的API,答案是沒有。那時就覺得很頭痛,因為要把Excel裡的資料一一建立到Rose裡可是要花不少時間的。

因為“想偷懶”而暫時使用Excel作記錄,如今為了要彌補把資料從Excel搬回Rose的差距,我必須投入時間以敉平之。我把Rose在畫面上最大化後反覆建立與輸入的使用者操作動作並記錄其順序,然後寫一個小程式用JXL讀出使用Robot物件來做這個重覆輸入大量資料的工作。

UI的動作不外乎是鍵盤與滑鼠與鍵盤。鍵盤的動作只有對某個鍵的壓下與放開,有時會有Alt、Ctrl、Shift的組合鍵;滑鼠的動作則僅是指標位置的移動與按鈕的壓下與放開而已。唯一的限制是在輸入Documentation時由於無法直接輸入中文字串,所以必須先切換到Unicode輸入法逐一把中文字元的四個unicode模擬鍵盤操作。

這個小程式幫了我很大的忙,在系統開發的初期可以專心在Excel裡快速建立清單,在建立後再交給Robot立即在Rose裡重現這些資訊。

2008年2月2日 星期六

K02 替代的作法(1)──初期Actor與Use Case清單

雖然Rose + SoDA可以快速地輸入資料並產出自訂形式的報表,但還是有不方便的地方。例如想要邊檢查清單邊編輯的時候、還有需要蒐尋Documentation內的資料等,都必須在操作Rose的同時,再檢查SoDA產生報表;對我而言,這就類似在兩個thread切換。如果可以在編輯的同時就能夠立即獲得需要的資料該有多好?

最初期的需求動作是列出所有的Actor、Use Case並決定Use Case所屬的Subsystem,這是需要編輯的三個對象。Actor與Subsystem需要的資訊是Name與Documentation、Use Case除了Name與Documentation外還需要所屬的Subsystem名稱。那麼就準備一個Excel檔案,建立Actor、Subsystem與Use Case三個Sheet並像下圖這樣建立欄位資訊,接下來就暫時忘記有Rose這件事而把收集到的資訊都全部填入到Excel檔案裡。

在Use Case的那一頁有一欄是要記錄所屬Subsystem名稱,將那一欄用不同的顏色標記以提醒填寫的人要參考Subsystem的定義填寫。

2008年2月1日 星期五

K01 系統的製程(1)──初期Actor與Use Case清單

系統的原始想法都在使用者的腦袋中,他們是沒法自己寫出系統的,所以才會找廠商協助開發他們想要的內容;正因為如此,我們必須經由需求訪談來盡量發掘使用者的想法。不過使用者通常只能夠概述要系統幫他們完成什麼樣的工作,一方面沒法明確描述系統功能,一方面也沒法有條理地整理需求。

需求的訪談就是協助客戶更完整地描述系統的需求,並在收集資料之後加以整理與分析。初期得到的資料內容應該有Actor List、Use Case List,以及Actor vs Use Case的使用關係表;而在這裡Use Case指的是System所提供的所有功能。
系統的規模到一定程度後Use Case會多到難以管理與維護,此時會建議定義一些Subsystem並將Use Case依內容特性予以歸類。在這裡的子系統會要求在特定的系統架構之下可以單獨執行的功能集合,當然它們是可以有依賴關係的,但是基本上是聚合力高的Use Case放在同一個Subsystem裡。