2007年9月30日 星期日

E22 設計的終點(3)──快速組合出商業功能模組

對我來說,SOA的想法實際上與Flow Engine的想法是幾乎相等的。作法並沒有什麼困難,但成敗的關鍵也同樣在於Web Service(等同元件)的設計想法;唯有封裝完整且功能齊全的獨立元件,才能滿足SOA想法的需求。

設計一個通用的Flow Step,可以依照傳入的id搜尋對應的Web Service執行,並可以將Context與Data Model作雙向的轉換(參考E21)。在Flow Engine裡的所有Flow Step就不再依class name呼叫實作,而是使用這個通用Flow Step並設定Web Service id。

當我們拿到Use Case需求後,首先還是要先分析完成這個Use Case需要哪些動作,以什麼樣的順序執行。在Flow Engine上就依執行的順序先定義好執行的框架,接著依每個動作的目的找出最適合的Web Service並將其id設定在Flow Step上,最後再定義好使用的傳入條件與傳出結果便算完成。

與架構設計的Controller概念比較,設計方式是不是沒什麼差別呢?

2007年9月29日 星期六

E21 SOA的實驗(3)──應用Context與狀態放置達成SOA

我想的概念很簡單:先從狀態放置區找出還沒有執行的Flow Step,再從Flow Engine的設定上決定Flow Step的執行先後關係,接著就依Flow Step的內容直接找Component 或Web Service完成動作並註記狀態。

以這個目的來思考,我們就得先設計好Context與執行狀態的存取,唯有資料有便利存放的地方才能夠快速且正確地使用它們;接下來的課題就是如何讓Context與執行狀態與Web Service的要求的XML迅速地作轉換。

我的作法會是根據每個Web Service宣告一個實作自Basic Data Model的資料模組來對應,在使用Web Service之前固定做資料設定的動作後,生成XML傳入;使用後傳回的XML依前述動作反著執行讓最新的資料更新回Context,就能夠讓系統繼續運行了。

2007年9月28日 星期五

E20 SOA的實驗(2)──在Context規劃執行狀態區

在最初的設計,大多都只會以一個變數來存放現在執行到哪一個狀態或結果,並依此來控管功能的執行結果。可是這只記錄了一個結果,對於執行清單與歷史都一無所知。

不管是不是使用Web Service,我們都應該在Context裡放置功能執行時所有使用到的元件或Web Service的執行狀態區;如此一來每個步驟除了可以把結果放入之外,還可以在執行前先判斷該步驟是否已經執行過。在這種設計之下我們將可以隨時追蹤Context所有執行過程的歷史與狀態,同時也可以再加上設計把所有未執行的動作同時發送給Web Service再依結果更新Context。

預留一個集合存放指向所有使用的Context物件,對於整個專案來說只要存取得到集合就具有監看所有已啟動Context的執行狀態及內容,甚至可以直接改變Context的內容來對該執行物件產生決定性的影響。

2007年9月27日 星期四

E19 SOA的實驗(1)──將Component包裝成Web Service

當Component沒有自己的預設行為,完全依靠外界傳入的設定與資料來決定它的執行內容時,就很適合再定義為Web Service。

Component傳遞的是物件,Web Service傳遞的則是XML字串。只要定義一個WebServiceInterface,在其中定義一個方法,其實作是將傳入的XML再成為Data Model、執行狀態與Environment,並轉呼叫Component的方法將這些物件傳入;最後執行結束或是有Exception時依照固定規則註記在執行狀態裡,最後把Data Model與執行狀態回復為XML傳回即可。

不管是元件或是Web Service,其目的都是將特定目的的動作封裝在固定範圍裡,只有傳入的資料與設定會影響內部運作的邏輯,執行結束再傳回執行的結果與改變後的資料供上一層的Controller來判斷與使用。這是必須掌握的原則。

2007年9月26日 星期三

E18 Project Controller(4)──Runtime Environment

把元件的觀念放大到系統,此時檢視所有的輸出輸入物件設計:Context等同於CompomentModel、Flow Engine等同於ComponentController、Flow Step等同於ComponentAction、傳回值的作用相當於拋出ComponentException。最後需要的是作用等同於ComponentProperties的Runtime Environment。

為了要讓每次的執行都是獨立的,在執行之前應該要有各自的初始化動作,另外就是提供執行時需要系統設定的內容存放的地方,這些就是Environment的存在意義。使用Environment時,可以在每次的執行方法中傳入,或是同樣包含在Context裡頭。

