2009年5月29日 星期五

V22 程式碼註解解析工具的後續連結

這張是程式碼與相關文件經過程式碼解析工具處理後預想的關係圖,在理想的作法之下應該滿足全部相關部分的需要。簡單的說明如下:

●UML工具:從UML工具內讀取有用的資訊加以轉換到其他產出,或是從程式碼裡取得必要的資訊放到UML工具裡。除了程式碼與Model之間原有generate code與reverse之外,可以再擴充其他元素的雙向存取。

●各種文件:主要是要產出符合CMMI需要的設計規格書與追溯表,必要時也可以有流程圖。如果專案上有其他的需要,也能夠另外再設計不同的產出。一般會匯出的文件格式會是word、excel與pdf。

●元件庫:專案中適合reuse的功能元件要有納入元件庫的機制,屆時需要產出軟體元件的規格;專案在使用軟體元件時可以再匯入之前產出的元件文件作進一步的分析與追溯。

●問題單系統:搜尋特定的修改註解取得修改的程式與說明,自動填寫到問題單系統內同一單號的說明。這需要問題單系統提供API或是直接修改其資料檔內容。

●版本資訊:搜尋指定時間範圍的修改註解取得修改的範圍與問題原因(搭配問題單系統取得),以及受到影響的所有方法作為參考資訊。

●知識庫:搜尋指定時間範圍的修改註解取得修改說明,列出作為是否進入知識庫的備選。知識庫管理人員可以取得知識備選清單並與現有的知識庫內容作比對,以決定要不要放入知識庫並加上補充說明。這需要知識庫系統提供API或是直接修改其資料檔內容。

●系統測試:參考判斷條件、使用關聯與流程圖來決定如何編排測試個案,以涵蓋每一種條件變化的流程為目標。

2009年5月28日 星期四

V21 敏捷開發原則與CMMI精神的共存

閒暇時偶而會與同事或管理階層的人談起開發時程與彈性設計的問題,也會上網搜尋一下目前其他人對於設計的看法(中文網頁裡的)。得到的大致說法都是敏捷開發的原則是以快速滿足需求與變化為目標,而CMMI的精神會以檢驗各個步驟的產出來確認軟體製程的各個階段;前者認為軟體設計是多變的心智活動,後者則相信軟體可以像產品一樣由工廠來開發組裝。

某天與其他部門主管聊起時,談到OOAD設計與這兩者的關係,我強調說設計的物件能否完整地一對一對應到真實的物件才是最重要的關鍵。今天一個有三層結構關係的物件在設計的時候被縮減為一層,無論用什麼樣的方法論作出來的程式都會在需要切割時出問題的一天;反過來說只要物件結構能正確對應,無論用什麼樣的方式開發都不會出現切割的問題。

乍看起來敏捷開發與CMMI是沒有交集的,快速開發可能造成佈置的雜亂(所以需要重構來調整),設計的完整會耗費許多時間製作文件,因此幾乎所有人都不認為它們可以相輔相成。經過這兩年的思索,我認為唯有使用"固定且具有彈性的統一軟體結構"才能滿足快速與完整的並存,同時再夾帶讓全部開發人員(不限同一個開發團隊)能快速明白設計概念的好處。

將軟體切割為靜態結構佈置與動態方法設計,作好完整的靜態結構佈置後以敏捷開發的原則進行動態方法設計,通過各個階段測試之後再運用工具程式解析以產生CMMI需要的文件。這些想法的關鍵都已經在這兩年陸續在實際工作裡加以驗證,有絕對的把握可以實現。

雖然要事先開發好所有的工具的確需要不少時間,不過在下一章會先說明專案開發時大致的流程、作法與需要的工具,並且構築出一個完整的開發roadmap。

2009年5月27日 星期三

V20 修改的追溯(3)──系統追溯總表與關聯搜尋工具

在系統要出一個新的版本時,輸入上次出版日期與這次出版日期,修改註解收集工具應該要能收集到程式碼內的所有修改記錄,進而輸出在Use Case層面的追溯總表。這份表格可以作為迴歸測試的參考標準。在理論上還可以更進一步作出每一個修改所影響的是呼叫它的方法裡哪一個判斷條件,這將是最為精確的結果。

應該追溯的當然不只是系統的Use Case,呼叫的歷程中每一個部分都應該要能夠被定義出來,這樣才能夠對中間的所有元件重作單元測試。如果有作好Unit Test的話只要知道元件後自動重作全部測試觀察是否有錯誤,然而有時還是得知道到底是哪裡被影響到。目前的IDE工具可以直接看到呼叫指定方法的全部關聯,卻仍無法向下呼叫的關係。

