:::

論文進度報告(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),所以留待之後有機會再一起講吧。

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