Environment的設計同樣應該是介面,依需求與設計陸續加上所需要的參數存取方法;實作的時候一樣繼承Basic Data Model,並衍生出以字串的保留與重現動作。有時系統的參數是存放在特定的機制之下(例開發Eclipse的plugin時會有它自己用的Project Properties),這個時候除了實作特定機制的用法外,還要再做出一組基本類別的以達到動態儲存與回復的目的。

設計裡的傳遞物件最好不要使用singleton的設計,也不要用方法設定到Flow Engine或Controller中存放再取得,以避免相依性過高,切記要在使用之前才傳入該次所要使用的。

2007年9月25日 星期二

E17 Project Controller(3)──Controller處理狀態的保留與重現

Controller實作的時候,我們大多會宣告變數(少數會用物件)來暫存執行時的狀態,這些大多發生在程式裡,即使在設計Flow Engine也是如此。這樣的設計會使得執行狀態只能在同一部電腦內被控制。

宣告一個類似Context的執行狀態存放區,裡面記錄著執行Flow Engine時的定義檔全部有哪些步驟,各個步驟是否已經執行過而且結果為何,同時讓它像Context那樣可以輸出為字串並再生回物件。這樣一來我們就有機會做到在這裡做到一半的流程,傳送到另一部機器繼續處理(當然要包括Context一起);或是每做完一步驟就將之儲存下來,如因故中斷時可以叫起來接著再做。

這個概念也如何Context般,可以使得測試與除錯變得更加方便。可以想像一下,在一個重要的測試動作前如果必須連上客戶大型主機,又要準備特殊資料時的不便;在花時間準備一次資料後,記錄下該動作執行後的狀態與Context,就能夠只針對指定的Flow Step作密集的測試。

執行狀態資料區可以附屬在Context裡,每次執行前都初始化其狀態。執行狀態跟著Context搬移將能夠更快速地取得與對照。

2007年9月24日 星期一

E16 設計的終點(2)──快速應付Controller的改變

實作Flow Step的動作後以Flow Engine定義來串連,其實這就像我們寫的程式在邏輯上呼叫已經完成的API一樣,道理都是相同的;但更進一步的好處是我們可以使用外部定義檔來決定執行的步驟與順序,而不需要更動到任何程式碼。

在只需要改變設定檔案的情形下,就適合使用編輯器來編輯檔案的設定內容。應用文字編輯器是最差的選擇,但那也比改程式要好上非常多;理想的作法是根據用途來製作特定的編輯器。像Flow Engine的定義就可以使用類似繪製流程圖那樣的編輯工具,只要定義好每個圖樣所代表的Flow Step,就能夠以圖形方式定義好執行的流程。

Flow Engine在使用Flow Step時,可作成兩種執行方式:一種是直接依Class Name來生成Flow Step並呼叫執行的方法,另一種則是取得Component ID再到網路上搜尋適合的Web Service來執行該動作。如此可使得功能執行的流程變化更為彈性且方便。

2007年9月23日 星期日

E15 Project Controller(2)──Controller Flow Step

根據商業邏輯的步驟,我們同樣要將聚合力較強的動作合併在同一個Flow Step裡,較弱的則分開到不同的Flow Step執行。這是專案裡流程設計的基本。Flow Step裡通常會有達成功能時自己的控制步驟,在這時可以用單一Controller的角度來設計內部。

每個Step Class在執行的時候都會傳入一個Context,在裡面取得傳入的物件,並將執行後需要傳出的物件放回;執行後的狀況以傳回值通知Flow Engine來決定下一個該呼叫哪個Flow Step。Flow Step裡所有的傳回值都應在Flow Engine上有相對的定義。

所有Flow Step都實作同樣的介面,這意味著每一個Flow Step可以任何一種次序來執行,只要我們在定義Flow Engine時注意Context內物件使用的先後關係,就可以自由定義執行的順序。Flow Step在設計時以完整達成一個特定功能為目標,因為這可以符合再進一步使用Web Service的要求。

2007年9月22日 星期六

E14 Project Controller(1)──Controller Flow Engine

最基本的Controller很自然地就只是一個Class,處理的流程與每個步驟都寫在裡面;在較好的設計下,我們應該得到處理的流程與步驟動作分開的結果。

