顯示具有 [L] SA作法 標籤的文章。 顯示所有文章
顯示具有 [L] SA作法 標籤的文章。 顯示所有文章

2008年3月6日 星期四

L19 系統軟體架構的層次(2)──Package的各種定義

簡單地用一張圖來表示Package使用上的定義層次,由左到右依序為範圍大到範圍小的,每一個物件都可以使用自己層級與往下層級的物件,除了Main Flow、Use Case會被限制只能存取到下一層。請記得每一個圖示都應該對應一個Interface的宣告,這是我偷懶而沒畫出來的。

MainFlow是使用者執行同時掌管Use Case是否進入的Package,Use Case與Activity對應的是系統分析時Use Case、Activity的進入點,,Module則是在Activity裡合作完成工作的各個組織。

MainFlow、Use Case、Activity與Module是屬於專案應該定義出來的部分,而Component與CommonAPI是屬於通用的部分所以列在下一行。後兩者同樣根據L07的reuse基準定義出不同層級使用的元件與函數。

2008年3月5日 星期三

L18 一層層地依序鋪陳系統結構

在作系統功能分析時,一開始會定義出與初始化系統有關的,因為我們得先準備好系統才能去使用;然後會接著定義使用者操作系統的相關功能,讓系統發生功用;再來會分析出操作系統的同時會不會產生對使用者回饋的系統事件;最後則依照需要提供給使用者定義的系統參數來定義參數的功能。

這是目前我在設計系統時採用的四段分析與設計,讓系統的每一層就像IC晶片的腳座與針腳,一層層地向上堆疊到最後得到完整功能的系統。前面說明的內容大致上只適用在第一層(初始化)與第二層(操作系統);如果系統有讓使用者註冊與客製化的事件或是客製化的參數,就還要分析那些功能應該放置在哪些Module,同時定義出它的詳細內容並記錄。

與客戶討論定義出來的Use Case其實會因分析的過程而有所增減,切記要把所有的變更都對應記錄在文件裡,只要少做了一個就會造成系統與文件的脫節,而且未來絕對很難被找到。當事人應告誡自己不要因偷懶讓少做的事造成文件的失真。

Use Case的變動也該與客戶溝通以取得共識,作適當的調整。雖然需求確認後系統會比較好做,但是我們在分析與設計時都時常發生遺漏與錯誤,又怎能期待客戶光是討論就可以得到完整的功能?為了讓系統隨時符合那些隨時會增訂的需求,還是在分析設計時作好一對一的對應吧。

2008年3月4日 星期二

L17 至今還只是設計Package Interface!

曾看過一篇文章,作者說到他根本不想學其他的方法論,因為只要給他資料結構就可以用DFD設計出系統!這是最快速做出系統的方式,因為只要把完成功能該做的動作全都做到就不會錯,也不需要去管Method要怎麼安排、Class與Package要怎麼佈置。

為了reuse,所以採用了提取相同部分的作法,從最小的動作(Method)開始、Method裡使用的固定數值直到集合型態的Class、Package等等都是可以切割並抽取的單位;為了彈性,每個切割的分隔還可以加上替換的機制(常數的判斷或Interface的宣告)動態更換其中一段的執行動作流程。

而到目前為止所做的工作只是Module層級的的佈置與系統分析相關的Method宣告,主要做的事是決定達成所有功能的全部方法,並將方法一一佈置到對應層級的Module Interface。由於Interface只是Method宣告的空殼,所以在review的同時可以快速地調整Module的佈置與Method的所屬interface;同樣的動作若等到Class與實作都出現時再動作,可就要再多花更多精力。

Interface後對應的是達成特定功能的Package,依照設計原則定義的Interface應會具有適合重用與維護的特性,也更適合再進一步套用Design Pattern增加彈性。這樣的概念也會延續到同樣是集合方法的Class,讓Interface的設計特性延續到更細部。

2008年3月3日 星期一

L16 Use Case與Activity的追溯關係

在Rose的Logical View建立Use Case Diagram後可以直接查詢到任一個Actor或Use Case的全部使用關聯,但是即使畫了Activity Diagram與Sequence Diagram也只能使用SoDA的條件篩選功能來查詢到Use Case對Activity以及Use Case Interface對Activity Interface全部的使用關聯,而沒法在Model上快速地直接查詢。