我的想法是製作一個工具,先分析出系統元件間的使用關聯。使用者在系統元件樹狀圖裡選擇指定的數個方法(或從產出的修改彙總表匯入)後,就直接在向上區與向下區用樹狀結構的方式表示各個相關的呼叫結構。其間也可以用滑鼠點選擇集合裡的任一個方法限制只顯示與之有關的。最後還可以匯出找到的關聯集合作為參考或正式記錄。

2009年5月26日 星期二

V19 修改的追溯(2)──時間與空間交集的修改集合

對系統來說雖然切割的單位是Package,但是在意義上應追溯到Method才是最精確的。然而一般的作法光是追溯Class都已經很難正確,更何況是要到Method。一個略具規模的完整Class-Class的追溯表大概可以到1000 X 1000的矩陣,到Method更不用談了;不過追溯並不是一次要看全部內容,而且侷限於需要看的部分。

需要看的追溯通常有兩種:從上往下的追溯與從下往上的追溯。想要從功能面上取出一個獨立的模組或功能時同時需要哪些物件,可用自上往下的使用關聯取得完全的集合;想要從中間一個方法得知在這個系統裡,總共有哪些地方的方法直接或間接呼叫到它,就是從下往上的追溯。理想的追溯是指定一個方法之後同時追查出所有向下與向上的全部關聯。

對於修改歷程的集合,除了要可以定義變動程式碼的範圍之外還要可以調整時間的範圍,這樣才能夠定義時間(像版本之間的時間)進而找出變更的空間(異動程式與向上追溯)。在任意變換的定義時間帶與定義的Project裡找出變更與影響集合用人工是很難作好的,無法正確地定義影響的範圍正是為什麼造成品質不佳的原因。

把這個很花時間的功能自動化後,任何時候都可以查出當時有哪些修改;唯一要多作的只是多註記問題單的編號註解。

2009年5月25日 星期一

V18 修改的追溯(1)──修改處的註解與收集程式

一個系統上的問題通常會在問題單系統裡建立一張問題單並給予一個編號,程式人員會針對解決這個問題而修改一些程式碼。以往的作法是填寫一份問題報告,描述問題的產出與解法,並記錄改了哪些程式;程式部分也另外填寫到一份release notes等到要上新的版本時,可以知道共有哪些程式需要更換。

版本-問題單-修改的程式是除錯與維護時物件的關聯,其中最基本的是問題單與修改程式間的關係。假設有一張問題單單號1234的錯誤在於初始值給錯,那麼就用根據本章前面所提的註解原則來修改程式並填寫註解。
  /*
   * 記錄索引的變數給予初值.
   */
  // index = -1; /* IR=1234 */
  index = 0; /* IR=1234 */

原則固定之後,註解處理工具就需要多設計一個程式來收集這些資訊。從最底層起要做的事有:
●每個Method裡為了每張問題單所修改的全部程式碼。
●每個Method內處理過的問題單集合。(回填到Method註解)
●每個Class內處理過的問題單集合。(回填到Class註解)
●每個Component內處理過的問題單集合。(回填到Component Interface註解)
●每個Package、Project直到workspace內處理過的問題單集合。(回填到對應的註解說明)

確認每個階層可以收集到所有填寫的修改註解,同時更新到Method、Class的註解裡是這個階段所要達成的目標。

2009年5月22日 星期五

V17 Sequence Diagram──一次只能表達一種呼叫順序的圖表

雖然Sequence Diagram是UML的一種標準圖,但是由於它只能表示在某種情況(通常是導向正確結果的流程)下的物件互動順序,沒有辦法表示分歧點判斷後的差異,因此我並不喜歡使用這張圖而寧願用Activity Diagram或流程圖來完整地表達。

有位曾共事的同事在討論時喜歡用Sequence Diagram表達物件的關係,無可否認地依序表達物件的合作關係時是非常清楚的,轉換為Collaboration Diagram時也可以立即知道達成功能時所需物件的關聯,然而無法立即由一張圖就知道整個功能的處理流程是十分不便的。

在不想繪製這張圖時,許多IDE工具提供在執行同時產生Sequence Diagram的功能。在IBM RSA 7.0(含)之前的版本是從頭到尾的呼叫流程都擠在一張圖而無法分割,這樣的圖表更是難以看懂其中的設計。不過這麼鉅細靡遺的圖表放到CMMI的設計規格書裡倒是挺適合的──反正許多規格書都只需要填滿指定的章節就好,並沒有人要求內容的正確性與適當性。