在處理流程部分,雖然已將內容侷限在純粹的流程控制,但是到底還是以程式碼來實現,任何的內容變動都會造成影響而必須有後續的分析與測試。理想的設計會在這個部分以Flow Engine框架讀入使用者的定義檔案,再依內容來實行控制。

Flow Engine的控制概念,是定義通用的Flow Step介面,動作被封裝在實作該介面的類別裡,執行時指定第一個動作的Class進入執行,介面的執行方法會有傳回值,定義檔裡會定義每個動作Class執行後的所有傳回值各要跳往哪個步驟去執行。依此概念執行到沒有下一個動作Class為止。

在流程生命週期中,傳入的Context是負責存放Flow Engine內所有輸出輸入物件的唯一資料集合。Context對應Flow Engine的關係,就有如Data Model對應Controller的關係。

2007年9月21日 星期五

E13 設計的終點(1)──快速應付Data Model的改變

Project Data Model直接繼承Basic Data Model其實也只是個快速的作法,當類似的Project Data Model會在多個專案出現時,同樣也要在兩者之間再加上一個中間性質的Data Model作為吸收改變的設計。

如果改變的是存放的屬性,我們可以變更存放那個資料的類別存取方法;如果改變的是資料模組,我們可以增減或改變類別的名稱;如果改變的是類別放置在Context內的群組與位置,我們可以改變Context存取這個類別的存取方法。

經由一層層對應管理資料模組的設計,我們面對改變時只需要確認屬於哪一個層次,接著就在屬於那個層次的類別介面修改存取的方式,並且將改變封裝到類別裡頭,由該類別與其繼承的類別共同合作以完成符合該變更的修改;加上Basic Data Model已經實作好存取資料的功能,因而可以只注重存取的控制。

即使全部都只是Data Model,實際在設計與使用時還是能夠依照定義給予不同層次的定義。設計好具有意義的層次後,改奱的影響就很容易界定出範圍來。更重要的一點是藉由Model名稱定義生成Data Model的機制可以讓物件的生成更為機動與快速。

2007年9月20日 星期四

E12 Project Data Model(4)──Model Service

系統裡的Project Data Model可能有很多種,其中某些Data Model的存取需要參考其他Data Model,存取的規則造成了他們之間的關係,而系統內這樣的Data Model關係也可能發生不少。

Project Data Model之間的水平使用關係,我們可以利用Model Service來加以封裝。每一個主要的Data Model(被存取資料的)都定義一個對應的Model Service類別,其他需要參考的Data Model則使用參數的方式傳入呼叫的方法,方法則根據呼叫時的參考規則實作並加以封裝。

一開始受到“Data Model可以含有存取邏輯”的影響,硬要把需要參考其他Data Model的動作寫進主要Data Model裡,卻發現不管怎麼定義都有不適當的地方,最後才終於領悟到要在Data Model之上再加上一層可以存取不同Data Model的Data Service才能夠妥善地處理。

2007年9月19日 星期三

E11 Project Data Model(3)──Context內容的保留與重現

這個功能的開發原本只是選項,因為這個想法與增進開發速度、應付未來改變都沒有什麼關係;但是實作這個功能卻能夠增進偵錯與維護的效益。

有錯誤報告的時候要附上能夠重現錯誤狀況的所有操作步驟,這是所有人的共識;這是因為有固定的步驟可以展現錯誤,在修改之後依舊可以用同樣的操作來判斷是否已經排除問題並檢查是否有其他衍生問題。但是在出現問題的關鍵操作動作之前所有做的事,都只是為了把進入關鍵動作所需要的所有資料準備好而已。

擁有這個功能後,發現錯誤的人可以在錯誤動作的前後都匯出一份包括Context所有資料值的檔案。負責修改問題的人應用工具把資料檔案再回復為Context並呼叫錯誤動作的方法,就可以立即開始測試;甚至有的時候只要觀察Context檔案的內容就可以發現端倪。

如果把匯出匯入的動作再細分為先針對XML字串的話,這將會成為Web Service輸出輸入所用資料模組的XML標準;因為Web Service元件收到XML後也是先重現為Data Model再執行,完成後再將Data Model轉換為XML傳回。

2007年9月18日 星期二

E10 Project Data Model(2)──Context

