:::

論文進度報告(2010/8/29):UML再開

布丁布丁吃布丁

論文進度報告(2010/8/29):UML再開

image

兵荒馬亂的過了兩個禮拜,現在繼續進行進度報告。

UML也可以用來寫JavaScript,而且意外地好用

上一次的進度報告中提到我寫JavaScript寫到打結,一不小心就把一個物件的責任切割到三個程式裡面,讓整個程式非常地複雜。回頭去看原本做的UML,卻與實作的方法有很大的差別,於是毅然決然地捲起袖子,停止程式撰寫的工程。又回來重畫UML。

加入Toolkit

toolkit

這次最主要的是加入了許多Toolkit。把撰寫PHP時學到的Generic Object應用到現在撰寫JavaScript上,就可以歸納出KALS_user_interface跟Event_listener等常用且重要的工具。

整理core、toolbar跟window

有了Toolkit的這些類別之後,我就能將之套用到其他類別上。

  KALSContext[1]

首先是整理core圖片,原本的UML如上圖,這是包含了KALS_context跟KALS_util的部份。

core

經過修改過後,你可以看到UML變得複雜很多。不僅利用了框線的顏色、背景的顏色來辨識各類別的特性,也使用紅色(未完成、處理中)、藍色(完成)來區別工作的進度。

這次也把屬性與方法做了權限的區分。公用權限(public)沒有標示,私用權限(private)前面加入「_」,保護權限(protected)前面加入「_$」。其中保護權限是特別為了指名是給繼承物件使用,或是請它覆寫的指示。這樣子在何時要使用哪種方法,即使沒有JSDoc標示也可以非常地清楚。

接著又整理了Toolbar跟Window的部份,這樣子大概可以算是一個大階段。然後先進行程式的撰寫,以檢視這樣子的UML是否合宜。

由於目前UML整體變動的非常快,KALS Wiki中我只會上傳UML規劃的檔案,並沒有將每張圖片一一上傳。

釐清類別之間的關係

由於JavaScritp的類別之間關係複雜,不釐清的話,對於後續開發會有很大的問題。

image

繼承關係應該是最容易釐清的一種,本身沒什麼問題。

image

問題最大的是上圖的「組成」(Composition),以及「聚合」(Aggregation)的差別。

在閱讀UML書籍時,就有提到組成是比聚合更為強烈的關係。但是書中並沒有寫上程式碼,到底有多強烈我也不知道。後來參考了(原創) association,aggregation,composition有什麼差別? (OO) (UML) (C/C++) 這一篇的說明,我才知道組成強調「同生共死」,上層物件建立時,被組成的下層物件也是跟著建立,上層物件結束時下層物件也跟著結束;而聚合則是「同日生,不一定同日死」,上層物件建立時跟著建立下層物件,但是上層物件結束時,下層物件還是可以活著。

儘管JavaScript依據瀏覽器的記憶體回收機制(garbage collection),在物件結束時似乎都不需要手動去做變數的移除等動作,但是強調各物件之間的「組成」關係,仍可以讓JavaScript的結構看起來完整許多。

kals_toolbar

這是kals_toolbar,也就是工具列部分的類別圖。可以看到各個類別一層一層地組成複雜的結構……而且還會繼續調整!

嘗試建立UML輸出成JavaScritp的程式,但失敗了

image

我使用的UML塑模工具StarUML有提供程式碼產生器(StarUML Generator)的功能。除了C++、C#、Java能產生較完整的程式碼之外,還可以安裝範本(Template)來產生PHP程式。

image

儘管當時撰寫PHP的時候,由於實作時與UML有不小的差距,不能直接從UML來產生。但這次畫JavaScript的時候,我就比較仔細地規劃、加入各種說明,甚至到了看UML就可以想像JavaScript程式碼會是怎樣的程度。

因此,這讓我興起了想要使用程式碼產生器來產生JavaScript程式碼的念頭。如果這可以完成的話,就能夠省下至少1/3的程式撰寫功夫。而且維護UML比維護整個JavaScript容易得多,也對未來的程式開發有莫大的幫助。

StarUML建立的UML檔案其實是純文字的XML格式檔案,也就是說,只要懂得XML Parsing的技術,要剖析UML並轉換成程式碼是可行的。於是我參考PHP的Template撰寫方法,以及「利用 StarUML 產生一個簡易的PHP類別」的說明,挑戰將PHP的Template修改成JavaScript的版本,並自動加上完整的JSDoc。

原本我以為StarUML的Template寫法只是使用單純的JavaScript程式語言(沒錯,Template就是用JavaScript為主體來寫的),但挑戰的過程中,發現他使用到了許多StarUML自定的物件。儘管StarUML提供了API文件,但是摸索中卻四處碰壁,網路上也沒有什麼相關的教學。

而要用剖析XML的方式來輸出UML,又發現工程浩大。光是理解UML檔案的組成格式都要花很多時間的,更別說剖析、轉換、輸出這之間的過程不知道要花多久來做測試。

最後只好作罷。乖乖地看著UML的圖片,一字一字地Coding吧。

這讓我學到一個教訓,下次要找一個輸出功能比較強大的UML塑模工具才是。下次吧。

由UML觀看專案進度

由於這次好好地整理了UML,於是開發進度就有了比較明確的依據。大致上可以整理如下表:

程式已完成 11
UML已整理類別 73
UML未整理類別 36
整體進度 11/108 (10%)

其中,UML裡未整理的類別表示整理之後可能會有更多的類別出現,因此整體的分母數字肯定會再增加。

而整體的專案進度也可以分成四個階段:

1. 核心 core

toolkit

包含工具庫toolkit、

core

核心core,這兩張類別圖。

他們是全部系統都會使用到的重要類別,所以撰寫時格外地用心。不僅JSDoc寫得特別仔細,也時常需要回頭修改此處的類別。

2. 標註工具列 Toolbar

kals_toolbar

包含工具列kals_toolbar、

kals_window

視窗kals_window、

navigation

工具列導覽視窗 navigation等三個類別圖。

上述的UML是已經整理過後的,所以目前是照著這些UML類別圖一步一步地撰寫程式碼中。

3. 標註 Annotation

KALSText

包含kals_text、

AnnotationEditor

annotation_editor、

AnnotationList

annotation_list這三個類別圖。