我認為Sequence Diagram如果增加branch node與merge node的定義後就會非常理想,但若是在分析設計Method的同時,把每個Activity都一對一對應到一個呼叫的Method的話,Activity Diagram就等同於Sequence Diagram的意義而不需要再重覆製作。而且這張圖表可以藉由程式流程Data Model自動產生出符合該Method層級的流程圖,比較起來反而可以省下更多製作圖表的時間。(若應用swinlane區隔出每一個不同activity所存在的物件,同樣也能夠產生Collaboration Diagram)

對於這種區解原意的應用,應該會有理論擁護者發出不平的聲音。理論難以應用時應該修改理論使之符合實用,而非堅持大師的想法造成無法進行的瓶頸。

2009年5月21日 星期四

V16 流程的存取(3)──從程式流程Data Model產出流程圖

一個Component Interface Method的實作會產生一組對應的程式流程Data Model,這個集合的內容應該產生一張對應的流程圖。同一個Component的流程圖要收集在一起,因為那是元件內部的完整流程說明文件。

處理的過程其實不難,依下面的順序進行:(依集合內程式流程Data Model的順序)
●逐一在流程圖上建立對應的節點,並標示節點名稱。
●根據程式流程Data Model內的關聯定義建立節點間的關聯,並標示關聯資訊。
●自動排版所有節點。
●自動命名與存檔。

困難的其實在於工具的配合,在2009/04看過幾套UML工具只有JUDE/Professional有支援API存取物件(US$ 280,但不知是否支援繪圖),其他像Rational Rose、StartUML、JUDE/Community都只能在產生報表時選取輸出的物件而沒有提供操作的API;即使是Microsoft Visio也只有data link API而沒有提供圖表的。

目前的潮流是先畫流程圖再產生程式,如果找不到用程式產生流程圖的免費工具,未來在實作這個功能時真的得另外製作一個用API畫流程圖的工具了。

2009年5月20日 星期三

V15 流程的存取(2)──Flow與Action方法的處理原則

處理的範圍限定在Component內部。首先要將Component內部的Implementation與Flow兩類方法收集起來,這是流程進行的範圍;Action方法原則上不用處理。倘使Action方法也有製作流程的需要,則把被Flow呼叫的Action視為範圍再進行Action方法的流程分析。

一開始要定義一個迴圈逐一處理每一個Component Interface Method,先進入Implementation方法再依程式流程進行,每遇一個定義上的node就產生一個對應節點收集資訊。在流程上,只要是Implementation與Flow方法的就必須進入該方法處理;在動作上,如果呼叫了Action方法或是其他Package的方法則註解為一個activity node而不要進入該方法。不應該遞迴處理到其他Package的內容,因為那會使得流程記錄得太細而失焦,難以看出現在層級應該注意的過程。

某Flow方法在內部呼叫同Component的另一個Flow方法時,該建立一個中間點將兩個Flow分成兩張圖來存放?或是不管呼叫的間隙而將全部的流程串成一張圖呢?這應該選擇後者。一個Component Interface Method的實作是一組獨立流程,部分流程會被抽成另一個Flow方法是因為它們在意義屬於某一特定目的,但仍是原來流程的一部分,因此串成一張完整的圖會比較易讀;況且圖是自動產生的,也不會太大張。

一個Component處理後再接著換另外一個,直到指定範圍內所有的Component都被處理完為止,這樣我們就拿到了所有Component Interface Method的程式流程Data Model。這時要設計一個中間檔的存放機制讓這些程式流程Data Model存成檔案,日後要轉換時再讀入處理而不需要每次都重新處理。

2009年5月19日 星期二

V14 流程的存取(1)──程式流程Data Model

接下來討論的是程式流程圖的產生。由於繪製流程圖的工具非常地多樣化,所以不應該直接把程式流程輸出為流程圖,而應該先設計程式流程Data Model先將程式碼的流程轉入,然後再根據實際使用的流程圖工具製作匯出程式。

一開始應該先分析流程圖裡面所包含的元件種類以建立對應的物件。我參考的是Activity Diagram內使用的圖形,能夠用最簡單地圖形表達出設計的意義可以降低複雜度。
●start node - Flow方法的進入點
●end node - 遇到return或是走到Flow方法的盡頭
●branch node - 每個判斷條件會對應到一或多個
●merge node - 每個判斷條件block的終點
●activity node - 不在判斷條件裡的動作

Flow方法裡只有變數宣告(activity node)、執行Method(activity node)與判斷條件(branch node、merge node)等三類敍述,判斷條件內除了java的關鍵字外就只有判斷式(branch node、merge node裡的condition),因此Flow方法的敍述在理論上都能夠對應轉換為程式流程Data Model。

