顯示具有 [E] 程式實作 標籤的文章。 顯示所有文章
顯示具有 [E] 程式實作 標籤的文章。 顯示所有文章

2007年10月8日 星期一

E30 萬物生息皆有其道,設計系統亦同

在早期的工作歲月裡,曾經我也認為達成系統要求的目標即可,但逐漸累積經驗後我慢慢感覺設計的東西要能彈性地應付需求的改變,才能夠正確實用在多種不同的地方。但是缺乏實際的方向時所能改進的地方其實是很有限的。

2004/07公司裡有講師講授OO-226 (B)的課程,那時第一次聽到這類的設計方式感覺似乎不錯,但是那時還無法理解。2005/10公司派我到恆逸上OO-226 (C)的課程,這次的課本編排得很好,所以聽起來也格外用心;只是聽完後依主管要求在公司講解一遍時,只能食古不化地依內容照念。

2006/01起公司開始研發自有產品,這時我大膽地與同組人員決定使用OOAD來做,不過當時原擬定四週的設計,光是Data Model就做了兩週半才定稿,與其他直接寫程式的組相比落後許多,但是在03/26那天初次感覺到OOAD的融會貫通。

2006/08接手了沒有一行程式是自己所寫的那個產品,除了首次以正式的方法進行錯誤的修正與需求的變更之外,也漸漸明白沒有分割好設計層次所得到的程式有哪些問題。2007年在公司又陸續講了兩場OOAD,加上聽過一場軟體工程的講座便興起了將自己OOAD的想法記錄下來的念頭。

2007/05/30開始在Blog上以每日一小篇的方式記錄,原先的計畫是以百篇上下的內容描述整個系統的開發與維護內容,但是一邊撰寫又一邊領悟到新的想法,現在到這裡已經成長到超過130篇,看來整個系統寫完應是200篇左右。

思索與領悟的過程裡,感覺在實作與設計之上還有一個“道”的存在,所謂的架構設計、細部設計等等都是依循那個常理所必然生出的產物,而且唯有領悟到那個道才能設計出理想的系統。現在的我也只不過是初次感受“道”的存在的新手而已……。

2007年10月7日 星期日

E29 設計的終點(6)──穩定、容易改變、又能快速開發

綜合以上所有的想法,開發一個系統時,我會先著重在MVC的分層設計,每一層再分為Implementation-Controll-Action三個小層次;不管大的層次或小的層次,其中的設計都使用Interface來規範裡頭打算要做的事情,Interface的實作程式會依需要去使用已經開發完成的元件並加以控制

每一層往上會去思考套用Design Pattern的可能性,再適當地改寫為適合作流程控制的寫法,甚至更進一步地做成基本框架的類型。把每一個功能與層次的內容與作法都定義出來,再統合審視可能性與適用性並修正,等專案人員都同意之後就定義出工作項目並發配下去進行。

系統經過精密切割後分層開發,每一層都檢視看哪些可以利用reuse的元件,在寫作的同時讓別人明白裡面在做什麼,並在與其他各層銜接的地方加上吸收改變的避震器類別。每一層都可以方便使用實作,又可以輕易改變內容,如此一來專案的品質將更穩定,開發速度也會比之前更快。

第一次的實作會是辛苦的,因為要比直接做一個專案花費更多的時間。決策上如果確定未來有類似的專案需要開發,那持續往這個方向改進會是最有利的。

這張圖要表示的是所有實作元件與檔案之間的關係:

2007年10月6日 星期六

E28 設計的終點(5)──以做成基本框架(Framework)為目標

把原先用程式表達出來的動作與邏輯,使用文字描述的方式來表達並依序實作,這是撰寫程式之上的另一個層次。

把文字設定讀入依設定生成程式來動作,概念與Web Service裡把XML再生成Data Model差不多,但是需要處理動作與順序,複雜度倒是有過之而無不及。雖然開發這類基本框架的處理需要能力更好的人才做得出來,然而一旦規格開得理想又能完成的話,應付未來的需求改變時,投入人力的數字與門檻就可以降低很多。

Data Model與Controller的基本框架是可以實現的,View當然也可以。同樣應用一組XML的設計內容,我們可以在不同的需要上將之轉變為不同的外觀,無論是哪一種程式語言所使用的UI,甚至是瀏覽器使用的html都可以分別以產生程式來產生。如此一來,整個系統都能夠大量地以設定的方式來生成。

2007年10月5日 星期五

E27 專案分析工具(4)──讓編輯工具能自由決定設定內容

對單一專案而言,製作出分析設定編輯工具之後已經可以算大功告成,但是更理想的狀況是針對用途不同的系統也可以reuse這樣的分析設定產生工具。