專案裡使用的Project Data Model實體一定會有很多個,如果要個別記得每一個實體的存在位置,這又是另外一種痛苦。應用集合與物件的想法,所以我們需要為專案定義一個存放所有資料物件的集合區域──Context。

按照使用範圍與生命週期的考量,Context裡至少有與程式共存亡的區域(Class)以及執行功能時才需要的資料區(Class);考慮所有Project Data Model使用與存在的時機定義相對的區域並在裡面宣告放置的變數。由於每個物件的存在都應有它自己的意義,於是符合動態流程的每個時間點都該有對應的使用資料區。

接著由底層的區域開始,每個區域都針對其內部存放的Project Data Model定義存取方法;依此逐步往上,遇到內部有放置其他的區域時也另外定義存取方法。經過一層層的封裝與定義,最後就形成可以從中取得所有runtime資料模組的Context。

全部的程式集合起來會成為系統,所有的資料模組集合起來會成為Context。我們可以把Context想像為一個對應系統的最大Data Model。

2007年9月17日 星期一

E09 Project Data Model(1)──向上的Data Model延伸

雖然Basic Data Model已經涵蓋了我們放置資料的需求,但那只是最基礎的set與get動作;在Data Model需要放置的資料數量很多時,每種資料的存放都會有各自的方式。如果我們不再為專案使用的資料包裝一層方便操作的存取方法,那麼撰寫程式的人必須去記得每一種需要資料的存取法。

抽取與封裝的動作,除了把共用的部分放到通用的地方之外,另一個的功能是把一些較複雜的邏輯隱藏在裡頭,讓使用的人只需要記得呼叫的入口就能正常使用。只記一個入口當然要比記數條規則輕鬆且不易出錯;我們只需要犧牲一點人力去包裝這類的規則,就可以讓所有撰寫程式的人在專案裡所有可套用的地方節省開發的時間,同時又把未來可能改變的影響封裝起來,這鐵定是划算的。

設計時把適合的資料定義在Project Data Model裡,同時為之準備getter與setter存取方法,記得要逐一宣告好而不要為了快而合併或短少。完整定義後的Project Data Model就可以提供給設計人員接著使用,實際上則繼承一個可以對應儲存方式的Basic Data Model直接使用元件提供的存取功能。這麼逐一把所有資料設計存放的資料模組後,就具有一組完全符合專案使用需求的Project Data Model了。

另外有一個重要功能必須同時實作出來:Project Data Model需要根據存放在Basic Data Model的某個值來產生該Project Data Model類別的實體。這種以Factory方式動態產生各種不同Data Model實體的功能將會讓專案的使用更加便利。

2007年9月16日 星期日

E08 Basic Data Model(3)──資料通用編輯器

雖然我們可以直接打開檔案來編輯Data Model的檔案,但是大多使用者都會希望可以有個UI編輯器。使用UI編輯器的幾個好處是用視覺化的畫面增進美觀、限定輸入的選項避免放錯值、用內定的格式存到檔案防止格式錯誤時什麼都讀不到。

雖然檔案的儲存格式有好幾種,但幸運的是我們已經做好對應各種檔案的Parser,而且都同樣地產出Basic Data Model;所以我們只需要做一個可以編輯Basic Data Model的通用編輯器,就能夠處理所有有支援類型的檔案編輯。只需新增一種編輯器就能應付所有資料模組,這種作法可以增進許多開發速度。

編輯器需要的功能大致上是起動、讀檔、顯示資料、編輯資料、存檔與結束,需要根據資料動態產生的是顯示資料與編輯資料。name可以顯示在編輯欄位的提示,value自然是放進欄位的值,我們可以利用註解來放置一些輔助的描述,像詳細提示文字、編輯欄位的種類、合法的輸入值等等,讓編輯器程式處理,如此一來可以讓編輯頁面更實用。

作為使用Basic Data Model與Basic Parser的Component,它的功用是資料模組的通用UI編輯器。現在有三個基本Compoent。

2007年9月15日 星期六

E07 Basic Data Model(2)──向下的基本實作

Basic Data Model做出來後,下一步是依照前面選用的儲存方式,繼承Basic Data Model後逐一定義與設計對應Data Model的介面與實作類別。實作的用意在於把對應的存取方式包裝在getter與setter的方法裡,讓呼叫者毌須知道實際存取的方式而能夠拿到自己想要的資料。