每一個程式流程Data Model都還要包含指向下一個node的指標(end node)沒有,branch node得有分歧條件與對應節點的集合才能建立正確的資訊。在非分歧條件下的程式碼毌須解析內容,只要把找到的註解都轉換成一個activity node即可。

2009年5月18日 星期一

V13 自動補齊註解(8)──匯入底層元件的註解產出

在workspace裡的程式碼都可以使用工具達到上述的註解產出,但是在使用軟體元件的同時,要是那些Jar File有改變的時候該怎麼辦?要怎麼找出系統被那些影響變動的範圍呢?很抱歉,截至目前為此沒有辦法──除非再設計一個功能。

想像把一組很多層次的Package從中切分為二,上面放在workspace裡而下面是Jar File,差異就在於沒辦法取到下面的註解加以分析並放入集合。那麼取代的方案就是:擁有元件程式碼的人應該先分析註解並產出結果,專案就在工具裡匯入產出結果成為註解集合再繼續處理,這樣就可以解決這個問題。(匯入不能只限一組,要能同時匯入多組資料)

匯出與匯入都應該以上述所有註解分析結果為範圍,感覺就像真的剛處理出來的結果一樣才不會有落差。在優先度來說,專案的改變要比元件的改變容易發生,所以這個功能的需要就沒那麼急迫。

直到這裡,才算完成所有與註解相關的自動化部分。

2009年5月15日 星期五

V12 自動補齊註解(7)──產生Interface Method的使用追溯表

每個Package的使用關聯集合如果都建立起來,除了可以快速地向下找到有關係的Package之外,還能夠搜尋到所有向上的被呼叫關係。如果有耐心作完全部的設計,追溯甚至還可以精確到Interface Method的程度。

公司定義的CMMI文件裡追溯表格只有三種:Use Case-User Case(水平)、Use Case-Class(垂直)、Class-Class(水平),這對於實際的系統設計來說是沒有對應且涵蓋度不足的。在我看來至少要有這些追溯表格:Use Case-Use Case(水平)、Use Case-Package(垂直)、Package-Package(水平)、Package-Class(垂直)、Class-Class(水平)。

仔細分析的話,可以發現追溯的根本是依層級來記錄使用關聯,Package-Class、Class-Class收集的是Component內部的使用關聯;Package-Package則必須收集每一個Component之間的使用關聯加以記錄;Use Case-Use Case、Use Case-Package這兩張表格在意義上也等同於Package-Package的作法(Use Case的入口方法都被收集在特定Package下)。

最完美的使用追溯表應該記錄到Method間的呼叫,但是攤開來看的話可能會大得太離譜。為了因應實際會需要尋找指定某個Method後列出呼叫它以及它所呼叫的所有關聯,勢必需要再設計一個查詢工具,指定一些Method後列出上下的全部使用關聯。唯有這麼作才能精確地圈選出修改後所有的影響範圍。

2009年5月14日 星期四

V11 自動補齊註解(6)──依階層收集Method註解

Method是底層的行為單位,再往上的組織階層有Class、Package。既然Package擁有多個Class,而Class又擁有多個Method,那麼在集合的層級上匯總集合元素的資訊也是應該具備的功能。

回顧前面的章節所做的事,在彙總註解內容時首先要作到的是格式檢查與基本資訊的產生,第二是宣告時繼承與實作對象的註解(Class),第三是全部的使用關聯與判斷條件(註明在哪裡用到),最後則是修改的目的與記錄。處理的流程就定義迴圈,然後依序收集全部應該要收集的註解。

收集所有的Method註解後的內容很多,Class的註解可能會變為上百行之多而難以閱讀,Package層級則會面臨到沒有可放置單一註解的地方。因此建議Class的基本資訊、宣告內容與修改歷程放在Class的註解裡,使用關聯與判斷條件則另外產生外部檔存放(這部分也可在需要用到時再產生);Package則收集修改歷程、使用關聯與判斷條件另外存到外部檔案。

Package的資訊只需要收集屬於自己內部的資訊,不需要遞迴向上彙總。每個Package都整理好本身的資訊後,在Component、Module等級的Package就可以遞迴向下收集使用關聯,知道到底使用哪些Package後就清楚重用這個Package時還需要連帶哪些Package。修改記錄的收集用途亦是讓我們可以立即知道該Package下全部的變動。

收集全部Package使用關聯的過程中,還能夠建立使用Package間的垂直與水平追溯表。

2009年5月13日 星期三

V10 自動補齊註解(5)──修改的程式與修改記錄的列表