這是標註工具的實作部分,可說是本系統最大的賣點。但是房屋必須要從根基開始做起,這個較為末端的工具,到目前仍還沒有好好地整理。但是如果吸收上述兩個階段的經驗再來修改此處的UML的話,我想應該會學習到更有效率的作法吧。

4. 搜尋 Search

Search

包含search這張類別圖。

搜尋功能大部分應用到了上面各階段使用到的功能;或著反過來說,在各階段時都會用到搜尋功能,只是在此階段中特別會把使用者介面UI做出來而已。

這階段算是收尾,可有可無。

Dropbox建立版本備份

image

Dropbox是一個知名的雲端線上檔案同步服務,不僅跨平台(Windows、Mac、Linux,甚至各種手機都支援),免費帳號就提供2GB的空間,還可以透過邀請來增加到最多8GB的空間。

(備註:如果有好心人士想要玩一玩Dropbox,請幫我點此邀請連結吧,感謝!)

在閱讀電腦玩物的「Dropbox Folder Sync 打破Dropbox限制,同步任意位置多資料夾」跟「Dropbox 今天救了我一命:已刪除檔案救援與舊版本資料還原」之後,我又再度拾起Dropbox來使用。

原本的Dropbox是不錯用,可是限制只能同步一個資料夾這點,就讓他受限很多。這是由於我電腦上需要同步備份的資料夾分散各處,網頁系統要擺在XAMPP的資料夾下、文件會擺在文件的資料夾、Blog資料則是放在Windows Live Writer資料夾底下。如果要用原始的Dropbox備份方式,就得一個一個移至Dropbox資料夾才能備份。

image

但是現在有了Dropbox Folder Sync,他可以透過軟連結(symbolic link)的方式來將您需要的資料夾加入Dropbox中。詳細的運作還是請參考電腦玩物的介紹吧,再此就不再複述。

image

因此我就可以利用Dropbox備份位於各個不同位置的資料夾,包括kals標註系統的主要網頁資料、Windows Live Writer Portable、以及各種文件等等。

image

更重要的是,Dropbox在備份的同時,也做了各備份時間的版本控制。對我這種常常在修改系統的狀態來說,哪天一不小心改錯了、刪掉了某支程式時,就可以利用Dropbox的版本控制來還原!

image

其實我原本是使用Google 協作平台(也就是KALS Wiki)來做版本控制。但是KALS Wiki只提供100MB的空間,而且版本也要自己上傳,使用上還是諸多不便,不如Dropbox設置好之後就自動同步備份來得好用多。

image

如果看到這邊時,你也想要申請一個Dropbox來玩玩,請別忘了點我的邀請,幫我增加一點空間吧QQ 感激不盡!

捨棄RTM,改用Google Task

image

在之前,我使用Remember The Milk(簡稱RTM)來做為待辦事項的記錄工具。RTM有著清爽、好用的管理介面,工作的事項可以設定標籤、延期、多個筆記、網址、優先程度等多種彈性的資料。

image

RTM什麼都好,缺點就是要使用同步功能,必須升級成付費的pro會員,一年25美金。免費會員只能試用15天,而我也已經把這額度用完了。

image

最近開始使用Android,跟以往一樣底與Gmail相處愉快,就興起了改RTM用Google Task的念頭。Google Task推出到現在已經好一段時間了,但是他的功能還是非常基本。設定工作事項標題、詳細記事、加個到期日、完成/未完成,頂多可以跟Gmail與Google日曆搭配使用,此外就沒了。最讓我詬病的是,我覺得Google Task的介面又小又難用啊!

image

儘管試著裝了Google Chrome的Google Task相關套件,但也沒多好用。倒是讓我發現了Google Task的另一種全螢幕介面:Canvas View (就像上圖一樣)。看起來介面是好些,再學著Google Task的鍵盤快速鍵操作方式,修改待辦事項倒也是挺方便的。

CAP201008302030

至於Android上就是使用GTasks這套件。操作上挺方便的,按鈕又大又舒適,缺點是有點廣告,還有沒有自動同步的工作。還有很多東西我還需要研究一下就是。

為什麼同步很重要?

可能有人會好奇,為什麼同步功能很重要?這是因為我工作的場所不只一台電腦,甚至連手機也是我工作的地方。在路上走路、晚上睡覺時,我常常腦袋裡面都會想著論文相關的事情。像是程式寫一寫,走回去的路上才想到什麼東西沒有寫到,於是就會需要記錄的地方。

手機是我最常用來記錄的工具,這也是我選用智慧型手機最重要的理由。在以前使用RTM時無法同步,我是會將待辦事項記錄在日曆中,然後讓日曆跟Google日曆去作同步,再到電腦上手抄到RTM。當然,這樣的作法是很麻煩的。所以這也是我捨棄RTM的主要原因。

現在手機使用GTasks跟Google Task同步,雖然需要手動去按同步這點也是挺麻煩的、而且常常會忘記,但是操作上是比以前順手多,可以更有效率地使用「待辦事項」這種工具。

不在電腦前的時候,想著有什麼事情還沒做完,然後加入待辦事項;在電腦前的時候,依照待辦事項把它一件一件地完成。這樣子的工作模式也蠻令人安心的,不用一直擔心有什麼忘記了、或是沒做到。

專案進度再調整

image

……是的,距離原本預定可展示標註系統的日子,已經經過7天了。就如上面的報告所知,實際上系統到完成還有很長一段距離。很遺憾的是,又要再度延後專案進度了。

不過這次因為更熟悉UML規劃,所以進度拿捏應該是更為準確才是。

image

總之,Coding的時間延長到9/21(二),也就是中秋節前一天為止,大概還有22天。詳細的專案進度,請看KALS Wiki。光看甘特圖上的時間,Coding就用掉了66天,而且噗浪上面的CODING日記還已經計到64日了。時間過得還真是快啊,永遠都覺得時間不夠用orz

結語

由於這次畫UML的時候是比兩個月之前隨便畫還要用心許多,開始照著UML來撰寫程式的時候,也相對地安心了許多。我不用再記著三個不同的程式是如何運作、他們到底是怎麼相依的,這些問題都在構思UML的時候已經釐清,這可以讓我更專心於把一支程式寫好,而不需要煩惱太多事情。