再來要定義一組Basic Parser,它的主要功能是讀取檔案成為資料(load)與將資料儲存到檔案(save)。同時往下要定義各種Data Model的Parser,使用I/O的方法取得檔案的內容,同時依照資料結構放到設計時指定的位置;反之亦然。這麼一來我們已經設計好每一種Data Model對應的存檔與讀檔動作。

Basic Data Model與存取它的Basic Parser是資料模組的根本Component。為了讓其他人可以快速地學習使用,放入元件庫的元件一定要做好API說明與範例程式。好了,現在我們的元件庫裡有兩個基本的Component。

2007年9月14日 星期五

E06 Basic Data Model(1)──資料存放的根本

設計後的實作因為有專案的規定可以遵循,所以可以發揮與需要說明的地方並不多。從這篇以下的內容,將會著眼在使用元件設計與架構設計想法所得到的觀念所能夠衍生出來的實作應用。首先,就從最底層的Data Model看起。

Data Model要可以在所有元件與系統間通用的話,最省事的方法就是定義出一組Basic Data Model的介面與實作,因為這麼一來所有Data Model內容的基本存取方法都會相同而不必另外設計,傳遞之後的資料都可以立即存取。

設計Basic Data Model時,我們要先思考要對應到哪些儲存方式。現在比較通用的儲存方式有XML、text、properties、Excel與Database Table(其他的我不熟),事先分析各種資料儲存的類型與方式,設計出一個符合各種儲存方式的Data Model;有了能夠裝填所有資料的容器後,接下來就是要思考如何把檔案裡的資料裝入容器。

註:我選用的是XML的結構,每個Data Model可以有name、value、comment,同時有一組Attribute與一組child集合;其他種類的資料使用對應的方式放進這些變數之中。

2007年9月13日 星期四

E05 實作的記錄──寫下撰寫程式時的想法

不管是系統層面或是元件設計,設計的人都開立好每個層次的介面規格與類別名稱,實作的人只要依據類別、屬性與方法上的註解寫出符合規格的程式碼即可交差。表面上看起來似乎單調又無聊,但事實上要比表面上的有趣一點。

不管是在系統或是元件,設計的都只是框架與訊息呼叫的順序,實作的人需要用真實的程式碼來實現所有的功能。在使用其它公司提供的元件時,通常會有人先寫好prototype範例,實作時只要依照內容撰寫;但是prototype重視的只是功能的達成,在狀況的控制上相對地不夠週全。在設計時因沒有實際去做,光憑想像也無法妥善地控制好一切;這時就需要實作的人去補齊狀況的控管。

還有另一種情形是設計的人指定了要使用的其他元件,但是並沒有提供範例程式。這個時候實作的人就必須在設計的框架下,找出正常操作元件的確切方法並產生程式。即使只是依照邏輯撰寫程式時,也得依照專案規定,找出系統提供的底層API來呼叫以完成動作。

無論做了什麼動作,實作的人應該在程式之間夾上註解來說明當時的想法、作法、碰過的一些狀況與為何決定這樣實作的經過,往後接手或維護的人才能夠立即知道當初為什麼要這樣做。不用說也知道,當初我在維護系統時看到的鐵定是沒有註解的純粹程式碼,而且沒有人記得為什麼要那麼寫……。

◎系統的目標:

2007年9月12日 星期三

E04 實作的開始──Code Generation

設計的內容裡有許多的Package、Class與Class內的attribute、operation,運用UML工具提供的功能可以直接把設計內容轉變為程式框架,開發人員要做的只是根據開發指引、設計文件與註解內容填入適當的程式碼,通過單元測試之後就可以暫時收工。

雖然好一點的UML工具提供了Design Model與程式碼的雙向同步,但是強烈建議絕對不要在實作階段修改程式後再同步回Design Model。系統的設計是立體的,Use Case與架構設計組成了水平面的X軸與Y軸,專案與元件的向下使用關係則是Z軸,每一個程式、方法或屬性都有它應在的位置與該做的工作。

認同每個物件與方法存在的位置都需要評估,那麼我們可以明白任何的變動也需要先追溯其影響再決定怎麼做才是最適當的。撰寫時雖然可以直接修改,短期內似乎可以解決問題,但沒有人敢保證未來不會發生別的問題。

把設計轉出程式框架之後,我們需要的是日後有改變設計的狀況時,可以保持已經撰寫好的程式碼又能夠把新的設計放進程式的功能。選擇具有這種功能的工具,減少改變設計時的異動會有助於養成先設計再撰寫的習慣。

