2008年1月31日 星期四

J16 目標是讓開發系統的經過有條理地呈現

一個系統的完成,是從客戶原先心裡的初步想法開始,經過需求訪談、需求分析、系統分析、架構設計、細部設計與程式實作所完成的。

想法變成系統的過程是經過很多次的討論與嘗試後所得到的,只拿到一個知道最後怎麼做而不知道為什麼要這樣做的原始碼,實在有太多太多之前的想法與經驗無從得知。另外一個困難的地方在於面對一堆程式碼時,無法肯定想找的功能從哪裡進入,進入之後經過哪些物件與方法且各負責什麼樣的動作。

因為需求變更或解決問題需要修改時更是頭痛的問題,不管是物件或是方法的重構上頭都綁住許多的程式區段,抽動這個時可能應付這邊卻沒法肯定有哪些功能同樣經過這裡、是不是會受到波及而有side effect,重構後擺放的方式是否與原來設計者的想法相吻合……等等令人頭痛的事必須考慮;而這些現象在大多數的系統開發裡都是無解的。

對於程式設計者而言,知道問題的產生原因後就能夠思考出對應的解決辦法。我想在這裡表達的,就是一個在某種程度上能夠避免上述問題同時不致增加太多額外投入時間的設計規則。

2008年1月30日 星期三

J15 輔助的文件(2)──單調的文書工作都寫小程式執行

前幾年看到有位同事臉色凝重,詢問後才知道主管要他統計約2,000個XML裡特定地方的值有哪些,而且各出現幾次,那時他只能夠一一去計算所以感到很難做。我自告奮勇地幫他寫了一個小程式去計算,大約一個小時後他就將結果寄給主管。

文字的整理與比對需要花很多時間而且容易出錯,在某些情況下還可能因為有改變而必須重新計算。這時不如寫個小程式來協助產出結果,耗費的時間可能差不多但是可以做到沒有錯誤,而且在修改時可以立即得到新的結果,同時還可以應用在其他類似的作法上。把單調的工作規則化寫成程式執行是我一向的習慣,除了避免無聊的重覆外還能小小磨鍊一下寫程式的功力。

許多小程式看起來只是使用在特殊情境之下,但是把所有小程式收集起來,在日後用到類似功能的情況時,就會發現其中一些適合抽出部分來作為API或是Compoent來使用。隨時隨地撰寫並收集應付各種狀況的小程式,對於累積個人使用的函式庫與元件庫是很有幫助的喔。

2008年1月29日 星期二

J14 輔助的文件(1)──選擇Excel作為快速記錄的文件

有位成員介紹了一個好用的Java讀寫Excel檔案工具──JXL。它提供了直接存取Excel檔案內容的Java API。

Excel檔案在某些概念上很像資料庫;檔案裡每一個Sheet可視作為一個Table,Sheet裡的Column相當於一個Field,而一個Row則等同於一筆Record。在應用上可以作出接近資料庫的資料存放,或是特定物件關係的追溯表格;在操作上可以使用API任意操作Sheet、Column、Row,同時也可以利用Excel內部的功能作排序、顏色強調等等的調整。

在不需要強調速度的文件轉換工作,可以將資料存放在Excel檔案裡依照需要轉出為各種不同編排的文字輸出;就像一種Model對照多種View的設計,只需製作一份資料就可以得到多種不同編排的輸出。而且使用它還具有快速編輯、篩選比對的好處,對我而言是個很理想的替代記錄型式。

註:一般在設計小型程式時若有儲存資料的需要時,我都視其特性使用XML或Excel作為儲存的方式。

2008年1月28日 星期一

J13 要堅持作Design Model或是先求完成功能?

文件有時候真的是很麻煩的東西,即使很努力且小心地逐一把物件與方法定義上去,還是可能有修改的時候;有時明明是兩個很相近的設計,但礙於其間的小差異又非得把幾乎一樣的東西再畫上一遍;有時則是希望可以得到兩層間特定物件的追溯關係,卻得在龐大的二維追溯表裡找出自己想要的資訊。

這當然有可能是自己沒能真正領悟出奧義時才有的迷惘,不過在身旁沒有高人存在的時候,一切都只能上網蒐尋相關的資料再憑個人的小智慧硬拗成可以解釋得通的理論,再用實際的專案加以驗證是否有預期的效果。原本認為Rose裡的UML是理想的設計表達,就在專案時程的壓力下也不得不妥協去找出具有用樣意義的記錄作法。

2007/11底設計好專案軟體架構並畫好Package Diagram與Class Diagram表達,就面臨著是否要花時間繼續畫很可能不符合實作的UML圖表。那時一方面寫信向主管回報狀況,一方面思考著要堅持Design Model,還是要先作出系統功能?長考兩小時後還是向現實妥協,以先有實際進度為優先(因為先畫UML再review實在是太花時間);但是準備好隨時可以找人快速地作出足夠文件的機關……。