我認為這種安定感是很重要的。這讓寫程式壓力不會很大,寫程式的風格也會依據UML而統一。甚至誇張一點的來說,就算不同人、只要有點程度的程式設計師,就能夠照著UML寫出統一風格的程式。這對於多人合作的專案尤其重要,儘管這次我是自己一個人來進行,但是不同時期的我其實都算是不一樣風格的程式設計師,因此仍是獲益不少。

缺點大概就是偶爾會把自己當做是打字機一樣,只是把UML畫的圖打成JavaScript程式,因此感覺到有點無聊這樣而已吧XD

這次的論文進度報告其實還有很多議題沒有講,因為有些議題感覺獨立開一篇,對需要的人來說會比較有用,所以這篇就差不多到此為止了。儘管是這樣說,但洋洋灑灑也寫了三千多字,用了一個晚上與一個上午的時間來寫,也是很花時間的啊orz

(more...)

[詐欺案件] 人頭帳戶被判刑五個月,附帶民事訴訟移送民事法庭

布丁布丁吃布丁

[詐欺案件] 人頭帳戶被判刑五個月,附帶民事訴訟移送民事法庭

繼上一篇「新竹法院的調解不成立」之後,現在我在繼續記錄一下發展至今的情況。

從5月中我前往新竹法院調解失敗之後,我乾脆直接提出刑事附帶民事訴訟,請求人頭帳戶賠償詐騙損害金額。這提告之後一段時間完全沒有消息,直到7月底時終於收到一封「臺灣新竹地方法院刑事簡易判決」,告知我判刑的結果。

根據簡易判決書的內容所示:人頭帳戶先生似乎是前科累累,而他本人聲稱「帳戶是遺失了,而沒有跟詐騙集團同夥」這個說法,也在檢察官蒐證之後不被採信。受害者除了我之外,還有另一位小姐,共兩名。人頭帳戶先生最後判刑5個月,如易科罰金,以新臺幣壹千元折算壹日。

對人頭帳戶先生提出刑事附帶民事訴訟求償的人只有我,但法官認為內容繁雜,將本件訴訟移至民事庭。跟書記官確認之後,看來未來我可能還會收到傳票,再去新竹法院參加開庭吧。


至於詐騙主嫌那些人的後續為何,不知為何庭期表查詢內已經找不到資料。不過要討錢的話還是得跟人頭帳戶先生討才行,我也就不是很在意他們到底怎樣了。

(more...)

論文進度報告(2010/8/15):糾結的JavaScript

布丁布丁吃布丁

論文進度報告(2010/8/15):糾結的JavaScript

image

由於一直想要有點進度再上來報告,但是儘管距離上次報告已經三週了,現在還是沒有什麼很具體的進度出現。

老實說,JavaScript寫起來超乎預想之外的複雜。舉例來說,撰寫AJAX的程式時,要考慮到前端JavaScript、中介Controller、後端Model等多種程式的結合,程式與程式之間相依性非常高,其中一個環節出錯,都會導致整個動作失敗。而且還要考慮到各個環節中出錯時的訊息回報機制,因此非常地複雜。當然,在不熟悉AJAX的情況下總是會有許多過渡期,只是這段過渡期掙扎的比在使用CodeIgniter時還要久,就讓人有點焦急了。

因此我想藉由這篇來整理一下目前到底做了些什麼事情,接下來到底還要做些什麼,依此來整理一下頭緒吧。

熟悉JavaScript IDE:Aptana Studio

image

Aptana Studio是知名Java IDE Eclipse的一個插件,用來開發PHP、AJAX的網頁應用程式。而Aptana Studio也有獨立的IDE,只是就像是預先調整好Eclipse之後的客製版而已。Aptana並不像Dreamweaver那種所見即得編輯器,而是更注重於程式端的撰寫。

前一次進度報告裡面我有提到NetBeans對於JavaScript的支援並不太好,相較之下,Aptana有幾點優勢:

  • 更聰明的自動完成:不僅僅是物件的方法可以自動完成,連變數名稱(會判斷全域/區域變數)都可以呼叫自動完成。我為了搭配Packer而將區域變數皆以「_」開頭,就讓這個自動完成非常地好用。而搭配JSDoc之後,功能更為強大。
  • 較為支援JSDoc:儘管Aptana使用了許多他自定的JSDoc標籤,而且要在註解寫到@時按Alt+J(因為我後來調整過,所以現在我忘了原本的快速鍵是哪個,但他就是得要按快速鍵才會叫出選單)。但是Aptana的確是比較能夠利用JSDoc來補完原本JavaScript難以辨識的物件導向特性,例如繼承(extends)

其他的像是Outline(程式大綱)、錯誤提示等就還算普通,但也是不錯用的功能。只是他的搜尋跟取代實在是有點不太好用,太過複雜了。結果我要取代時都改貼到EmEditor去操作XD

題外話,在研究Aptana時我發現到了Aptana Jaxer這個AJAX伺服器架構,這可說是非常前瞻性的開發方式,可以讓你在原有的JavaScript程式碼當中,撰寫控制伺服器端Server中資料的AJAX程式,以簡化Client-Server之間的複雜性。這次我並沒有使用到Aptana Jaxer,但下次有機會開發AJAX專案的話,我會考慮由此著手。

有興趣的人,可以來讀讀看「初探Jaxer」來入門喔。

設計模式:觀察者模式

image 

(圖片來源:Wikipedia)

觀察者模式 (Obersver Pattern)是經典的軟體設計模式當中的一種,他透過介面統一來讓觀察主題(Subject)與觀察者之間的相依性鬆綁,將通知的任務集中在觀察主題中,而各觀察者自行到主題去訂閱,而通知之後行為也仍讓各觀察者自行決定。

在JavaScript這種大量依賴事件(Event),且通常是非線性、動態的執行環境中非常地適合使用觀察者模式。JavaScript是使用「EventDispatcher(事件派遣者)」來做為觀察主題,而觀察者通常是輸入function,稱之為「監聽者(Listener)」,這是JavaScript程式語言的特色發展而成一種獨特觀察者模式。

如果你用過JavaScript的addEventListener功能,其實你所用的就是觀察者模式的一種。例如你可以針對window(視窗)改變大小(resize)的事件進行觀察,程式碼通常如下:

window.addEventListener('resize', function (event) {
    //當視窗大小改變時,做一些動作...
});

當學會觀察者模式的作法時,這簡直是JavaScript的神兵利器,許多功能都可以利用觀察者模式來實作。其中,我想到最有趣的功能是語系檔的觀察者模式。