2007年9月11日 星期二

E03 實作的準則──Coding Standard

在結束設計進入實作之前,為了維持所有撰寫程式的產出有一定的風格與使用規則,這時必須有一份Coding Standard供所有程式人員作為程式實作的遵循規則。

Coding Standard的規定範圍甚廣,從命名規則、匯入宣告、註解內容、撰寫風格、甚至連括號的位置都會有所規範,其用意就在於專案裡任何一個人都能夠立即看懂其他人所寫出來的程式。我們可以想像命名方式不同時另一個人還得多花時間去明白一些很基本的東西,這都會是無形的資源浪費,同步好基本想法後,專案成員就可以投注更多心力在於系統的功能開發。

接著應該會有通用API文件,瞭解並熟悉這些通用API的使用可以快速地組成需要的小功能;在不清楚有哪些通用API的情形下,會時常發現到處都會散落著有同樣功能的小方法,如此一來呼叫的使用關係無法收斂,也降低了程式碼的共用性。

再上一層要有通用元件的使用文件,讓開發人員依照設計的要求傳入正確的物件及變數,並作正確的判斷。API層級的所有文件,都是要讓所有人知道如何使用基本的功能與元件來達成設計的內容。

經由規範與準則,我們可以同步專案中所有人員的基本想法與產出水準。

2007年9月10日 星期一

E02 實作時由下往上

在妥善的設計之後,其實要從中任擇一段開始開發都可以,但是還是按部就班地從最底層開始實作會比較適合。其中一個原因是在我們的設計裡,呼叫都是往下層進行,在確保下層程式都已經完成的同時,我們隨即可以對現在開發的程式進行測試。

不過我認為最重要的原因是由於系統是由上往下的設計,下面的變動影響是往上層擴散。如果一開始就在底層實作時發現設計階段一些忽略的問題,都還來得及馬上修正而不用擔心向上的影響;反之如果從上往下實作,卻在最底層的重要元件發現問題,改完之後望著一大堆受到影響的程式清單,心裡大概是欲哭無淚的感覺。

先寫上層的程式還有一個小缺點,就是在單元測試時如果使用的下層程式還沒準備好,就必須先準備一個假的回應程式。要多做一個物件,那個動作就必須花費一些資源,當然能省的地方就儘量省下來。

2007年9月9日 星期日

E01 使用OOAD開發就可以提升軟體品質?

在軟體業裡似乎流行起魔法,謠傳說只要公司用OOAD技術開發就可以大幅提升軟體品質或是減少開發時間等等的,聽到的人都感覺很興奮。但是OOAD本質上只是一種設計方法,即使應用了方便的工具還是不見得有希望有的成效。

設計最重要的還是心裡的想法,方法與工具只是輔助落實心裡想的使之可以更詳細表達出來,對於設計內容並沒有實質的幫助。一名把整個系統視為一個大Component來開發的人,不管用什麼方式都只會產出得到一個大黑箱的設計,完全不能期待換成OOAD會有什麼不同。這應該是我們最基本的認知。

不管用哪一種方法來設計,確認好Data Model、架構水平層次與垂直使用層次,並加上應付改變的設計;然後經由不斷地review、討論與修正,逐漸修正為最適合這個系統的彈性設計才能提升軟體品質。再經由包裝獨立元件的軟體工廠挑選適合的元件快速組裝底層動作部分,未來可以將設計重心放在商業邏輯的控制,以此來減少日後的開發時間。

提升軟體品質的動作其實是耗費時間的,但是可以省卻的是設計不良時維護的痛苦,若能再加上提供適當的reuse元件來減少底層部分的設計,在第一個專案時或許感覺不到改進,但是從第二個類似專案起就可以開始節省開發投入的資源。

當然,必要的前提是我們得保證軟體設計內容的彈性與品質才行。

2007年9月8日 星期六

D28 細部設計的流程(Model)

在元件設計的階段裡,是將局部的功能需要以類似一個小型系統的方式加以設計。記錄下來的物件關係模型如下面附圖。流程與動作的主軸與基本觀念是一致的,但是Properties的輸入由ComponentImpl來使用;ComponentController使用的Component Model因為封裝而改由ComponentImpl傳來。