2008年1月27日 星期日

J12 做人的方法(8)──自己少做一事,後人痛苦許久

常覺得“想偷懶”是人類能夠進步的一大動力,某些人為了減少日後花在類似事物上的時間,會先“多付出”心思設計一些東西來符合他的需要。在設計程式的時候也是如此,為了應付重覆動作的事情,會將之抽取成通用的步驟中處理而節省重覆投入的人力;而那些人力可能是自己也可能是別人。

同樣是“想偷懶“的念頭,有時卻會有迥異的影響。在撰寫某個方法的內容時,因為”不想多做“一些動作,而把應該拆開的東西寫在一起且省略掉應有的註解,反而造成後來程式難以看懂與維護的影響,而且影響的很可能同時是自己與別人。

最近有篇轉述文章提起孫運璿的事蹟(同時與某人作相對比較),還特別去找了他的小傳來看。傳中有段說幼年時候在大家庭仰靠大伯、二伯臉色,青年時又寄居世伯家裡,使它比一般孩子早熟,他必須替對方著想,盡量不要麻煩別人。我認為就是這個觀念讓他用高標準來要求自己做好,而不願使自己沒做到的事造成旁人的負擔。

“想偷懶”可能造成讓其他人有更省事的作法,也有可能使得大家變得混亂,這一切得看想偷懶時的出發點是為了什麼吧。

2008年1月26日 星期六

J11 設計的順序(5)──變化的參數

設計的時候時常會發現有數個動作除了該交給同一個物件處理之外,連執行的內容也是相近的,在完全相同的狀況當然該呼叫同一個方法,有小差異者則必須在呼叫同樣方法之時藉由某些傳入的參數改變內部的作法。

雖然在入口之處建議每個功能指向各自的方法,但是方法內部要如何實作則沒有限制。Copy-Paste是我最不推薦的方式,因為那又多生成了一段程式需要控管;最理想的作法自然是為原有的方法再定義一個多形進入的方法,導向使用原先就已定義好的設計。

設計時是由System開始逐層往下,Module、Component、Class逐一完成設計。設計的目標都是各階層之間的Interface(入口)、實作Interface的執行流程與動作,在架構本身完整的功能時,還必須要兼顧與其他設計項目的使用、合作關係,慢慢建立起穩定的系統。

2008年1月25日 星期五

J10 設計的順序(4)──動作的進行

把入口與流程視作為設計項目的表層,那麼每個動作的實作都是深入元件內部設計、藉由之前所佈置的物件各出己力而合作完作的。入口動作的分解呼叫程序是UML裡Sequence Diagram所要表達的,從另一個角度來看它又可以經由呼叫方向得到所有合作物件關係的Collaboration Diagram。

System:每個Use Case的Activity Diagram都應該至少對應一張Sequence Diagram。
Module:每個Module Interface Method都應該至少對應一張Sequence Diagram。
Component:每個Component Interface Method都應該至少對應一張Sequence Diagram。
Class:每個Interface Method都應該有一張Sequence Diagram。

動態的圖表主要以表達內部的呼叫關係與順序,如果有使用其他設計項目情形,就在圖表裡引用它的Interface Method作為標識。最初學著畫UML時把Sequence Diagram從最頂層的Use Case延路拉到最末端的Class Method的作法,這時回頭看起來根本是把自己搞累的錯誤。

2008年1月24日 星期四

J09 設計的順序(3)──靜態的佈置

把入口相關事項安排妥當後,接下來要配置設計項目內的物件,參考的依據是分析出來的動作該由什麼樣的物件來負責執行與應該準備什麼樣的資料,同時放置物件時應該注意到的從屬關係與特性定義。物件被設計出來以符合特定動作的執行,儘量使用一對一的設計而且每個物件都要具備Interface以便再作深入一層的分析設計。

System:下一層的單位是Module,在這裡應表現出System裡各個Module的從屬關係。(包含Interface)
Module:下一層的單位是Component與自有的Class,在這裡應表現出Module裡各個單元的從屬關係。(包含Interface)
Component:下一層的單位是自有Class,在這裡應表現出Component裡各個Class的從屬關係。(包含Interface)
Class:在這個步驟不需要表達Class內部的設計。

設計項目除了使用Interface定義它的責任之外,若幾個設計項目間共同具有某些特性的話,應將這些特性再使用另一個Interface來描述,並且讓設計項目的入口Interface繼承新建立的Interface,讓它完整具備應有的特性。

2008年1月23日 星期三

J08 設計的順序(2)──處理的流程