在傳統系統開發中,語系檔通常只是供其他UI(User Interface,使用介面)元件讀取。如果語系檔有所變更時,就要在讓全部UI再來做一次讀取的動作。而這個讀取的動作通常是跟UI的初始化動作綁在一起,也就是要讓整個網頁重新讀取,才能達到語系變更的功能。

利用觀察者模式改良語系檔的話,就是把語系檔當做訂閱主題、讓各個UI的語系設置動作作為觀察者。當語系檔有所變更時,則通知各個UI的語系設置動作,以達到即時的語系變更效果。

舉例來說,在尚未讀取語系檔之前,UI會以各自的預設語系來呈現,如下圖:

image

再讀取語系檔的內容之後,語系檔就會通知各UI來更新語系,於是就能呈現語系檔中的中文字句,如下圖:

image

諸如此類的應用還可以用於AJAX接收資料的通知、Data Collection資料變更的通知等等,非常地好用,可以在未來難以預知的變化中提供多種組合的可能性。

觀察者模式可說是我在學習JavaScript中最大的收穫了。

研究Android手機版本

如果問我開發網頁程式最大的魅力在哪裡,我想應該就是HTML、JavaScript那種跨平台都可以執行的泛用性吧。

JavaScript比起Adobe Flash、Microsoft SilverLight更為泛用,甚至各平台許多的Widget也使用了JavaScript作為開發語言。而在現在的智慧型手機如Apple的iPhone、Google的Android (微軟的Windows Mobile 6以下請排除在外,WM真的是沒救了)也總算是支援較完整的JavaSript功能,也就是說,理論上我可以寫一個網頁程式,讓他同時在桌上型電腦跟手機、平板電腦上都可以正常地運作。

image

上圖是Android SDK中提供的Android模擬器功能,跑的是Android 2.1版本。眼尖的讀者應該可以發現到,這跟上面圖片中讀取的其實是同一個網頁,而他們的UI也幾乎是一模一樣。這就是我想要達到的效果。

由於我比較喜歡開放原始碼的Android,所以在研究手機網頁時,我是以Android為主,而不是iPhone。安裝Android SDK時著實讓我花了點功夫,最後是參考Android 模擬器安裝 (Install Android Emulator)來完成的。在之後的測試中,一開始我安裝最新的Android 2.2,但是速度不知為何很慢,於是我又測試了幾個版本,目前是使用Android 2.1在做測試平台。

image

我也試著去找了iPhone的測試平台來安裝,免費的只有找MobiOne,但是他的瀏覽器模擬並不是很正確,系統偵測的數字會受到外在環境影響,實在是很難在這上面開發,故放棄。

開發手機網頁的困難

然而在手機上開發網頁卻是需要注意到許多事情。以下是兩個主要碰到的問題:

找不到手機縮放的Sweet Spot

現在有許多鑽研手機網頁程式開發的方法,但大多數網頁所指的「手機(phone、mobile device)」指得都是Apple iPhone,例如Web Development For The iPhone。儘管大部分的功能在Android瀏覽器也是一樣的效果,但是像是viewport(瀏覽畫面縮放)的判斷,只有在較新的版本(似乎是Android 2.1)以上才有支援,Android 1.6並沒有支援,viewport。這種微妙的差異讓開發時遇到了不少困難。

Eric Shangkuan發表了一篇寫作Mobile Web App的準備來討論Viewport的注意事項。大部分的手機網頁開發都是將Viewport網頁縮放鎖死,不允許使用者在手機上放大縮小。而各種framework如jQTouchSencha也都是如此。

image

圖片來源:jQTouch Preivew

舉例來說,這是jQTouch的網頁介面。在這種狀態中,使用者是不能夠縮放畫面大小。雖然實際上也的確是不需要縮放,但這是在把網頁當做純應用程式功能時才能使用。如果你的網頁是文字與應用程式功能混雜的話,那麼就會有些問題。(像是我的標註工具)

image

圖片來源:37singals

Micah在Device-scale user interface elements in iOS Mobile Safari中討論到了功能元素與手機縮放尺寸的影響。一開始讀取網頁時,手機瀏覽器會將尺寸縮放到能夠看到整個網頁寬度的大小,於是你會發現到功能按鈕就會小到讓手指很難按得到。

image

圖片來源:37singals

可是當你把手機畫面放大時,卻又發現這按鈕大到一種礙眼的程度。

image

圖片來源:37singals

這樣子的大小才是一個理想的尺寸(sweet spot)。

因此Micah提出了一個偵測尺寸縮放、並偵測現在尺寸、然後利用CSS3的「webkit-transform: scale()」來調整元素尺寸的解決方案。很遺憾的是,這似乎只能用在iPhone上。儘管我花了很多時間改良讓他能用在Android,但是實際上並不偵測到真正的縮放尺寸。

於是我放棄了,還是鎖死viewport,讓使用者乖乖用固定尺寸瀏覽網頁吧。

事後我發現到原來scale的資料可以從touch事件偵測中來取得,在JavaScript Touch and Gesture Events iPhone and Android這篇有較為詳細的介紹。下次有要研究手機網頁開發時再來研究吧。

捨棄只能在手機跟Google Chrome執行的手機網頁Framework

image

就如上面提過的,jQTouchSencha都是專門為了手機網頁開發的Framework,其中Sencha則是結合jQTouch、Ext JS等知名JavaScript Framework的一個集大成的Framework。

他們都使用到大量的JavaScript跟CSS3,在iPhone跟Android上也都能正常運作,也可以在Google Chrome上顯示,而且非常地適合手指操作(Finger Friendly),而我也非常喜歡這種UI。

image

但很遺憾的是,在Firefox甚至IE當中,他們都無法正常地運作。也就是說,用Sencha或jQTouch所撰寫的網頁,幾乎就只能在手機或Google Chrome上才能開啟。

這是讓我難以接受的限制,於是最後就捨棄他們不用。只有在設計UI時,才會開啟來參考他的外觀而已。

持續改良中的單元測試

image

由於之前要嘗試各種技術,雖然一直是使用QUnit來建立測試頁面,但那些都不能算是真正的「單元測試」。由於AJAX是非同步的執行方式,這讓單元測試沒辦法很單純第一次做完,當然也就不知道該做的測試到底什麼時候會完成、是否成功。所以我改良了QUnit,加入預測測試數量的功能,以便更能準確地掌握到該測試的完成度。