◎一個ComponentImpl由一個或一個以上的ComponentController組合而成
◎每個ComponentImpl使用一組Properties與一種ComponentModel
◎每個ComponentControllerl有一個或一個以上的ComponentAction(可能沒有)
◎每個ComponentController有可能傳回Return Code(可能沒有)
◎每個ComponentController都應該定義無法處理的Exception狀況(可能沒有)
◎每個例外狀況可以使用其他的ComponentAction或經由ComponentImpl拋出去註:這裡的Component也有可能是一段程式碼。


每個Component在設計時都有Class Diagram與Sequence Diagram,設計的同時每個Class都要定義屬性與方法,同時附上註解。Class會存在於Package(通常等同於Component的範圍),所以每個Package也會有一張Class Diagram來描述有哪些Class。

追溯關係則至少有三種:Component Controller與Component Action的使用關係。此外,訊息、參數與例外的內容應有清單與影響的關係追溯。
◎系統的目標:

2007年9月7日 星期五

D27 物件關係追溯的極致

現在想像一個Basic Data Model方法的內容需要修改,在我們的設計裡資料模組是所有元件與Controller使用的物件,所以我們必須重新測試系統所有的功能。這樣對嗎?只追溯物件使用的關係,的確只能這樣處理,事實上修改物件的一個方法時,應該只要確認那個方法被哪些物件在哪些方法裡使用,再往上搜尋所得的結果才是真正的影響。

在改變後為了確認所有被影響的動作都是否正常時,會因為只是物件層級的概略追溯而造成錯估真正的影響範圍,會付出比實際影響範圍超出許多的不必要測試之類的資源浪費。一個系統的在測試階段的問題單很可能上千張,如果每個問題的解決都或多或少地浪費了一些資源,累積起來到專案結束時總共有多少呢?

然而記錄得越詳細,所需要的資源的資源也會比較多,這時我們需要便利的追溯工具來減輕負擔。不要使用程式開發工具裡的追溯,因為層次一多,尋找的次數與內容也相對增加很多。在設計的同時其實使用關聯就已經存在於Design Model裡,只要有相對的工具可以便利地列出指定物件的追溯關係,這樣一來就方便許多。

2007年9月6日 星期四

D26 物件關係追溯的意義

每個物件在系統裡都有其存在的意義,也有與其他物件互動的關聯。追溯就是記錄物件與其他物件使用的所有關係。

一個物件所負責的動作或是處理邏輯因需求的變化或是發現錯誤的修正而有所改變時,都有可能連帶到影響使用它的其他物件;影響連帶地使上層物件有可能被改變,又再造成上一層其他物件可能被影響。如此循回下去,找出所有會使用到此物件的連帶關係。我們必須測試過使用關係裡的所有物件,才能保證這次的修改除了解決現有的問題之外,沒有再形成任何其他的問題。

有的時候我們需要把某個功能或物件獨立出來使用,這個情況我們需要知道往下使用了哪些物件,所以要從上往下尋找。以一個物件為中心,向下找出它使用的所有關聯物件,與向上找出會連帶使用它的所有關聯物件,就可以定義出它的影響範圍,這是每位從事軟體工程的人最基本的思考模式。

以自己的經驗來看,身邊的人會認真思考追溯關係的實在很少。工作上接觸的外國人士,像香港與新加坡,對於影響追溯的記錄追蹤相對地積極許多。

2007年9月5日 星期三

D25 追溯關係(3)──Package, Component & Class

在Rose Model裡,只要我們建立了物件與物件之間的關聯,那麼不管是在Rose的畫面或是SoDA產生的文件,都可以追溯到使用自己的物件與自己使用的物件。在Component View裡的所有物件與Diagram也是一樣。

從最上層來看,我們需要有全部的Package List與Package vs Package的水平追溯;接著要有每個Package vs Component的垂直追溯與Component vs Component的水平追溯;再往下還得有Component vs Class與Class vs Class的水平追溯。

對於一個元件來說,把元件內部的Class與Interface同時放到縱軸與橫軸,並於橫軸加上所使用到的其他元件Class與Interface,這是我們對於一個元件內部設計所應該追溯到的關聯範圍。

每一個物件的存在都有他所屬於的地方與他所擁有的物件,找出物件這一類的關聯存在是垂直追溯;物件本身在運作時會使用到的其他物件(應都是同樣層級),找出物件使用關聯的存在則是水平追溯。

2007年9月4日 星期二

D24 Component的使用關係──Component Diagram