每一個操作功能從窗口的起始點進入之後,就屬於設計項目內部的處理。秉持著建立SOP的精神,從入口進來的方法應該決定它的處理流程作為需求規格的對應,以及設計規格的根據;一般在這裡所做的是製作處理的流程圖。

System:處理流程的呈現在Use Case的Activity Diagram。
Module:處理流程的呈現在Moudle Interface的Sequence Diagram。
Component:處理流程的呈現在Component Interface的Sequence Diagram。
Class:處理流程的呈現在Interface的Sequence Diagram。

在製作功能流程內容時,著重的是動作的定義與執行的順序[A05]。其中定義動作的粗細程度會直接影響系統設計的良莠,是最重要的部分;最好在定義動作時把自己的想法呈現出來,經由團隊成員的review以趨近理想的境界。

入口、流程與動作,這是在分析規格時絕對要認真思考的三大要素。

2008年1月22日 星期二

J07 設計的順序(1)──外部的定義

現在必須把設計項目(在我的定義裡指System、Module、Component與Class四層)視為一個封閉的單位,允許外部能夠操作這個單位的地方只有窗口的位置。設計的首要工作就是先決定好設計項目的窗口與其所負責的工作內容。

System:系統的窗口是Use Case,功能描述定義在Use Case Specification。
Module:模組的窗口是Module Interface,功能描述定義在Interface的Java Comment上。
Component:元件的窗口是Component Interface,功能描述定義在Interface的Java Comment上。
Class:Class的窗口是Interface,功能描述定義在Interface的Java Comment上。

窗口功能的定義務必採用一對一的方式,也就是一個明確的功能建立一個獨立的Method定義;即使是分析後獲得的子功能也需要建立一個自己使用的Method定義。就算有數個功能可以很明顯地定義為使用不同參數從同一個Method進入,也要強迫把它們一一獨立成不同的Method,如此才能明確地追溯每個Method向上與向下的使用關聯。

2008年1月21日 星期一

J06 設計沒有限制,但要定義適合自己的規則

人在世上本是自由的,什麼都沒有限制但是太過自由會影響彼此之間的平衡,所以形成了風俗與法律來約束各人的行為。系統開發也是如此,程式設計本來就是在語言的許可範圍內堆疊出功能的需求,可以自由自在地做出任何自己想做的樣子;但是要讓所有的物件依序運行的話,應該要定義屬於他們的常理才能讓它們維持長久。

之前有人說過OO語言既然擁有這個多好用的特性又允許開發人員這麼使用,就沒有不用的道理。我們去外地觀光時,有一條街上什麼商店都有,你有可能每一間店都去看嗎?優先瀏覽自己有興趣的商店,就是依心裡喜好選擇而使用部分事物不是嗎?為了某些更理想的目的而犧牲一部分便利的特性,這會是每個人斟酌是否願意去執行的考量之處。

通往完成系統的路有無限可能,從其中找出一條最適合自己與團隊的路是設計軟體結構者的責任。適合不僅是快速完成而已,還應該兼顧使用、設計、改變、抽離、更換、重用、教學等等。在這段時間的經歷中,我相信已找到最適合自己使用的結構與作法,這便是屬於我自己的“招意”。

2008年1月20日 星期日

J05 用不同的方式製作記錄

寫日記的方式同樣隨著科技的進步而改變。很早以前寫日記都會到文具行買一本日記本,用筆一字字地刻畫出心裡的感覺;電腦出現之後,比較懶得用手寫字的人開始用檔案來記錄日記,存放在私人的資料夾裡;等到Blog開始風行,有更多的人陸續使用它公開放置自己的日記。雖然日記記錄的形式一直改變,但是記下個人的經歷與心情的本質還是相同。

只是在不同的方式下會呈現出不同的內容。在日記本與個人檔案的記錄方式下,通常會勇於寫出所有發生的事,不管好壞都忠實地記錄,因為我們知道那些內容是寫給自己看的;但是在公開Blog裡的日記,一般都是遊玩或聚會的內容、或是正面的心情感受,極少會出現指出自己缺失並檢討往後要如何改進。即使同樣是記錄,也會因使用方式的不同而有所增減的。

開會或上課時同樣有許多人抄筆記,記錄下發言者講述的內容,但是遇到內容順序掉換或改變白板上的圖表時就會因筆記本沒法對應修改而感到無力;有時候的討論因牽涉到結構或流程而以紙筆來進行,幾次塗塗改改後紙上就一大片殘跡而不得不換紙。如今的我偏好找個白板邊討論邊修改,到最後定稿時再用相機拍下作記錄;這樣可應付隨時修改的需要,而且節省下作記錄的時間。

2008年1月19日 星期六

J04 融合OOAD與XP (3)──用其他門派招式演繹招意