現在單元測試也大量地使用了setTimeout來做出自動操作的功能。也許這跟實際上用手操控滑鼠來操作還是有點不太一樣,但勉強算是堪用。

此外,也不斷地調整CodeIgniter的Controller跟View架構,讓它更適合開發AJAX環境。

之後還會做一個統一計算單元測試的頁面,就如當初在CodeIgniter裡面做的一樣。這就稍晚再來進行吧。

專案進度整理

類別 應完成 已完成 已完成百分比 程式語言
Model 100 100 100% PHP
View 73 4 5.4% JavaScript
Controller 9 0 0% PHP
總計 182 104 57.1%  

進度與上次報告來說幾乎沒有差多少,但是實際上卻已經寫了快40支程式。然而到目前為止都還是像準備作業一樣,還沒有正式進入實際開發的階段,所以感覺上根本沒有做多少事情。

image

目前可能是比較接近系統核心的,應該只有Selection_manager而已。就是實作了選取區域的功能。

image

KALS Wiki上面寫著原本預定的8/23要完成……連我自己都覺得不太可能了。還是到那一天再來看看吧。

結語

為了開發手機版介面,我跟實驗室借來了HTC Hero。使用之後果然發現到很多在電腦上用滑鼠操控無法得到的落差,使我改進了不少UI設計。(此外,Hero真好玩,Android真是不錯用)

現階段我仍在進行基礎的準備工作,目前正在撰寫跨網域檔案上傳的功能。檔案上傳很基本,但是加上一個跨網域的限制,就是很少見的技術。然而,對我正在做的標註工具來說,跨網域卻是基本的門檻而已。

因為要做的事情還是很多,多到難以看到完成的終點,所以最近多少有點喪失動力、甚為消極。

於是每天就在陌生的技術中,不斷地挑戰未知的領域,然後浮沈地掙扎吧。

(more...)

論文進度報告(2010/7/24):從Model到View

布丁布丁吃布丁

論文進度報告(2010/7/24):從Model到View

image

上週末終於把Model的部份寫完了,也就是說,PHP的部份告一段落,而接下來要進入JavaScript的部份。進度的概況大概就是完成上面那張圖中的右下角部分,而其他都還要繼續做。

類別 應完成 已完成 已完成百分比 程式語言
Model 100 100 100% PHP
View 73 0 0% JavaScript
Controller 9 0 0% PHP
總計 182 100 54.9%  

以程式數量來看進度的話,就是上面的表格。大概完成了一半,現在進入下半場:JavaScript。


Model完結之傷感

回顧一個月多前開始撰寫PHP的部分時,需要熟悉PHP物件導向、CodeIgniter、撰寫PHPDoc、單元測試的開發方法,讓我摸索了好一段時間。到現在Model完成了,單元測試也十分稱職地完成了他的工作,現在又要暫時把它擱在一旁,是覺得有點捨不得。

我在撰寫Model時,實際上撰寫的檔案數量為141個,細表如下:

類別 數量
Libriaries 107
Extension Libraries 4
Languages 1
Helpers 3
Unit Test 24
Views 2
總數 141

在開發過程中有不少重新思考UML架構的時候。如果繪製UML時能夠熟悉CI跟PHP的話,也許那時系統分析的數量會更為準確也說不定。

image

同時,這些程式全部通過單元測試。單元測試共34頁、456項測試。這是程式品質的一種保證。

而且我也把核心的工具整理成toolkit類別,包括Generic Object、Collection、Iterator等等,在未來開發PHP專案時又可以將之拿來使用,是非常寶貴的程式結晶。

雖然是這樣說,但到目前為止,仍然沒有什麼很令人亮眼的東西可以拿出來跟大家講。Meeting報告時看老師聽我講這些抽象的東西感覺像是有點無聊,我也沒有辦法orz

要看到實際上可以用的程式,還要把View跟Controller組合起來才有可能。再怎樣也是急不得的。


View開始之困惑:學習撰寫JavaScript

說要完結Model、開始撰寫View之後,已經過了一個禮拜了。老實說,到現在我還是很困惑,我到底該怎麼辦才好?跟一個多月以前寫PHP一樣,JavaScript是一個我很熟悉的程式語言,但是我一直沒有很正式地去學習它。說到JavaScript,一般會想到表單驗證啦、jQuery動畫特效啦,但是我要寫的層次是比這些都還複雜很多,是要靠一個指令,帶出整個標註工具,並且要由純JavaScript來跟伺服器溝通、交換資料。這種在別人網頁上進行從無到有的架構,對我來說是從未經歷過的高難度境界。

為了要將JavaScript嚴謹地架構起來,最近我開始學習更多相關技術:

JSDoc

JavaScript很自由,但是因為太過自由了,所以他的物件導向特性並不是很明確。JSDoc是類似JavaDoc的JavaScript專用程式註解格式,一個搭配JSDoc的JavaScript程式大概會長得如下列程式碼一樣:

/**
* 驗證是否為陣列
* @param $obj
* @return 驗證結果
* @type boolean
*/
jQuery.is_array = function ($obj)
{
    return (typeof($obj) == 'object' && ($obj instanceof Array));
};

我們可以利用JSDoc來說明一個類別的繼承(@extends)、建構子(@constructor)、方法的參數(@param)、回傳資料(@return)與型態(@type)、所需類別(@requires)等等在程式中難以說明的特性,而使得我所使用的IDE:NetBeans可以正確地解讀複雜的JavaScirpt程式。

image

如果NetBeans能夠正確地解讀,那麼就能在撰寫程式時即時地提供說明與自動完成的功能。

然而,JSDoc卻是一把雙面刃。由於JavaScript並不像PHP是在伺服器端執行,而是必須讓使用者下載到他的電腦才能執行。也就是說,JavaScript的註解撰寫越多,表示它的體積越大、越吃網路流量。為此,我還需要一種JavaScript的壓縮打包技術。

Packer JavaScript en PHP

常常使用複雜framework,如jQuery、jQuery UI的人,一定有碰觸過min打包版程式的經驗。研究JavaScript打包技術(Packer)的Dean Edwards已經將之發展到很成熟的地步,而且支援.NET、perl,以及PHP來使用。