設計元件的同時,時常會有動作需要使用其他已經開發完成的元件。雖然在Sequence Diagram與Class Diagram裡記錄了其他元件的Interface,但是若想知道使用一個元件時同時還需要“附帶”加上哪些元件才能運作正常的話,如果沒有記錄下來使用關聯,就絕對不是一時三刻內可以知道的。

想要快速地知道元件的使用關聯,同樣必須付出努力來記錄才能擁有這種效果;作法是在繪製UML Diagram時同時在Component Diagram記錄下元件間的關聯。首先建立放置元件的Package,Package的作用是library的界限,未來放置在同一個Package裡的所有元件實際上都會集合成一個library file 。這個時候先用一張Component Diagram放上所有的Package(先不要有使用關聯)。

接下來依序處理元件。首先要決定元件要放在哪一個Package裡,可以直接在Package節點上New Component並修改名稱。接著在Package裡新增一張Component Diagram,把所有Package裡的元件放進去,再逐一把使用到的其他Package元件放入並拉上使用關聯;與其他Package有關聯時,記得回到上一張圖拉起Package之間的關聯。


依序處理每一個Component與Package直到所有物件的位置與關係都正確為止。

2007年9月3日 星期一

D23 Component的設計產出──Sequence Diagram & Class Diagram

以介面定義作為規格的封裝元件,就像是一個獨立運作的小型系統。設計時以Implementation為起點,將元件的控製邏輯想法,逐一繪製成這兩張UML Diagram。

設計的想法與系統極為類似,我們可以把每個Interface方法視作一個Use Case,依元件每個層次應有的Interface先用Class Diagram標記出來,再用Sequence Diagram串接應該呼叫的方法,依這個原則完成所有方法的流程設計。這裡只需要處理正常執行的流程,因為錯誤的狀況都直接拋出Component Exception。

在設計時最重要的原則,是要把元件設計成絕對獨立的個體,進入Interface之後使用與傳遞的物件,除了執行環境的基本類別之外,就應該只能繼承與使用與開發的系統無關的類別。如此一來可以讓元件與系統之間除了被使用之外,完全沒有關聯存在;這也意味著日後可以把元件提供給任何一個系統來使用,而沒有之前系統的包袱。

在系統設計時如果使用到元件庫裡的元件,完全不用處理細部設計。因為該元件是已經開發完成而且已經通過測試。

2007年9月2日 星期日

D22 清單與項目(3)──集合與物件

物件本來是單獨的個體,但是當一堆相似的物件因為特定的目的而群聚在一起時,他們就應該受到集合管理。

集合是管理所有物件之處,我們需要取得特定物件時直接向對應的集合發出要求;發出的要求應含有想取得物件的篩選條件,集合則依條件傳回所有符合的物件實體;當然也應有列出集合內所有物件的方法。管理的動作還另外包含了新增物件與移除物件,控制者可以依實際狀況來增刪集合內物件的實體。

資源的管理有三個大類:目標與步驟是先有目標再將之切割為多個步驟,所有步驟成果的總和應等於目標的結果。清單與項目是先有項目再將之條列為清單,根據現在的所有項目產生清單的內容。集合與物件則是定義一個集合來管理所有物件,物件的增刪都被動地經由集合來操作。

群組與個體之間會有著使用或管理的動作,這同時表示著它們具有關聯,所以他們相互的影響都需要被追溯以應付未來可能有的任何改變。

2007年9月1日 星期六

D21 令人感到麻煩的設計(6)──解決循環使用的現象

在設計的經驗裡,總是會“不小心”遇到像左圖那樣循環使用的現象,這是需要極力避免的。因為當B改變的時候,要追溯到使用它的A,如果A因為B的改變也作了改變,那麼使用A的B又要再度改變而形成無窮迴圈。

最簡單的解法,就是把A拆成兩個Package,使用B的放在A1,被B使用的集中在A2,這樣就可以讓循環使用的現象變為圖中的單向使用。可是實際遇到的情況大多都因為Package的內聚力過高而無法乾淨地分為兩個Package。

嘗試了幾種有問題的方式後,我提出右圖的解法:在B裡定義一個A2功能的介面(注意:這個介面屬於B),A維持原來使用B的動作,但內部原本要分割成A2的部分使之實作B提供的介面,如此一來A使用B與A實作B都可以是由上往下的使用關係。