註解的處理約略分為三個層次:靜態的Class與Method宣告、Method內動態程式收集、還有現在要討論的修改記錄列表。我們期望所有的修改在依照規定作好註解之後也能夠被這個工具分門別類地收集在註解裡,然後使用修改追溯的功能找出全部應該測試的範圍。

每一次的修改都應註明日期,版本屬性可以使用人工填入,或是在統一處理的時候依照版本時間來區分該次修改屬於哪一個版本。修改可能是Method的宣告或內容修改。對問題單而言,根據此單號修改的部分是解決問題的方法;對Method而言,把屬於自己的修改資訊收集起來就是全部修改歷史;對版本而言,落在指定時間範圍的註解就是這次版本所有的修改。

原先的修改記錄都是手動撰寫在另一份文件或是問題單管理系統,要說明修改的原因同時附上修改問題時動到的程式碼片斷。之前在維護公司系統的時候,修改程式與單元測試如果花費一個單位的時間,那麼比對與commit程式加上填寫修改報告就大約要再花費半個單位的時間,對效率的影響是很大的。

製作自動產生修改報告文件的工具可以增進維護人員的效率,再搭配後面所提之修改處對應的測試範圍更能保證精確地測試到應該測的部分。不過要達成這些功能的同時,需要先嚴謹地定義各式註解代表的意義與擁有的欄位,才能令處理工具正確地處理程式碼的各個區塊。

2009年5月12日 星期二

V09 自動補齊註解(4)──Method使用關聯與判斷內容

在處理Method流程的同時,我們可以拿到Method裡每一行敍述所操作的方法,收集每一個方法內所呼叫的全部方法(不管是元件內部或是其它的Component Interface Method),就能夠再作進一步的分析使用。

對一個Method而言,解析過裡頭的程式碼同時收集所有呼叫方法意義是:該Method所使用的全部Method有精確的範圍。再進一步地分析,方法有無論如何都會執到、提供條件敍述判斷用、滿足特定條件判斷才會執行到的三種類型,第一種表示的是百分之百都會用到的動作(include)、第二種表示的是造成處理流程分歧的判斷(decision)、第三種表示的是前述判斷條件成立後才會執行到的動作(exclude)。

方法使用關聯的應用意義在於追溯,從Use Case Method往下看是完成所必須具備的全部Method,從指定Method往上看則是找出每一層直接或間接使用它的關係;關聯的層級也可以從Method可以推展到Class。以此為基礎產生出來的就會是各個層級裡所有Class(或Method)的水平追溯與垂直追溯,在Class層級等於Use Case層級時,拿到的是Use Case的水平追溯與垂直追溯。

在條件敍述裡判斷的方法可以被另外區分出來,涵蓋所有條件分歧路線與所有條件值的測試才會是完整的。經過這一層的處理,應該還可以產出所有影響分歧條件的Method清單並同時收集每個條件Method本身全部的可能傳回值,撰寫Test Case時可以快速參考所有可能的變化加以設計測試。

使用與判斷的資訊我認為放在Method的Java Doc比較符合其存在的位置意義,經由處理程式自動產生,並在日後每次執行的時候自動修改這個部分的內容。

2009年5月11日 星期一

V08 自動補齊註解(3)──補齊Method內的程式碼註解

元件六個部分裡Properties、Model與Exception的程式碼是簡單到不需要用註解說明的,自動補齊程式碼註解的對象是Implementation、Flow與Action。依照我的設計準則,每一層被上一層呼叫到的入口Method都應該只用程式流程的敍述來呼叫實際動作的方法。

流程相關的方法有以下五種,標示種類為流程者表示內部應只放流程敍述與動作方法呼叫。
●Implementation Method(入口方法)
 beforeInvoke()與afterInvoke()內放的是流程,細部的動作只能是Flow Method或是其它的Component Interface。
●Flow Method且被Implementation Method直接呼叫(被入口方法呼叫的流程方法)
●Flow Method但只被Flow Method呼叫(內部流程方法)
 以上兩種都屬於流程,細部動作只能是Flow Method、Action Method或是其它的Component Interface。
●Action Method且被Flow Method直接呼叫(被流程方法呼叫的動作方法)
 這屬於實作流程,細部動作只能是Action Method或是其它的Component Interface。
●Action Method但只被Action Method呼叫(內部動作方法)
 這屬於實作流程,細部動作只能是Action Method或是其它的Component Interface。不過到這層應該大多都是呼叫很底層的API,產生的流程內容已經不易讀懂。

除了最後一種Method之外,其他種類的Method只能放置流程控制的指令。為這幾種指令定義好註解的範本,再從實際執行的方法註解裡取得第一行的功能簡述嵌入到註解範本裡,產成註解結果後放置到程式碼前即可。依序執行每個Class的每個Method裡的每行程式,就可以用同樣的方法產生全部的程式碼註解,並可以隨時依真實的註解同步最新的內容。