讓我們來看看打包到底能做到什麼程度:以下左圖是原始程式碼,總共13649位元組;右圖是打包壓縮的結果,只有5177位元組。壓縮到一半左右的大小,實在是很棒的成果。

原始程式碼(13649) 打包壓縮結果(4691)
image  image

打包壓縮其實並不是什麼很神祕的技術,大致上可以分成普通壓縮與Base 64、是否縮短變數名稱等選項。普通壓縮中,他刪除了註解、多餘的空格、對齊(tab)、換行,並將程式撰寫簡化,以節省空間。除此之外,使用Base 62則能獲得更高壓縮率的作法,在edikud的blog中介紹了一些提高壓縮率的守則,但似乎是寫錯了,所以我更正之後說明如下:

  1. 區域變數名稱前加上_,像是function的參數。例如「obj」改寫成「_obj」。
  2. 全域變數名稱前加上$。例如「TYPE_ID」改成「$TYPE_ID」。
  3. 最後補充一項:程式每行結尾都要加上「;」。原本JavaScript會把沒有「;」的換行補上「;」作為宣告的結尾,但是打包之後,換行會被刪去,所以就必須在一開始撰寫時就養成良好習慣地加上「;」才行。

至於測試方法則不是我關注的重點,所以就不特別去在意。

搭配CodeIgniter的網頁快取功能,我就可以把打包壓縮過後的JavaScript以cache的方式保存起來,既能在程式有所更改時立即地轉換成打包格式,也不會重複進行打包動作導致系統資源浪費。

QUnit:JavaScript的單元測試
image

為了養成撰寫程式時的良好習慣,即使是寫JavaScript,我也採用Unit Test單元測試的開發方法。Qunit是一個JavaScript的單元測試工具,用法也十分簡單,介紹網頁裡面已經把主要用法說明完畢。

只是我並不喜歡原始QUnit的介面與功能,所以修改了不少版面、加入型態判斷、例外捕捉並顯示錯誤訊息等功能,建立一個屬於我自己好上手的QUnit工具。透過QUnit來偵錯,我發現我逐漸改變以往使用alert來偵錯的方式,QUnit不僅能詳細地回報錯誤細節,速度與效率快上許多,因此更方便於跨瀏覽器之間的測試。

等待我把QUnit使用更熟悉之後,我會再把改良版的功能發佈出來跟大家共享。

JSONP:跨網域AJAX技術

以往在寫DSpace時,我是使用了很多AJAX技術,但那都是同一個網域底下的資料存取,而我的論文則是往更高的目標邁進:跨網域AJAX存取。

JSONP是一個天才想出來的非正式方案。這是利用<script>標籤的src載入JavaScript可以讀取不同網域的JavaScript檔的特性,只要在src的網址中以GET方式輸入參數,然後伺服器則回應相對應的資料並以JSON的方式讓使用者端的瀏覽器去做callback回呼的動作,就能夠達到跨網域AJAX的境界。詳細的作法可以先看看Hpyer的介紹

這個是很簡單的作法,但也是很危險的一種技術。因為參數以GET的方式傳遞,也就是說資料都會是以明碼來顯示,這就是一種容易被入侵的漏洞。對此我在思考利用公鑰私鑰的方式來為傳遞參數進行加密的作法,不過似乎是挺複雜的,我現在連基本的JavaScript物件導向都還沒熟悉呢。

此外,JSONP是以GET方式傳遞參數,而CodeIgniter又剛好最討厭GET傳遞參數。調整CodeIgniter讓他能支援JSONP,讓我花了不少功夫。等我真的把它馴服了,我們再來談談CodeIgniter的調整方法吧。

NetBeans對於JavaScript支援沒這麼強

習慣NetBeans對於PHP的支援之後,改寫JavaScript時就會明顯地感覺到不方便。這個不方便其實比起什麼功能都沒有的筆記本,或是只有語法顏色標示的編輯器來說還是強的很多。NetBeans提供了方法的自動完成(搭配JSDoc就如上述效果般)、可能錯誤的提示、自動補完()、{}、[]等括弧。

雖然不錯用,但跟PHP的支援比起來,少了兩個對我來說還蠻決定性的功能:

  1. 缺少變數名稱自動完成:也就是NetBeans無法取得JavaScript的變數前幾個字來猜出後面的字,這讓我寫function函數的時候就很不習慣,沒辦法快速帶出參數名稱。
  2. 方法自動完成的速度慢:要使用方法的自動完成,必須要在變數撰寫完畢之後加一個「.」以表示要使用方法時才會帶出來,但是選單速度非常慢,大概要等到1秒才完成,而且一旦自動完成輸入錯誤而想要回頭修改時,又必須要回到輸入「.」的情況才能再次帶出自動完成選單。非常地考驗耐心。

因此我正在找尋是否有NetBeans的Plugins能夠補強這兩個缺點,不然其他都很完美了說。


寫好系統只是興趣,並不代表研究順利

身為一個社會科學領域(表面上是文科)的研究生,我很瞭解理工科那種想把系統做好就算是完成論文研究的作法在這邊是行不通的。社會科學的研究講求結果分析能力,在好的環境中分析好的結果,在壞的環境下也可以分析出壞的原因,換句話說,不管研究對象的環境是好是壞,研究都能夠進行。

但是,其實我並不喜歡這種調調。並不是說這樣好或不好的問題,只是我個人看到問題擺在那邊,就會想要去動手解決,然後找出更好的方法之後,跟別人說明這些作法。就像我在這個Blog作的事情一樣,我的論文也是一樣的理念。

所以我不是用別人寫好但我並不滿意的系統,而是自我挑戰作一個系統,不僅只是作,而是以對我來說前所未有的嚴謹態度來撰寫一個系統。基於毛老師的理論,我今天用這種方式撰寫系統,以後我也應該會繼續用這種嚴謹的態度面對未來的工作,而這也是我的自我期許之一。

然而回到頭來,我很清楚這種想法至多仍只是能稱得上是一種興趣,而與研究進度無關。撰寫好系統,並不代表實驗能進行順利、問卷會設計、統計會分析,這些技術與知識都是不太相關的事情,而我則是抱著來一個我學一個的心態,一步一步慢慢地做完這個論文而已。

有些人也許看著我三不五時刻著系統進度,就以為我論文快完成了,但事實上兩者是不太有相關。那為什麼我要花這麼多時間在做系統呢?我會回答說這是一種興趣,更直接一點,我依然在耍任性,就跟寫書的時候一樣。