在定義Use Case Interface與Activity Interface的時候,如果明確地限制了它們所在的Package,就可以從程式碼快速地得到Use Case對Activity之間的使用的關係。

從Activity Method找使用它的Use Case Method時只要選擇Method Name再執行References就能夠得到所有使用它的Class & Method,只要留下Use Case所在的Package就是我們要的答案。反過來,從Use Case找使用的Activity時只要把該Use Case Method內所有與流程有關的方法內容剪賠到一個文字檔,就能找出所有的Activity。

在需要繳出水平追溯與垂直追溯的場合,可以使用Eclipse的JDT插件來分析程式碼。定義好Use Case的Package集合與Activity的Package集合,依序進入每一個Use Case Method一步步地列出其中定義在Activity Package的物件名稱與方法,就可以產出Use Case vs Use Case、Use Case vs Activity與Activity vs Activity三份追溯關係表。

這個工具搭配JXL產出為Excel檔案就是保證100%正確的追溯關係表,未來有任何程式碼的改動時只要再重新執行一次又能得到當時最新的結果。

2008年3月2日 星期日

L15 Interface Method需要記錄大量的資訊

Method是真正在做事情的單元,所以它使用的資訊也是最多的。Class與Package只能說是分類Method的集合標準,只會帶有它自己的規格說明與結構的關係,前者會成為標準的Documentation,後者則應該使用Class Diagram加以描繪。

在L11的Excel表格裡我們可以發現在Method的宣告就具有名稱、動作規格、傳入參數與傳回值等資訊,這些都必須一一詳加描述,才能夠讓接手的人做出符合期望的內容。其中的動作規格可以取得Activity Documentation轉到Method的Java Doc作為說明。

在方法的執行需要上,Use Case Interface Method需要Activity Diagram與Activity Interface Method List,而Activity Interface Method會在SD的階段才加以設計,但需要的內容也不外乎流程與動作的組合資訊。在Use Case Interface之外,會有開始執行該方法的時間點(Entry Point)、進入前的系統狀態(Precondition)與執行後的系統狀態(Postcondition),這些都必須在啟動系統的主流程裡加以考慮與設計。

以上所有提到的Method資訊應該全部都要說明的,但是大多數人會認為我全部都知道了為什麼要再浪費時間寫出來一遍?面對一個沒有說明的Method或許還能從少量的程式碼反推,但是面對一群沒有註解的Method時?再更慘一點,面對的是一大堆沒有分類好的Method散落在許多Class與Package時呢?其至連Class與package都沒有依據準則分類時,更是慘不忍睹。

想像一下新進人員與現在的自己對於系統認知的差距,那正是需要記錄的資訊。

2008年3月1日 星期六

L14 替代的作法(5)──Use Case的執行流程

Sequence Diagram當初對我造成不小的困擾,一部分是因為不確定它應表達的深度,另一部分是因為一張圖只選擇一個劇本作為表達;這令拿到全部Sequence Diagram的人不易明白Use Case的完整作法。

在流程裡所做的動作只有三大類:執行動作、設定資訊與取得資訊,我的作法是以這個三個基本分類來切分並定義所有Activity,並隨之對應到一個Interface Method。在沒時間製作畫面的時候,可以先定義好Use Case對應的Interface Method,然後每個方法都用一個文字檔案來儲存說明。文字檔案的內容可以像寫程式般把Activity Name或Activity Interface Method Name嵌在裡面,前面再用程式註解開頭。

例如:
// if (印表機進紙狀態 == 沒紙) {
// 印表機進紙
// }
// 印表機列印
// 印表機退紙

註解時盡量把流程控制的作法交待好,未來實作者的工作就是依註解替換為Interface Method,並驗證程式的執行邏輯是否正確。如此一來Use Case Method內就只是純粹的方法呼叫與邏輯控制,這樣也使得註解的效用等同於Activity Diagram,既帶有流程圖的意味,在寫程式時保留下來同時又能作為程式註解用途。

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

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