接下來的目標是在領會出它的精髓後,用可以表達其意義的最小作法記錄出能夠讓人看懂的文件。套用武俠小說裡的講法就是“只求其意、不求其形“,領略到其中含意之後就可以使用任何招式演繹出應有的意義。

幾乎所有人都曉得UML是把不同階段裡的模型,由靜態與動態兩大類圖表來表達運作的原理,從需求收集、硬體架構到系統分析、系統設計每個階段都有專屬使用的幾種圖表。但是大家用歸用,雖然知道圖表想要表達的是該階段心裡的想法,但是除了表達與溝通之外如何使用UML來作進一步的分析與設計反而是常被遺忘的部份。

要表達些什麼其實是很抽象的,系統的模型該塑造成什麼模樣、依照什麼型態建立都是很模糊的定義,雖然有設計準則可供參考,但是每個人建立的模型卻是大相逕庭。招式雖然是用來演繹招意,但是在使用招式之前卻應該先弄清楚自己想要表達的招意到底是什麼才對;因為招意本身若未定義得清楚明白,接招的人同樣會是迷迷糊糊地什麼都搞不清楚。

2008年1月18日 星期五

J03 融合OOAD與XP (2)──使用招式領會招意

記錄是為了表達心中的想法,UML是OOAD採用的記錄工具,雖然它很適合分析與設計,但是建立各種圖表實在是很耗費時間的工作。既然留下想法的記錄並與他人溝通是它的目的,那麼應該明白透過UML可以留下哪些東西給其他人。

Use Case Diagram:系統的所有Use Case以及Actor、Use Case之間的使用關係;是SA的靜態圖。
Activity Diagram:Use Case裡Actor、System相互作用的流程;是SA的動態圖。
Package Diagram:系統各個部分的組件配置與關係;是Architect的靜態圖。
Class Diagram:可以表示各個組件、Component內部的設計結構;是SD的靜態圖。
Sequence Diagram:針對Use Case或是Interface Method內的程式呼叫順序;是SD的動態圖。
Component Diagram:描述各個Component之間的使用關係;是Component的靜態圖。

從幾個重要的圖表裡可以發現UML想表達的內容,在靜態上無非就是配置物件關係並定義應有動作[G15],在動態上只是顯示完成目標的物件動作內容與執行順序[G17]。

2008年1月17日 星期四

J02 融合OOAD與XP (1)──二者恰如天平兩端

OOAD強調的是對應,最理想的設計是做出一一對應的設計,在置換與改變時可以用影響最小的方式調整;想法採用UML作為記錄內容,循序漸進地從需求分析到系統設計詳細記錄下來。

專案進行之初,成員花了大約一週討論好系統模組與架構,並整理出大致上的Use Case List,依照理論接下來應該要製作所有Use Case的Activity Diagram;但是衡量了一下,大大小小的圖可能得畫上兩三百張,然後接下來是Class Diagram與Sequence,這些圖畫完並review到差不多正確為止,專案時間也差不多結束了。

當時心裡閃過的念頭是,在趕時間的前提下乾脆使用XP吧!可是講求快速完成正確的功能,其副作用就是系統的結構完整性很容易就被破壞;要堅持做出完全對應的設計結構,又必須付出許多時間作為代價。這兩者恰如天平的兩端在一些理念上各有擅長,而我面對著時程上的壓力,最後的決定就是找出兩者的平衡點──使用XP作出符合OOAD結構的系統。

2008年1月16日 星期三

J01 心裡的想法要用行動加以驗證

在I03-I05提出了幾個有問題的設計現象,像物件責任沒有對應現實、動作責任分配錯誤以及邏輯散落在多個層次等等。當一堆程式碼出現在眼前如果連入口都沒辦法知道,就會令人有無從著手之感,再加上因為觀念的混淆造成內容更難以看懂;遇到這種情形時,除了把程式放到一旁等人講解之外,對於一個系統被寫成這樣心裡其實感覺有點難受。

但是我們不能一味地說別人寫的程式有這些現象,因為只說別人的設計有問題而做不出真的令人感覺比較好的設計,那並不是有建設性的意見。在寫完第一部的OOAD想法後,很希望能進入一個真正的專案來驗證想法是否可行;剛好公司指派我從事改寫UI工具的任務,而且要與大陸那邊的一個小團隊共同進行。

專案從2007/11-2008/01,一開始想認真地用自己的想法來設計系統,但是在執行時遇到了一些難以繼續的困難。一方面改變進行的方式,一方面思考如何維持想做的事,一方面獲取經驗改良原先的想法,原先告一段落的寫作卻在新的想法不斷產生之下,為了繼續記錄而開始蘊釀。延續使用第一部裡的OOAD想法,接下來想記錄的是如何依序建立一個理想中的系統結構,是為了什麼目的而採用那些步驟的。