2009年5月8日 星期五

V07 自動補齊註解(2)──Method的傳入參數與傳回值

版權宣告與Class註解僅是靜態的說明,解析的重點還是在於Method。Java Doc的最基本是說明Method的功能,使用param記錄傳入參數名稱與類型、return記錄傳回類型、throws記錄拋出的例外類型,都與Method的宣告行有關。

設計者在改變方法宣告的同時,不一定會去更正Java Doc的內容,因此仍然需要加上自動補齊的功能令它們同步。註解需要的內容都可以從Method宣告行拿到,列出的資訊與Java Doc轉成的Data Model比較後,刪除多出的屬性、自動補上缺少的欄位並調整順序以符合Method的宣告。自動產生的部分應加上標示(例如[AUTO])以方便事後搜尋出來作人工的調整。

開發團隊都會定義自己所用的Naming Rules,在處理Class與Method的同時也可以依照規則檢查各個屬性的名稱;同時也可以檢查屬性名稱後是否有加上說明。以上應有而未有的註解可以在應加上的地方註明[TODO]表示少了些東西,以便快速定位後補加上去。

到現在為止處理的是Class與Method宣告的部分,在詳細描述的區塊務必在先用第一句簡短地描述其功用,後面再跟著註記詳細的說明;這是因為未來需要Class與Method的註解時會取得第一個句子作為使用內容(避免內容過多)。

註:如果Method是實作Interface或是覆寫父類別的Method,就不要在這層產生宣告註解而應該產生指向宣告的註解內容。

2009年5月7日 星期四

V06 自動補齊註解(1)──格式正確性與基本資訊

註解是人為按照格式輸入的,編輯器會自動檢查註解是否有造成程式編譯不正確的錯誤,但是註解內容的格式就需要另外用工具來判別。除了檢查格式之外,應該同時從預先建立的基本資訊檔裡取得對應的內容自動地放入註解並儲存。

package宣告之前通常應有版權宣告段落,class註解內通常會有since、author、version;Method註解雖然有param、return、throws但是打算也加上since、author等資訊,這是因為Method可能會因重構移動到其它Class裡而造成資訊的錯失。

雖然Eclipse可以匯入標準的註解格式,但是格式可能因不同的需求而修改存放資訊,在需要變動的時候絕對不會有人一一將成千上萬的Class取出來重新調整;同樣地如果有人忘了匯入而造成缺少註解內容,若那人不動聲色地放入儲存庫也不見得有人發現或是會更正。用自動的功能消弭掉人為的誤差讓所有的產出一致無論在什麼領域都是非常重要的事。

整合以上的需要註記的欄位就是應該放在基本資訊檔裡的資訊,這些資訊區分為公司通用(版權宣告)、版本使用(version)、個人專用(author)與時間相關(since、版權宣告裡的年份),設計時依不同用途放置在不同的資料夾中備取。處理時若有缺少的欄位就從資訊檔取得,存在的欄位再定義檢查的規則看是否有誤。

2009年5月6日 星期三

V05 註解的存取(3)──取得註解的內容

為了確認Java程式碼與註解的關聯,實際在workspace裡測試了Eclipse JDT的功能。JDT裡共有兩個系列可以處理Java程式,分別是CompilationUnit與AST。

AST採用DOM的結構方式解析程式碼,從Class、Field、Method甚至是方法裡的Block、Statement都能找到對應的物件,不管是解析的深度(CompilationUnit只能拿到Class、Field與Method)或是API的便利都比CompilationUnit好用。但是AST從Eclipse 2.1起就因為註解的複雜而取消在Block與Statement上附帶Java Comment的功能,只在Type(等同於Class)層級集合該程式的全部註解;無法建立註解對應程式碼的關聯,這對我後續想做到的事是沒有幫助的。CompilationUnit的解析沒有進入Method內,也沒有提供直接取得Java Doc的方法,但是各物件都提供了getSource()的方法可快速拿到包含註解與宣告的程式碼。

程式碼的註解的確會造成判讀的困擾,像是因修改而註解掉的程式碼就很可能被視為下一行程式的註解。為了讓程式明白地知道該註解是資訊還是修改記錄,必須定義不同用途的註解方式:像是註解的程式碼一律在行首使用 // 、設計的記錄與屬性都用多行的 /* */ 包覆該程式碼前一行、修改的簡要資訊則先用單行的 /* */ 放在程式碼後讓處理程式整合到設計記錄。