這種個性,真的是沒救啦。

(more...)

論文進度報告(2010/7/11)

布丁布丁吃布丁

論文進度報告(2010/7/11)

image

先來講一下進度報告好了。一樣地用一張表講完目前進度:

類別 應完成 已完成 已完成百分比
Model 100 54 54%
View 73 0 0%
Controller 9 0 0%
總計 182 54 29.7%

這是程式寫作到第21天的進度,已經完成了1/4,而核心的Model部分也做完了一半,可喜可賀。

image

不過現實層面是預定的專案進度是做不到了,所以日期必須往後順延。程式寫作的時間從15天延長到45天,可能到8/24才能有展示可以看了。詳細的資料就請上KALS Wiki去看囉。


強大的Collection

最近又學到Collection跟Iterator的技巧,跟上次的進度報告中提及到的Generic Object(其實也沒講到多少) 搭配使用之後,便可以應用到一般Model中許多常用的類別。

Collection(集合)是一種陣列的強化版本,不僅可以做到原本陣列大部分可以做的事情,還可以控制集合成員(members)的變更,並且實作延遲實體化(lazy initialization)的技巧。搭配Iterator之後,Collection還可以放進foreach去跑。只能說是好用到一種令人感動的境界,而且其實許多類別都是一種Collection,當初我太小看Collection這種工具了。

除了參考原本書中介紹的Collection來撰寫,並讓他擁有Iterator的功能之外,我又將之進化成一些特色類別,並組成我自己的toolkit。以下隨便介紹,看不懂很正常,反正一般只要知道有八成的類別都可以拿來套用這些toolkit就對了

Generic Collection

image 

將Generic Object作為成員,並設定預設載入的資料表與成員類別,可以對集合的成員進行Update的動作。

Generic Attribute Collection

image 

繼承Generic Collection,並將Generic Attribute Object作為成員。叫做Attribute的原因是通常這種集合是附屬於某個主物件底下,作為額外的屬性。例如Annotation會有很多額外的feature(特徵),而這種屬性都會附帶有「type_id」,然後還有一些特性。

Generic Association Collection

image

繼承Generic Collection,並預先載入指定資料表中關連的資料表的資料,並且能夠修改指定資料表的關聯內容。


Benchmark Fever!

image

如果眼睛很尖的人,應該發現到開頭那張Unit Test的擷圖中多了一個項「Benchmark Time」。Benchmark是測試速度或是評分時常用的技術,CodeIgniter有著強大的Benchmark功能,可以記錄任何程式執行時所耗費的時間。因此我把它結合到CodeIgniter的Unit Testing當中,以便分析每一項測試所需要耗費的時間。當耗費時間過久時,該項測試可能就有些問題囉。

image

再搭配CodeIgniter的Application效能分析,就可以自動捕捉到多項細節資訊。包括URI字串、使用類別/方法、記憶體使用狀況、基準測試(benchmarks)、GET資料、POST資料、以及資料庫查詢的各種語法。特別是資料庫查詢的細節,光靠這個就能找到許多無效或錯誤的查詢,而修改許多錯誤。

由於之前寫到Annotation_scope_collection時,發現效能異常地慢,於是試著把Benchmark加入Unit Test,並從中找出最有問題的測試點來改善,最後才抓到不能一直依賴CI->load->library()來當做include_once讀取類別這個問題。改善之後我可以看到執行速度大幅縮短,然後我又試著加入Cache的機制,結果速度又縮短了0.x秒,實在讓人很開心。於是一不小心就會沉迷在改進程式以縮短執行速度這個挑戰極限的樂趣中。

現在幾乎每種測試都能在1秒之內跑完,其實不要慢得太誇張,差個0.x秒也就沒什麼大礙了。


本來想草草地寫,結果也寫了好一段時間。那這次就這樣啦,詳細進度可以追蹤我的噗浪,來繼續寫下一階段。

(more...)

論文進度報告(2010/7/2)

布丁布丁吃布丁

論文進度報告(2010/7/2)

image .

這次進度報告又隔了兩個禮拜,由於到最近才有比較明顯的成果出來,是也就沒有急於每週定期報告。

實際進度一張表就可以講完了:

類別 應完成 已完成 已完成百分比
Model 100 19 19%
View 73 0 0%
Controller 9 0 0%
總計 183 19 10.3%

這是到Coding D13的今天為止的進度。

以下是其他話題閒聊XD


完整的物件導向?還是兼容PHP 4.3?

我使用CodeIgniter 1.7.2這個PHP Framework來建置系統,而CodeIgniter是兼容於PHP 4.3為目的來設計,在CodeIgniter的PHP寫作風格指南裡面也提到說,除非特別說明,否則程式應該能夠相容於PHP 4.3版以上。

PHP 4跟PHP 5的物件導向寫作有很大的不同。PHP 5比較像是Java這種嚴謹的物件導向,有public private abstract final等好用的功能可以使用,而PHP 4則比較像是單純的變數跟函數綁在一起的物件。

image

在繪製UML時,物件中成員變數與方法的開放程度都會是考量的範圍內,但是PHP4並不支援,而CodeIgniter只有在Controller中有提供此方法,那就是private(私有)方法的名稱前加入「_」,例如「_filter_id($id)」。

本來我也是想用這種方法去兼容PHP 4.3,但是寫一寫忽然發現這還是有些問題。這樣作法會無法善用完整的物件導向概念,儘管實作上PHP是很自由的,但是從學習的角度來說,還是盡量地嚴謹一點會比較好。因此我中途決定改以較完整的方法來撰寫PHP程式碼,不僅讓物件導向較為漂亮,NetBeans的導覽視窗(Naigator)跟自動完成功能也能提供比較完善的支援。

image

這是我在撰寫Generic Object時,NetBeans的導覽視窗,有上鎖的表示private私有方法,而黃色菱形的則是PHP 5的魔術方法__construct()建構子。看到NetBeans能夠更正確地解讀我的程式,也就覺得用完整的物件導向也挺不錯的感覺。

也許以後實務工作時我會從簡來做,但現在我仍在學習中,就好好地確實地寫好每一支程式吧。

很好上手,卻也很難抉擇的PHP