不同用途的系統有不同的思考方式,首先就會有不同的設定檔,有不同編輯外觀,也有不同的對應方式,當然匯出到系統的處理方式也有所不同。設定檔可以使用元件對應到Project Data Model,編輯外觀可應用通用編輯器再加工使用,儲存的對應方式與匯出的處理動作能夠使用Flow Engine的架構讓使用者撰寫對應的程式;如此一來在Model-View-Controller三個部分都可以有快速完成的方式。

撰寫客製化的程式已經具有相當的便利性,但是需要一定的程式功力與經驗才能寫得好,資深的設計與寫作人員在專案裡已經不多,有時候會難以再抽出適當人力做出這樣的工具。如果專案需要的工具設計變得容易製作而且沒有問題,是不是大家都渴望的呢?

2007年10月4日 星期四

E26 設計的終點(4)──用程式封裝商業邏輯與設計邏輯

應用Baisc Data Model的觀念,專案的分析與設定記錄就像是外部的檔案,為了更方便地編輯檔案的內容,我們可以使用通用編輯器來擴充為專案用編輯器讓使用者直接編輯並存檔。

在編輯器上編輯的欄位可利用提示文字與輔助說明描述欄位值要如何設定與會有什麼影響,使用者只需要參考詳細的說明來設定,就可以得到正確改變系統內容或運作的結果。這裡引用的技巧在於使用者按照說明設定的值,在匯出動作的同時被一組負責處理匯出的程式依設定在程式裡轉換出系統對應的輸出。

用程式封裝邏輯就是編輯器與轉換器最大的任務,無論是系統的分析與設計還是系統執行時的設定檔,利用編輯器明白地告知使用者所有設定即將造成的影響,再使用轉換器讀入設定值並反應出應該要有的動作。

減少懂得設定之前學習曲線與設定時的花費時間,將有助於所有人員對於系統的了解、使用與操作,這也會是節省專案開發時耗費資源的最大捷徑。

2007年10月3日 星期三

E25 專案分析工具(3)──將分析與設計的記錄匯成產出

再進一步想,以文字檔形式讀入的其他專案內容有Flow Engine定義檔、訊息內容檔案、元件設定檔案……等等,凡是在執行時期以文字檔案生成或設定系統的一部分者,都可以使用程式將記錄加以轉換產生。

由於實際系統的產出分散在許多地方,在取得清單與比較內容這樣的組合動作上都比較不易處理。倘使用集中處理再匯出的方式,同時加上把系統實際產出內容抓取到集中處理的設定檔,這樣就可以擴充到取得系統的目前狀態並加以修改再匯回系統的處理模式。

雖然集中處理檔案設定的內容,已經可以加快設定與產出系統檔案的速度,但是要去產生或編修相關的內容卻還是需要對系統內部有相當程度的了解。為了讓並未完全清楚系統運作的人員(甚至是幾乎不懂系統內部的使用者)能夠順利地正確設定,勢必還需要有輔助的設計才行。

2007年10月2日 星期二

E24 專案分析工具(2)──需求分析與設計的記錄

在需求分析與設計時,我們需要對收集到的資訊加以分類並整理,要能明白每個功能是由哪些動作所組成,而那些動作允許有哪些檔案與內容的存在。分析出來的需求規格書會以文字描述為主,接著對應到設計的設計規格書就會將文字描述轉換為應有的系統產出。

專案的整體設定、各個功能的需求規格書與設計規格書,在實作的觀點來說全部都是在描述系統即將會有的產出。通常程式員會依照規格的內容,逐一做出專案裡對應的所有產出,這一向都是最花費人力資源的工作。

試想,以上的文件與產出其實都有關係存在,如果我們把所有的內容與關係都定義在表格裡的話,系統分析人員就只需要把想法填入表格就可以期望未來有對應的產出。這個概念,就像是設計時把想法直接放到Design Model,再經由其他的工具轉換出我們期望的文件(產出),將會節省許多開發人力。

2007年10月1日 星期一

E23 專案分析工具(1)──執行設定檔的編輯器

我一直強調在設計時,一定要讓影響程式運行的參數定義在外部的文字檔(或資料庫),最大的理由就是讓改變設定不要發生在程式內部,因為設定會由人來決定要設定什麼。如果封裝到程式裡面的話,只要一改變就會需要作改變的追溯。

在設計時依據架構設計的原則,產出層次整齊且方式一致的設定檔案,會比較容易讓使用的人找到想要的設定內容。在提供給使用者修改的大多情況下,由於必須防止程度較差的人作出錯誤修改而導致系統停擺,所以都會準備編輯器;透過編輯器可以只顯示出使用者可以修改的地方與現在的值,使用者只能輸入經過檢核的值而且保證以正確的格式放在正確的位置。

利用通用編輯器可以對應編輯一個檔案,我們可以收集專案所有設定檔清單加以分門別類,做出一個符合專案範圍的設定檔編輯工具。這時對於使用者而言,只要打開編輯器就可以保證看到的是他全部所能調整的設定,同時也不用擔心輸入錯誤的問題,因為這些都已經被編輯器加以管理。

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傳回。