回到現實面來看,設計都希望有設計文件的產生。如果依照一般的方法論在先作出設計文件,在實作或測試發現設計有錯誤的時候,除了改程式之外還要多出修改文件的動作;如果直接把想法寫成程式,在完成系統後還要再依程式內容重新寫出文件。
依照我的程式結構,流程是被集中在一個Method裡的,此時運用Java構文解析可以有三個方向可以努力:一個是分析出使用到的其它元件、一個是把流程轉換為流程設定檔,另一個則是將流程輸出為流程圖。當然,首先要做的是把程式碼讀入到處理的程式裡;目前可以運用的技術是JDT。
定義好規則之後,才能寫出對應規則的程式,再運用可以處理規則程式碼的元件產出我們要的東西。讀入程式碼後,我們可以按照需要輸出;以產出流程圖為方向的需求下,只要找到提供適當API的工具,就可以依照程式碼解析出來的內容產生對應的表格。
這樣做的好處是程式不管怎麼修改,只要符合規則就可以立即產出對應實際內容的文件(關聯與流程)。
2008年5月7日 星期三
2008年5月6日 星期二
O16 流程使用Flow Engine實作的可能
Component結構是把焦點放在最容易被修改的Flow上,努力將內部的使用對象依特性放置到不同的Interface裡。這樣的作法在Use Case上接下來的可能,就是使用Flow Engine來實現以定義檔來處理流程的可能。
想像有流程產生器時,程式寫作除了Action Method需要多加注意之外,其他部分的設計就變得很單純,加上Component, API已經建立在元件庫,就可以定義執行流程後透過Flow Engine使用映射來執行其他部分或其他Component的方法。想想這樣的系統開發是多麼棒的一件事。
將執行Method需要的Class Name、Method Name與輸入參數定義在動作,流程的控制可以根據執行動作可能傳回的結果設定接下來要執行哪一個動作,依此推疊出一個功能完整的流程。Flow Engine本身會是一個要額外開發的元件,如果想為流程編輯設計一個編輯工具又會是一個更大的元件,但是往這個方向開發卻可以有更多的回收。
Flow Engine需要設計的動作是有限的,經過完整測試後就可以不再變動;使用者需求的變動都被轉化為設定後,只要不出執行、判斷的範圍就只會改變設定檔而不用動到程式。重點在於系統任何的程式變動都需要經過一層層的測試才能確認是否沒有問題,使用流程設定則只需要測試過程是否正確即可。
想像有流程產生器時,程式寫作除了Action Method需要多加注意之外,其他部分的設計就變得很單純,加上Component, API已經建立在元件庫,就可以定義執行流程後透過Flow Engine使用映射來執行其他部分或其他Component的方法。想想這樣的系統開發是多麼棒的一件事。
將執行Method需要的Class Name、Method Name與輸入參數定義在動作,流程的控制可以根據執行動作可能傳回的結果設定接下來要執行哪一個動作,依此推疊出一個功能完整的流程。Flow Engine本身會是一個要額外開發的元件,如果想為流程編輯設計一個編輯工具又會是一個更大的元件,但是往這個方向開發卻可以有更多的回收。
Flow Engine需要設計的動作是有限的,經過完整測試後就可以不再變動;使用者需求的變動都被轉化為設定後,只要不出執行、判斷的範圍就只會改變設定檔而不用動到程式。重點在於系統任何的程式變動都需要經過一層層的測試才能確認是否沒有問題,使用流程設定則只需要測試過程是否正確即可。
2008年5月5日 星期一
O15 理想元件結構的調整
Component在我的想法裡會有19個檔案,這是為了解決之前提過的現象而鋪設。重點在於Flow與Action,在設計的流程裡經由Impl進入,參數參考Properties,處理的資料放在Model,處理的動作放在Action,唯一存取外部的是其他元件的Component Interface Method;Action裡也是類似的作法。在這個結構裡,接手的人可以把重心放在Flow與Action內部而不用到處找東西放在哪裡。如果所有的元件結構都是這樣,在遇到有人新接手的時候,只要先講解Component的基本結構再說明現行系統的Package Diagram,最多只需要一天就可以讓新人開始追蹤與除錯。但是複雜的結構帶來的是設計與實作時必須在19個檔案中工作,手忙腳亂再加上偶而忘記把東西放在哪裡卻是免不了的,這也相對地更降低了產能。
在確定不需要某些需要的時候,可以縮減結構的複雜性。在各個部件裡,如果確定不會有改寫的需要,可以不要放置Abstract Class;Action動作不多時可以取消而以Method的型式放在Flow裡;Properties也可以直接用Java Properties或是基本Data Model的方式放在Impl裡取用。在堅持應有的Interface與Class下,元件的檔案數量可以減少到10個。
2008年5月4日 星期日
O14 設計與重構就像光與影的共存
設計的人雖然已經作出可行的系統結構,但是實作者是否有與設計者一致的觀念是一個問題,設計者對於這個系統的想法能不能傳承給實作者是一個問題,另外實作者撰寫程式時臨時發生的錯誤又是一個問題。
對於實作上較沒經驗的人,即使提供已經設計好的Method,實作時還是會發生責任錯置的狀況。在大陸的專案裡,有個集合物件本身擁有多個子物件,在需要記下所有子物件的現在狀態的功能實作時,把狀態記錄在集合物件而非要求各個子物件記錄自己的狀態。這是一個很明顯的責任錯置。
即使是設計相當有經驗的人只要一時閃神放錯地方,未來還是得重構。在設計的時候,我起初把數種不同元件的event處理都放到相同的Package裡,後來裡面Class實在太多太雜,只好依所屬元件再分開到幾個package存放,使其成為一對一的對應。
設計是把完成功能的動作放置到最適合的地方,但是沒人設計時能一直保持分工正確的,也沒有人寫程式不會出錯的,因此我們必須不斷地檢視自己所作的設計並予以調整。設計與重構就像是光與影的共存時常會發生,這也是我一直堅持要設計出只需移動方法就能完成重構的系統架構的原因。
對於實作上較沒經驗的人,即使提供已經設計好的Method,實作時還是會發生責任錯置的狀況。在大陸的專案裡,有個集合物件本身擁有多個子物件,在需要記下所有子物件的現在狀態的功能實作時,把狀態記錄在集合物件而非要求各個子物件記錄自己的狀態。這是一個很明顯的責任錯置。
即使是設計相當有經驗的人只要一時閃神放錯地方,未來還是得重構。在設計的時候,我起初把數種不同元件的event處理都放到相同的Package裡,後來裡面Class實在太多太雜,只好依所屬元件再分開到幾個package存放,使其成為一對一的對應。
設計是把完成功能的動作放置到最適合的地方,但是沒人設計時能一直保持分工正確的,也沒有人寫程式不會出錯的,因此我們必須不斷地檢視自己所作的設計並予以調整。設計與重構就像是光與影的共存時常會發生,這也是我一直堅持要設計出只需移動方法就能完成重構的系統架構的原因。
2008年5月3日 星期六
O13 動態的應用(3)──Data
Data的存取是使用Class與Method混合搭配所產生的運用。我使用的地方在於Context的再生與Bean、Property內容的生成。
製作Context的輸出首先得要有易於列出現有資料內容的設計,然後要將列出來的Data名稱與值轉換為字串,這組字串可以存放在任何地方。再生的時候從字串裡逐一取得Data名稱與值再動態呼叫資料名的setter便可以復原儲存時間點的Context。
Bean的生成可以想成是Context再加上一個動態的Class,也因此定義的方式就可分析為Class與Data的組成。定義時需要特別注意Data的值為集合或是物件的狀況,集合主要有List與Map,要設計出集合類型與其中值的定義法;物件的文字定義或許可以依循bean的方式,只要維持固定的模式即可。
目前我選用的是用Hibernet的XML定義方式來存放執行時期所需的Data。
製作Context的輸出首先得要有易於列出現有資料內容的設計,然後要將列出來的Data名稱與值轉換為字串,這組字串可以存放在任何地方。再生的時候從字串裡逐一取得Data名稱與值再動態呼叫資料名的setter便可以復原儲存時間點的Context。
Bean的生成可以想成是Context再加上一個動態的Class,也因此定義的方式就可分析為Class與Data的組成。定義時需要特別注意Data的值為集合或是物件的狀況,集合主要有List與Map,要設計出集合類型與其中值的定義法;物件的文字定義或許可以依循bean的方式,只要維持固定的模式即可。
目前我選用的是用Hibernet的XML定義方式來存放執行時期所需的Data。
2008年5月2日 星期五
O12 動態的應用(2)──Method
另一個動態的應用是Method,是根據取得的字串對應指定的Class呼叫特定的Method。應用這個功能我們可以把想要執行的動作放到外部的字串裡。這樣的好處是可以把注意力放在提供執行方法的Class,而不用跟著變動執行呼叫的部份。
最常運用的是Data的setter與getter,根據屬性名稱組成存取屬性的方法並自動呼叫;雖然在提供存取的Class裡必須提供所有的getter與setter的方法,但是在呼叫的那一端就可以使用簡潔的程式碼來應付所有的Data存取。
除了資料的動態存取,利用Method的映射還可以作出執行的流程。讓執行的順序與內容定義在外部檔,用一個元件負責流程的處理,依照順序執行對應的動作(當然,動作要集中在一個Class或一個Class僅負責一個動作都可以),使用這種方法可以把變化的部分抽取到文字檔案的定義而不需要改動程式。
對系統而言,只要更動程式的任何一行都必須重新測試所有的影響部分,即使某些流程的改動很單純,但仍然需要完整的測試,一些要求更為嚴謹的客戶甚至會詢問改變的原因與影響。使用外部定義可以避免這個問題,這是因為定義的意義都已經定義為對應的方法,改變只限於傳入的屬性。
最常運用的是Data的setter與getter,根據屬性名稱組成存取屬性的方法並自動呼叫;雖然在提供存取的Class裡必須提供所有的getter與setter的方法,但是在呼叫的那一端就可以使用簡潔的程式碼來應付所有的Data存取。
除了資料的動態存取,利用Method的映射還可以作出執行的流程。讓執行的順序與內容定義在外部檔,用一個元件負責流程的處理,依照順序執行對應的動作(當然,動作要集中在一個Class或一個Class僅負責一個動作都可以),使用這種方法可以把變化的部分抽取到文字檔案的定義而不需要改動程式。
對系統而言,只要更動程式的任何一行都必須重新測試所有的影響部分,即使某些流程的改動很單純,但仍然需要完整的測試,一些要求更為嚴謹的客戶甚至會詢問改變的原因與影響。使用外部定義可以避免這個問題,這是因為定義的意義都已經定義為對應的方法,改變只限於傳入的屬性。
2008年5月1日 星期四
O11 動態的應用(1)──Class與Constructor
不管是Class的生成或是方法的呼叫都儘量使用映射的機制。這樣做的好處在於可以把字串動態地變成指定的Object或執行Obejct的特定Method,不必像初學者般運用大量的if-else判斷才能定位到應該要執行的程式。
當所有物件的規格都有定義Interface時,我們就可以在使用該物件的地方定義使用Interface。當這個Interface只擁有一個實作Class時可以直接new出來使用;但實作的Class種類變多時,就能夠依狀態的不同取得不同的Class Name再使用Class.forName(className).newInstance()拿到指定實作類型的物件。
生成物件時如果需要傳入參數,則需要取得Class的Constructor,取得時需要傳入Constructor所需的參數類型陣列;呼叫時也要將傳入的參數依序放在陣列裡,然後就可以取得指定的物件。一般來說會把Class Name加上id放置在設定檔裡,依不同狀況取用不同id的設定,如果需要傳入參數的話,則將相關設定放在同一組id下。
記得物件範圍的切割度會影響作法,物件範圍涵蓋得越大則越可能得準得許多應付不同需求的Class,但是如果切割得過小也會造成花費時間過多。這一直都是個值得深思的問題。
當所有物件的規格都有定義Interface時,我們就可以在使用該物件的地方定義使用Interface。當這個Interface只擁有一個實作Class時可以直接new出來使用;但實作的Class種類變多時,就能夠依狀態的不同取得不同的Class Name再使用Class.forName(className).newInstance()拿到指定實作類型的物件。
生成物件時如果需要傳入參數,則需要取得Class的Constructor,取得時需要傳入Constructor所需的參數類型陣列;呼叫時也要將傳入的參數依序放在陣列裡,然後就可以取得指定的物件。一般來說會把Class Name加上id放置在設定檔裡,依不同狀況取用不同id的設定,如果需要傳入參數的話,則將相關設定放在同一組id下。
記得物件範圍的切割度會影響作法,物件範圍涵蓋得越大則越可能得準得許多應付不同需求的Class,但是如果切割得過小也會造成花費時間過多。這一直都是個值得深思的問題。
2008年4月30日 星期三
O10 我的設計準則(4)──靈活替換
一個以“滿足客戶既定需求”為目標的系統,只是勉強及格而已。因為無論是需求的改變或是因為要修正之前沒有被測出的錯誤,都會造成在固定結構下的變動而使得問題因為失衡而接二連三地發生。因此,彈性的設計雖然對實現功能沒有直接影響,卻能夠避免未來的巨大風險。
彈性設計的首要,在於切割出可以置換的單位。一個只能置換整個元件的設計,極可能在只有流程變動略大時就需要重新放上一個內容幾近相同的另一個元件;因此除了儘量應用參數化的設計外,我把元件的內部切割為六種特性放置屬於該部分的程式碼,每一個部分都可以根據實際的需要來改變實作的類別。
另一個要求是使用介面來定義切割出來的單位。要能靈活置換必須應用OO裡的多形特性,利用介面定義好切割單位的規格並在上層的程式使用,再用動態變換的設計(例如Design Patterns)更換實際工作的物件以應付不同的需要。
靈活替換還有一個重要的目標是使用較少的程式碼來達成較複雜的動作。像是Class、Constructor、Method等Java物件,以及Method所能涵蓋的getter、setter的資料存取方法,活用這些映射物件將有助於快速的開發與動態的改變。
彈性設計的首要,在於切割出可以置換的單位。一個只能置換整個元件的設計,極可能在只有流程變動略大時就需要重新放上一個內容幾近相同的另一個元件;因此除了儘量應用參數化的設計外,我把元件的內部切割為六種特性放置屬於該部分的程式碼,每一個部分都可以根據實際的需要來改變實作的類別。
另一個要求是使用介面來定義切割出來的單位。要能靈活置換必須應用OO裡的多形特性,利用介面定義好切割單位的規格並在上層的程式使用,再用動態變換的設計(例如Design Patterns)更換實際工作的物件以應付不同的需要。
靈活替換還有一個重要的目標是使用較少的程式碼來達成較複雜的動作。像是Class、Constructor、Method等Java物件,以及Method所能涵蓋的getter、setter的資料存取方法,活用這些映射物件將有助於快速的開發與動態的改變。
2008年4月29日 星期二
O09 我的設計準則(3)──絕對重用
設計程式的人都知道,同樣目的的重覆程式碼應該抽取到同一方法裡作為重用。重用的好處主要是讓同樣目的的程式碼只有一份,在使用時有固定的用法且在修改時只需要修改一個地方就能改變全部。
在理想的設計裡應該抽取相同層級內相同目的的物件,不管是類別、方法或是常數,而不要包含不同層次的東西。在抽取方法的的時候,有時會有幾乎相同但有少許差異的地方,這時可把差異的部分用參數區別並在程式中判斷,如此就可以使用相同的程式碼。
對系統而言,特定方面的功能都集中在一個元件;對元件而言,六種類型的類別各自掌管屬於自己的行為;對方法而言,同樣的動作都抽取到同一個方法;對資料而言,使用的常數全部要定義在固定的介面裡。每一個可以抽取的地方都應該確實地實行,否則同樣目的的程式碼在系統裡到處都存在,會變得難以有固定的用法與切實的維護。
在相同使用層級的視界裡,努力把聚合力高的的共同部分抽取重用,是現在堅持的準則。檢視方法定義的所在位置是否正確與不應該存在兩份以上的相同目的程式碼或物件,是review設計的主要方向。
2008年4月28日 星期一
O08 我的設計準則(2)──動靜分離
撰寫程式時如果沒有適當切割與分類,會造成不同層次的動作都集中到一個類別,為了避免層次不清的混雜,所以希望可以遵循分層負責的準則切分出每一層該做的事。
在元件裡的動作雖然具有明確的目標,但是為了達成元件方法的目標,還是必須用正確的順序執行應該執行的小動作,所以這裡會依照動態的執行流程與靜態的固定動作加以分類,將不同的類型的東西封裝在不同的地方;也就是Flow與Action。
有許多人(包括我)奉行MVC的設計,但是在本質上來說MVC的組成會進一步劃分為MVFA。製作流程圖時是依照Use Case的流程串連各個負責實作的Activity,我是進一步把這個觀念應用在程式內部,以強制將流程與動作分離用來解決流程時常異動的問題。我的目標是在實作Flow的部分時,可以藉由週邊的Interface快速地知道可以使用的物件與動作全部有哪些,在幾乎不同多作學習慣情況下快速改變執行的邏輯。
另外不管是在系統上或是元件內,動作的實作是Activity所描述的,而且特定功能的動作會封裝在同一個Component。將流程與動作分離時,如果系統的精髓在流程,則把流程部分掌握在自己手中,將動作部分外包給其他公司開發;反之如果Component裡有設備或邏輯的機密,則將流程部分拿去外包而將動作部分留下來,如此將有助於商業機密的保護。
在元件裡的動作雖然具有明確的目標,但是為了達成元件方法的目標,還是必須用正確的順序執行應該執行的小動作,所以這裡會依照動態的執行流程與靜態的固定動作加以分類,將不同的類型的東西封裝在不同的地方;也就是Flow與Action。
有許多人(包括我)奉行MVC的設計,但是在本質上來說MVC的組成會進一步劃分為MVFA。製作流程圖時是依照Use Case的流程串連各個負責實作的Activity,我是進一步把這個觀念應用在程式內部,以強制將流程與動作分離用來解決流程時常異動的問題。我的目標是在實作Flow的部分時,可以藉由週邊的Interface快速地知道可以使用的物件與動作全部有哪些,在幾乎不同多作學習慣情況下快速改變執行的邏輯。
另外不管是在系統上或是元件內,動作的實作是Activity所描述的,而且特定功能的動作會封裝在同一個Component。將流程與動作分離時,如果系統的精髓在流程,則把流程部分掌握在自己手中,將動作部分外包給其他公司開發;反之如果Component裡有設備或邏輯的機密,則將流程部分拿去外包而將動作部分留下來,如此將有助於商業機密的保護。
2008年4月27日 星期日
O07 我的設計準則(1)──分層對應
功能的完成是經由正確順序地執行所有必要動作所達到的,分析出所有的必要動作是製作功能的前提。收集大量的系統動作後,依據其執行的特性與目的加以群組化形成元件,這便是用於組成系統的軟體單位。
對開發系統而言,先準備好最底層的元件,像是Log、Message、Setting等基礎必用的元件,然後定義與Client to Server、DB存取元件,再來是定義基本的MVC元件;到這裡是所有系統都可以完全重用的基礎。再向上則是與Domain有關的MVC、Business Component、產生元件的Factory與系統Root Component。
往內來看,元件的處理邏輯有Impl、Flow、Action,處理的異常有Exception,處理時的變動參考Properties,處理的資料來源則是Model。這是元件內的六個組成單位,每個單位再封裝與自己負責功能的相關程式,依此向下完成每一個部分。
以Compnent為界線,向上組合成客戶想要的系統,向下再依MVC原則切分內部,每一個靜態物件或是動作類型都安排一個元件負責處理。二者的中間以Component Interface作為介面清楚地隔成兩個不同思維的層面,但是用相同的設計概念貫穿全部的Component,讓所有人快速瞭解整個系統是如何被架構起來的。
對開發系統而言,先準備好最底層的元件,像是Log、Message、Setting等基礎必用的元件,然後定義與Client to Server、DB存取元件,再來是定義基本的MVC元件;到這裡是所有系統都可以完全重用的基礎。再向上則是與Domain有關的MVC、Business Component、產生元件的Factory與系統Root Component。
往內來看,元件的處理邏輯有Impl、Flow、Action,處理的異常有Exception,處理時的變動參考Properties,處理的資料來源則是Model。這是元件內的六個組成單位,每個單位再封裝與自己負責功能的相關程式,依此向下完成每一個部分。
以Compnent為界線,向上組合成客戶想要的系統,向下再依MVC原則切分內部,每一個靜態物件或是動作類型都安排一個元件負責處理。二者的中間以Component Interface作為介面清楚地隔成兩個不同思維的層面,但是用相同的設計概念貫穿全部的Component,讓所有人快速瞭解整個系統是如何被架構起來的。
2008年4月26日 星期六
O06 做事的方法(11)──交付工作並非學禪
在民間故事裡,常會看到古代高僧做出一件事,讓大家根據自己的想法來推測有什麼含義,同時以檢視每個人的答案看誰的答案最接近高僧想的,然後把主持的位置交棒給他。用這個方式來確認誰的想法比較貼近出題者的想法是很不錯的,因為思維相近的人推想出來的邏輯都會差不多。
可是看一下其他的人提出的答案,同樣的動作在每個人的眼裡所解讀出來的結果都大不相同呢。如果主管交待事情時沒有描述出完整的想法,只單純地告知要做什麼,不僅接收命令的人會有“為什麼要做這個”的疑惑,消息讓其他的人聽到時還會造成每個人各自解讀主管想法再傳出去的結果,使得謠言到處流傳。
平時做事時,也有不少與主管想法不同的時候。管理階層想的是如何達成目標,實作階層想的是怎麼順利做事。有次幾個人為了怎麼順利執行進度而計畫了半天,最後跟主管確認時才發現公司政策上決定不能那樣做而要用另一種比較麻煩的方式。因此為了不浪費私下計畫的時間,所以養成先去詢問主管是否有政策考量的習慣;無法使用邏輯推理出來的結果,到底不是像我這樣的人可以理解的。
開發系統不應該也弄成這樣。設計者把想法直接做成程式,再讓一堆維護的人根據程式去猜想他原來為什麼這樣做,還有做了會有什麼好處或壞處,這是非常令人無力的事。如果自己不喜歡做維護的工作,又何苦把辛苦接手你開發系統的人搞得這麼累呢?
可是看一下其他的人提出的答案,同樣的動作在每個人的眼裡所解讀出來的結果都大不相同呢。如果主管交待事情時沒有描述出完整的想法,只單純地告知要做什麼,不僅接收命令的人會有“為什麼要做這個”的疑惑,消息讓其他的人聽到時還會造成每個人各自解讀主管想法再傳出去的結果,使得謠言到處流傳。
平時做事時,也有不少與主管想法不同的時候。管理階層想的是如何達成目標,實作階層想的是怎麼順利做事。有次幾個人為了怎麼順利執行進度而計畫了半天,最後跟主管確認時才發現公司政策上決定不能那樣做而要用另一種比較麻煩的方式。因此為了不浪費私下計畫的時間,所以養成先去詢問主管是否有政策考量的習慣;無法使用邏輯推理出來的結果,到底不是像我這樣的人可以理解的。
開發系統不應該也弄成這樣。設計者把想法直接做成程式,再讓一堆維護的人根據程式去猜想他原來為什麼這樣做,還有做了會有什麼好處或壞處,這是非常令人無力的事。如果自己不喜歡做維護的工作,又何苦把辛苦接手你開發系統的人搞得這麼累呢?
2008年4月25日 星期五
O05 說話為什麼會夾雜著英文單字?
以前在國內時,時常會疑惑為什麼有很多人在中文語句裡夾雜著英文單字,明明那些單字都有標準的中文名稱;那個時候都會要求自己說話時儘量使用中文單字。
在2007/11起與大陸的團隊一起進行開發,在討論與溝通的同時發現我說的話有時候他們無法明瞭,後來才發現是因為英文單字在大陸與台灣翻譯的用詞不同造成的。與其把話完全說完後才發現沒法溝通而重說一遍,倒不如直接把專有名詞全部置換在句子裡表達還比較快速;發現了這個道理之後,對他們表達的溝通內容就完全改變。
想像有本巨大的百科全書,裡面收集世界上所有的名詞、動詞、形容詞……等等,對一種語言來說,當你知道越多物件在該語言的名稱就有越多可使用的候選單字;在越多狀況下能夠用該語言表達自己的意義並且聽懂別人的表達就是越熟練的證明。
從根本來看,對每一種物品、動作、形容……如果可以輕易答出它在該語言下的念法,就更可以輕易地把自己的想法用該種語言的表達。而在溝通的過程中,由於每種語言對同一物件的形容不同,如果擔心產生誤會的話就使用大家都統一的英文來描述它。
註:倘使把字詞的本體想像為該物件的Interface,那麼各個語言下該物件的名稱就很像是該物件的實作。字典是收集指定字數內所有字詞的集合,各種字典內都具有該語言下所有字詞的名稱;把字詞名稱視為Object,字典就像是提供所有物件Interface實作的Factory。再往上看,我們在不同語言的需求下會取用指定語言的字典(Factory),這種選取的動作正是Abstract Factory的精神。
在2007/11起與大陸的團隊一起進行開發,在討論與溝通的同時發現我說的話有時候他們無法明瞭,後來才發現是因為英文單字在大陸與台灣翻譯的用詞不同造成的。與其把話完全說完後才發現沒法溝通而重說一遍,倒不如直接把專有名詞全部置換在句子裡表達還比較快速;發現了這個道理之後,對他們表達的溝通內容就完全改變。
想像有本巨大的百科全書,裡面收集世界上所有的名詞、動詞、形容詞……等等,對一種語言來說,當你知道越多物件在該語言的名稱就有越多可使用的候選單字;在越多狀況下能夠用該語言表達自己的意義並且聽懂別人的表達就是越熟練的證明。
從根本來看,對每一種物品、動作、形容……如果可以輕易答出它在該語言下的念法,就更可以輕易地把自己的想法用該種語言的表達。而在溝通的過程中,由於每種語言對同一物件的形容不同,如果擔心產生誤會的話就使用大家都統一的英文來描述它。
註:倘使把字詞的本體想像為該物件的Interface,那麼各個語言下該物件的名稱就很像是該物件的實作。字典是收集指定字數內所有字詞的集合,各種字典內都具有該語言下所有字詞的名稱;把字詞名稱視為Object,字典就像是提供所有物件Interface實作的Factory。再往上看,我們在不同語言的需求下會取用指定語言的字典(Factory),這種選取的動作正是Abstract Factory的精神。
2008年4月24日 星期四
O04 讓參與者明白系統的一切
在進入實作之前,如果實作的人與設計的人不同,那麼就必須有移轉的動作;簡單地說,就是要把設計者腦子裡的東西“複製”到實作者的腦子裡。
移轉的動作常見的有兩種:一種是設計者把記得的部分跟大家說一遍,一種是循序漸進地將完成功能所需要的資訊製作文件。口述的方式的問題在於設計者想到什麼說什麼,除了細節難以即刻描述之外還有遺漏的問題;使用文件的話,一旦寫下就可以永遠保存,裡面記載的內容可以讓所有接觸的人看到全部的內容。
移轉最大的問題都在於設計者提供了些什麼內容?實作者所能知道的範圍一開始都被侷限在設計者提供的部分。雖然我們明白設計的人描述設計越詳細越好,不過由於把心裡的想法記錄出來需要時間,而且這對產能沒有任何幫助,因此許多設計者都把時間放在功能的實現而忽略掉文件內容的重要性。
適當的圖文描述有助於實作者直接吸收表達的內容,在描述內容有所缺漏的時候,實作的人必須再確認設計者的想法,或者自己去推想他原先想表達什麼。如果團隊裡想找出具有天份的人時,這的確是個不錯的方式,不過在正常的開發系統時,這樣地讓一群實作者繞一大圈才能懂設計的目標,真的是很浪費資源的作法。(節省設計者的時間,浪費實作者與維護者的時間)
因此,我強烈堅持應努力讓實作者快速明白系統的設計,以穩定而不易改變的元件與系統結構套用在所有地方,讓實作的人適當統一的寫作風格,也藉此機會減少設計者額外花時間製作文件。以這種方式,可以在一天的基本說明之後只依賴內部的註解進行系統的維護。
移轉的動作常見的有兩種:一種是設計者把記得的部分跟大家說一遍,一種是循序漸進地將完成功能所需要的資訊製作文件。口述的方式的問題在於設計者想到什麼說什麼,除了細節難以即刻描述之外還有遺漏的問題;使用文件的話,一旦寫下就可以永遠保存,裡面記載的內容可以讓所有接觸的人看到全部的內容。
移轉最大的問題都在於設計者提供了些什麼內容?實作者所能知道的範圍一開始都被侷限在設計者提供的部分。雖然我們明白設計的人描述設計越詳細越好,不過由於把心裡的想法記錄出來需要時間,而且這對產能沒有任何幫助,因此許多設計者都把時間放在功能的實現而忽略掉文件內容的重要性。
適當的圖文描述有助於實作者直接吸收表達的內容,在描述內容有所缺漏的時候,實作的人必須再確認設計者的想法,或者自己去推想他原先想表達什麼。如果團隊裡想找出具有天份的人時,這的確是個不錯的方式,不過在正常的開發系統時,這樣地讓一群實作者繞一大圈才能懂設計的目標,真的是很浪費資源的作法。(節省設計者的時間,浪費實作者與維護者的時間)
因此,我強烈堅持應努力讓實作者快速明白系統的設計,以穩定而不易改變的元件與系統結構套用在所有地方,讓實作的人適當統一的寫作風格,也藉此機會減少設計者額外花時間製作文件。以這種方式,可以在一天的基本說明之後只依賴內部的註解進行系統的維護。
2008年4月23日 星期三
O03 測試先行──保證設計能有正確的結果
設計與撰寫的目的,最基本的目的是為了保證功能需求可以被正確的執行。無論系統內部設計得再爛,只要把執行功能需要的動作都依正確順序放入並通過測試,在使用者的角度來看都可以被稱為及格的系統。
由於系統有這個最基本的要求,因此“功能必須正常執行”成為首要的目標。在元件設計完後,我通常都會對它的initial、dispose與幾個重要的執行方法進行測試,不過我的目的在於檢查Method內執行的動作是否正確且沒有缺漏。設計時比較像紙上談兵,聽起來似乎都很有道理,但是實現起來就會發現有所缺漏或是邏輯相互抵觸,這些都必須依賴測試來發現。
外在測試單位是API與Component Interface Method,內部測試則是以Flow Method內部為主要,在執行時驗證Flow內使用的Action與結果是否符合完成功能的需要。從第一個實作的元件開始(應該是從底層開始實作),就應該在實作結束時實行Unit Test來保證功能正確而且不會被修改。順利的話,通過Unit Test後都可以預期使用是完全正確且沒有問題的;這會讓設計更上層元件的人專心在其內部而毌須擔心底層元件的問題。
如果有餘力的話,在設計與實作時應該要經常檢驗Component Interface的定義是否具有高內聚與低耦合的特性。雖然“功能必須正常執行”是最基本的要求,但是我們應該把眼光放遠,將目標放在“每一個元件都能被單獨重用”,這樣才能更加速自己系統與其他系統的開發速度。
由於系統有這個最基本的要求,因此“功能必須正常執行”成為首要的目標。在元件設計完後,我通常都會對它的initial、dispose與幾個重要的執行方法進行測試,不過我的目的在於檢查Method內執行的動作是否正確且沒有缺漏。設計時比較像紙上談兵,聽起來似乎都很有道理,但是實現起來就會發現有所缺漏或是邏輯相互抵觸,這些都必須依賴測試來發現。
外在測試單位是API與Component Interface Method,內部測試則是以Flow Method內部為主要,在執行時驗證Flow內使用的Action與結果是否符合完成功能的需要。從第一個實作的元件開始(應該是從底層開始實作),就應該在實作結束時實行Unit Test來保證功能正確而且不會被修改。順利的話,通過Unit Test後都可以預期使用是完全正確且沒有問題的;這會讓設計更上層元件的人專心在其內部而毌須擔心底層元件的問題。
如果有餘力的話,在設計與實作時應該要經常檢驗Component Interface的定義是否具有高內聚與低耦合的特性。雖然“功能必須正常執行”是最基本的要求,但是我們應該把眼光放遠,將目標放在“每一個元件都能被單獨重用”,這樣才能更加速自己系統與其他系統的開發速度。
2008年4月22日 星期二
O02 絕對不要直接寫程式來作設計
人腦是沒法放置太多資料的,除了極少數過目不忘再加上記憶持久的人,細節的部分到最後不是忘掉就是亂掉。在想要在程式裡執行一個動作的時候,如果遇上記憶沒法串連的情況發生, 放置的動作就有可能不在它應在的位置或是使用到不正確的方式。
程式的設計應該是嚴謹的,每種不同功能的相關動作必須要有一致的風格與寫法,而且必須在整個系統內予以貫徹。每一個動作的使用錯誤都會在切割於這個關聯上時造成必須改動的影響,這是因為在這個切割面上所露出方法的使用是不平整的。一個設計良好的系統,會在Use Case、Tier與Layer的三度空間中儘可能地放置整齊的切割面。
動作責任歸屬與使用方式的錯誤,因為功能還是達成所以可以通過所有的功能測試,但如果到系統開發後期才發現從某個切割面上必須調整,那可不是好玩的事;因為在那之上又堆疊了許多設計,任何下層的方法變動都會連帶造成使用它的方法必須修改。
在一次UI的設計上,欄位希望在輸滿指定長度時將游標移到下一欄位,但是開發的人寫成輸滿長度後要再多打一個字才會移動游標,後來為了改回正確的行為模式修改了很久,因為牽涉到得先檢查最後一字元是否合法以及移動游標時間點的衝突,而多花了不少時間。
維持各個可能切割面露出方法的正確性與一致性,這是直接寫程式作設計時無法滿足的需求;因此我強烈建議在每一個可能切割的地方先行檢驗其Interface與結構。
程式的設計應該是嚴謹的,每種不同功能的相關動作必須要有一致的風格與寫法,而且必須在整個系統內予以貫徹。每一個動作的使用錯誤都會在切割於這個關聯上時造成必須改動的影響,這是因為在這個切割面上所露出方法的使用是不平整的。一個設計良好的系統,會在Use Case、Tier與Layer的三度空間中儘可能地放置整齊的切割面。
動作責任歸屬與使用方式的錯誤,因為功能還是達成所以可以通過所有的功能測試,但如果到系統開發後期才發現從某個切割面上必須調整,那可不是好玩的事;因為在那之上又堆疊了許多設計,任何下層的方法變動都會連帶造成使用它的方法必須修改。
在一次UI的設計上,欄位希望在輸滿指定長度時將游標移到下一欄位,但是開發的人寫成輸滿長度後要再多打一個字才會移動游標,後來為了改回正確的行為模式修改了很久,因為牽涉到得先檢查最後一字元是否合法以及移動游標時間點的衝突,而多花了不少時間。
維持各個可能切割面露出方法的正確性與一致性,這是直接寫程式作設計時無法滿足的需求;因此我強烈建議在每一個可能切割的地方先行檢驗其Interface與結構。
2008年4月21日 星期一
O01 設計常會出錯,而且實作時才發現有錯
不管哪個方法論都有這個問題,因為思考時所想的與實作時要做的有時會有差距,理論上設計經驗越多,差距應會越來越小,但是並沒有辦法保證所有的方法設計都做出完美的設計,出錯的部分通常是應該做的動作少做、動作順序錯誤或是執行結果的判斷錯誤。
主管時常問我:有沒有可能人在台灣帶領大陸那邊的人一起設計?我的回答都是:在設計階段是不可能的。人的想法都會有疏漏,定義固定的作業流程與不斷的檢查就是希望及早發現設計的疏失並解決,討論與檢查的行為在設計者之間有大量的資訊交流,拉開設計者的距離後在彼此之間的資訊交流相對地就變為比較困難。
主管還會問我:是否可以在台灣設計然後拿到大陸開發?我的回答也是:以現在的作法是不可能的。這是因為現在的設計者還無法寫出可以完整描述設計的文件,雖然現在公司已經導入CMMI,也規定出設計產出應有的章節,但是無法表現出設計精神的產出是難以順利開發的;更何況設計的人還沒有寫文件的習慣。
如何讓實作的人快速明白系統內部的設計概念是很重要的工作,因為讓實作人員依照設計用正確的順序呼叫正確的方法才可以保證系統的形成會符合設計;同時也因為設計的錯誤可能在任何地方發生,藉由設計概念的傳達也能夠讓實作人員協助發現設計時疏漏的問題。
主管時常問我:有沒有可能人在台灣帶領大陸那邊的人一起設計?我的回答都是:在設計階段是不可能的。人的想法都會有疏漏,定義固定的作業流程與不斷的檢查就是希望及早發現設計的疏失並解決,討論與檢查的行為在設計者之間有大量的資訊交流,拉開設計者的距離後在彼此之間的資訊交流相對地就變為比較困難。
主管還會問我:是否可以在台灣設計然後拿到大陸開發?我的回答也是:以現在的作法是不可能的。這是因為現在的設計者還無法寫出可以完整描述設計的文件,雖然現在公司已經導入CMMI,也規定出設計產出應有的章節,但是無法表現出設計精神的產出是難以順利開發的;更何況設計的人還沒有寫文件的習慣。
如何讓實作的人快速明白系統內部的設計概念是很重要的工作,因為讓實作人員依照設計用正確的順序呼叫正確的方法才可以保證系統的形成會符合設計;同時也因為設計的錯誤可能在任何地方發生,藉由設計概念的傳達也能夠讓實作人員協助發現設計時疏漏的問題。
訂閱:
文章 (Atom)