用程式來處理程式碼是我想做的作法中最關鍵的技術。尋常的程式設計的自由度會令程式區塊內的意義不夠精確,所以要先定義每一個細部單位的意義;再來是解析後儲存的集合與每一個單位彼此之間關聯的建立。根據後面想要達成的功能,將會陸續明白需要在哪些地方建立什麼樣的關聯,這也必須加以明確的記錄。

至於要用哪一種技術來解析程式碼,現在也還不能決定。目前比較偏好CompilatoinUnit加上自己寫程式分析更細部的source,不過解析方法純粹自己撰寫也是能夠接受的選擇。後面的文章會暫時假設所有程式碼與註解的解析都百分之百正確,以此為基本前提來討論可以自動產出些什麼。

2009年5月5日 星期二

V04 註解的存取(2)──處理註解的順序

要開始撰寫處理註解內容的工具的準備工作有三個:首先要定義好註解的格式與對應的Data Model,再來是用什麼樣的流程來通過全部有註解的地方,最後則是用什麼樣的技術來取得該地方的註解內容。

現在有定義的程式註解全部都放在Java檔案裡。這裡需要用兩個方向來看待之:在Eclipse的workspace結構裡Java檔案的放置方式,與取得Java檔案後如果解析內部的結構。

要在workspace裡找到Java檔案,結構的層次依序為workspace、java project、source folder
、package四層(雖然package真實的資料夾結構是多層的,但是在Eclipse裡已經壓扁為一層),這意味著每一個層都得準備一層迴圈來重覆處理,同時在每一層的迴圈裡可能需要有自訂處理範圍的功能(初期先全部處理亦可)。經過這四層迴圈就可以取得全部的Java檔案作後續處理。

Java檔案的內部結構是Class(Interface)、Data或Method、Method內部的程式碼,其中Data與Method之間沒有關聯但是在一個Java檔案裡都是零到無數個的。所以處理一個Java檔案時要依序取得Class(Interface)註解、所有Data註解、所有Method註解與所有Method裡所有程式Comment,在取得的同時也要將關聯資訊放入註解Data Model。

在處理程式裡取得的註解Data Model都要依照結構放入對應的cache,目的是希望隨時都可藉由package、class、data與method等等的關鍵字找到對應的註解Data Model,處理完後全部的註解Data Model還必須匯出到現有的Java檔案裡一同儲存才算是完整的處理。

2009年5月4日 星期一

V03 如何寫好作文

作文的基本結構其實很接近Use Case-Scenario-Activity,可以用top-down的設計方式來鋪陳文章的內容。

先將整篇作文視為SRS(System Requirement Specification),作文的題目就像是Use Case Name,用很少的字數來表達全部文章的功用;SRS的第一個章節是描述Use Case目標的詳細說明,那麼第一段就可以先用較多的字數闡述主題(這適用於論文,記述文不要用)。

再來就要先在腦海裡製作文章的scenario,進入前的準備、起點、詳細流程、流程中各種可能分歧與最後的狀況,這些scenario相關的部分都必須先構築完整才能進行下一階段。如果流程只有一半就開始寫作,很有可能會跟現今的專案一樣寫到一半才發現流程有不足之處而難以收尾,屆時不是改寫出問題的那一段就是草草結束,這些都不會有好結果的。

如果需要其他看法的scenario佐證自己的論點,記得也要一併思考。能夠整合為一個流暢的scenario的話就一起表述,否則就依序分開寫作,但是要小心不要有前後的衝突而自打嘴巴。各個scenario都陳述的最後用一段結尾來說明這個Use Case採用我們上面作法的優點或是延伸的感想。這樣一來作文的全部架構就大致成形。

接著進入細部設計。scenario裡的每個activity是句子的集合,要決定用哪幾句話的句意來達到activity的目標,同時再設計每個句子裡要用什麼樣的字詞組合。心裡的模型如何拆解為對的句子順序關係到流暢度,記憶了多少字詞關係到可以選用的API多寡,這無法投機而要看各人事前所作的修行。組合之後再運用重構的想法調整用字遣詞與前後關係,確認後再落筆撰寫。

慢慢寫出心裡的結構與內容完成作文後,記得再閱讀一次測試來找出不理想的地方修正。通過測試後就可以無怨無悔地交卷了。

註:我的高中聯考作文分數為50.5/70、大學聯考作文得分也超過60%,這個論點應該很具有參考價值!

2009年5月2日 星期六

V02 註解本體的內容與註解的放置