儘管PHP有提供物件導向功能,但原本他是程序導向的程式。而CodeIgniter雖然是物件導向程序,但是他卻有自己的一套作法。雖然高度自由的PHP讓我可以選擇各種作法,但這也是頗難抉擇的一件事情。

CodeIgniter會希望程式設計師以CI_Base物件為主體,在Contoller、Model裡面已經先預載了CI_Base,而Library或其他地方則是要呼叫「CI =& get_instance()」。如果要使用CodeIgniter豐富的Library或Helper的話,就非得使用CI_Base才行。

然而CodeIgniter裡面的如果要用繼承、介面等物件導向功能,就不應該使用它的Model,而是用Library才是。這也跟原本我在UML中規劃的方式有所不同。Library並不會預先載入CI_Base,都必須另外呼叫才行,

因為CodeIgniter寫作方式與我預先認知有所差異,所以實作時遇到了很多難以抉擇的困擾。到底要用物件導向的繼承?還是要用Helper的function?以前寫PHP時,很依賴function來提供模組化的作法。但現在程式開發的技術進步了,是否能夠改用物件導向的繼承來實作呢?

這些問題並不只會在一開始困擾著我,在系統持續發展的時候,也會不斷地修正我的作法,以求得更好、更佳的程式開發方法吧。


迷上了Unit Test 單元測試

自從之前看了極致軟體製程(eXtreme Programming,簡稱XP)的介紹之後,我就把單元測試這個概念深深地記在腦海當中。而在開發系統時,我也開始學著依賴單元測試,並且到最後迷上了它。也許有人會在噗浪上看不懂我在念著測試測試到底是什麼,其實就是指單元測試(Unit Test)。

相符或不相符的檢查

單元測試是軟體測試的小型版本。軟體測試的概念很簡單,就是看看系統產出的實際輸出與我們希望的預期輸出是否吻合。我製作了meeting時報告用的投影片,不過我認為節圖出來用文字來說明應該會更好懂:

image

這是單元測試的一個示意圖。程式設計師撰寫出程式給電腦,然後要求電腦執行該程式,而程式設計師也自己想一個預期成果,並把它們相互比對。這支程式輸入兩個整數參數,並把它們彼此相加再輸出。輸入test(1, 2)的話,輸出結果應該是3。如果正確地符合程式設計師的預期,那麼測試就算通過(Passed)。

image

反過來說,當程式跑出來的結果並不是3的時候,可能就是該程式出現問題了。上面示意圖中則是測試沒通過的樣子,因為程式裡漏掉了參數,導致結果輸出不如預期,這時候就是要回頭去debug了。

單元測試與程式開發

image

單元測試本身是一種黑盒測試,它只注重輸出結果,並不看程式內部的細節。但由於他檢測的程式通常都是非常小的一塊,而不是整個系統的運作,所以用來檢查錯誤非常方便。

單元測試提供了一個模擬環境供程式運作,它可以讓程式重複地進行測試,並輸出一張簡單明確的報告,讓你知道哪些測試通過、哪些沒通過。由於單元測試執行速度快、簡單,因此只要程式有任何修改,都可以馬上回頭以單元測試進行檢查。久而久之程式設計的動作就會變得很單純:寫完、測試、通過就繼續寫,沒通過就回頭修改。

image

在極致軟體製程中,單元測試也是相當重要的一環。當系統分析做完之後、要開始撰寫程式之時,程式設計師應該先只寫程式的大綱,像是成員變數的宣告、私有公有方法的宣告(但是裡面都是空空如也),很快地把整個程式的大綱寫出來即可,內容細節或是能不能運作,稍後再說。

有了程式大綱之後,就開始製作單元測試檔案。這個測試檔模擬該程式使用的情境,包括輸入的參數、預期輸出的結果。在嚴謹的單元測試當中,會將程式裡每一個方法一一去測試,但我在實作上只有測試幾個重要的項目而已。其實這也不是什麼大問題,只要後續想到什麼情境還可以拿來測試,隨時都可以加入單元測試檔,這也是XP告訴我們的方法。

測試檔完成之後,就拿程式大綱來測試。理所當然地,測試會失敗。接著程式設計師再繼續把程式細節一一地補上,並隨時利用單元測試檔來檢測自己的進度。直到所有測試都通過,那麼這支程式就算完成了。

單元測試Framework:PHPUnit

就像Java的單元測試框架JUnit一樣,PHP也有單元測試的框架:PHPUint。它是由純PHP程式碼寫成的輕量級測試框架,具有自動產生規範好的測試檔格式功能,能提供嚴謹的單元測試。除此之外,它也可以結合Xdebug分析程式碼覆蓋率,或是支援Phing部屬測試與Selenium做大型自動化集合測試。

image

在IDE中也會提供PHPUnit的支援,像是上圖就是NetBeans的測試功能。

但由於CodeIgniter框架運作方式與單純的PHP不同,難以使用PHPUnit來做測試,所以我並沒有使用這個強大的工具來進行單元測試,而是使用CodeIgniter提供的簡易版單元測試功能而已。

通過測試的程式令人安心

我現在也學著以測試導向作為程式建置的方法。儘管有人會覺得這個測試檔的製作很多餘,但習慣時候,看到測試通過的程式反而更令人安心。

程式設計最大的樂趣,我認為莫過於看到程式順利運作的時候。但在大型系統中,我們不得不將程式分割成細小的部分,就像MVC中切割成三大責任一樣。系統運作缺一不可,但是要等到全部做完才看到成果,也未免太令人不安。就像我現在在開發Model這一塊,正常情況下它是沒辦法獨立運作,而更不知道它到底能不能順利地運作。這時候使用單元測試,就可以簡單、迅速地知道這支程式在預期的情況下正不正常,並依此來修改程式。

雖然看到測試沒通過時,會覺得有點難過,但也總比系統寫得超複雜時還要回頭偵錯好的多。反過來說,看到每個單元測試都通過時,那種感覺真是非常地快樂。於是不知不覺,人心就變得單純了XD


我在這次報告中還有敘述Generic Object跟Lazy Loading的概念。Generic Object我還要再作一些修改,而它也實作了Lazy Loading這個程式設計的小技巧(儘管它很重要XD),所以留待之後有機會再一起講吧。

本週的論文進度報告就到此為止。因為有雜務丟下來了,所以又得一段時間沒辦法寫論文。就認命吧。

(more...)