註解要怎麼寫才是理想的?在網路上能找到一些不同的說法。比較普遍接受的說法是不要記載程式碼怎麼寫的,而要記錄為了什麼目的而寫這些程式碼;因為註解是為了讓其他人快速地看懂自己為什麼要這樣寫。對於這個看法我沒有異議,方法有自己必須達成的目標,方法內的一連串註解是達成目標的分解動作,一組詳細記錄的註解其作用有如該方法的SOP般讓所有人都能很快地看懂怎麼樣來完成。

註解以精簡為目標,但是在較艱深的場合還是附上簡短的範例說明較為理想。如果把人腦視作一部電腦,撰寫某段程式碼後寫出的註解就像是把當時的想法匯出為文字敍述,驗證註解內容是否恰當的一種方式,就是經過較長一段時間忘卻後讓原撰寫者看自己原來所寫的註解,倘使能夠讓自己完全回憶起當時的情景就是滿足所需的註解。

目前Class、Method與Data的Java Doc註解,以及程式上的Comment都跟著程式碼走。前面的Java Doc只存在於靜態說明的地方,即使屬性加多後行數增多,並不至於影響閱讀;但是Comment一般都要求越簡短越好,用我的方法製作Comment後勢必使得程式碼間的間隔拉大造成不易閱讀的現象,這並不符合普遍的需要。

龐大的Comment或許可以脫離程式另外存在?這是讓程式碼變回較易讀的方法之一,但是Comment與程式分離之後必須有自己的管理機制,同時還要建立Comment與程式碼的關聯。程式碼是非常易變的東西,建立在易變的基礎而且必須另外同步更新Comment勢必浪費非常多的時間。顯而易見地,這是一個蠢解法。

既然目的是在擁有詳細的註解時維持程式碼的可讀性,那麼可以學習Eclipse作法,在Java編輯器上把Comment區塊縮減為一行。開啟一個Class後其實我們可以發現有很多地方可以收合,像是最前面的版權宣告區塊、所有的Java Doc註解與Method的程式本體都是如此,但是對於Comment就沒有這樣的功能。改寫Java編輯器使之對Comment也有收合與展開的功能,就可以達成目的。

2009年5月1日 星期五

V01 註解的存取(1)──定義註解的格式

以下的各種註解範例取自於JDK 5.0裡頭的java.lang.StringTokenizer。

/**
* Class Description....
*
* @author Lee Boynton
* @author Arthur van Hoff
* @version 1.189, 10/21/05
* @see java.lang.Object#toString()
* @see java.lang.StringBuffer
* @see java.lang.StringBuilder
* @see java.nio.charset.Charset
* @since JDK1.0
*/
這是Java Doc對Class的註解範例。很明顯地具有描述的本體與下面用@符號開頭的屬性,屬性可能具有多個值。

/** Field Description.... */
private final char value[];
這是Java Doc對Data的註解範例。只擁有描述本體而沒有任何屬性的結構,很明顯地是Class註解的子集合。

/**
* Method Description....
*
* @param codePoints array that is the source of Unicode code points.
* @param offset the initial offset.
* @param count the length.
* @exception IllegalArgumentException if any invalid Unicode code point
* is found in codePoints
* @exception IndexOutOfBoundsException if the offset
* and count arguments index characters outside
* the bounds of the codePoints array.
* @since 1.5
*/
public String(int[] codePoints, int offset, int count) {
}
這是Java Doc對Method的註解範例。註解的屬性名稱雖與Class註解有所出入,但是基本的結構是一致的。

/* Reset these anyway */
delimsChanged = false;
// The array representing the String is the same
// size as the String, so no point in making a copy.
v = originalValue;
從String與StringTokenizer裡發現兩種不同的註解類型,都是合法的Comment。它們都只具有描述的本體而沒有任何屬性,與Data的註解結構相同。

2000年的時候曾經維護過某大公司應用在銀行的大型產品程式碼,註解裡鉅細靡遺地記錄著對應程式碼的修改歷程,每筆記錄存放了修改日期、修改人員與修改原因的資訊,同時Class上也收集了Class內所有的修改記錄,看起來非常地清楚。因此在註解的設計裡同樣選擇採用這個制度,讓修改歷程放在註解裡跟著程式碼走,額外再使用Java Doc的標籤讓這些記錄可以出現在產出文件裡。(以前的產品只能用文字搜尋)

U22提到了收集所有註解另外處理的功能,經過收集後的註解已經與程式碼脫離,所以需要額外的欄位來定義與其相關的程式部位:Class、Data註解需要記載屬於哪一個Class,Method、Comment註解需要記載屬於哪一個Class的Method,將這些資訊定義在一個關聯用的Attribute(id)裡。

以上是註解Data Model結構(U23)的基本設計依據。