框架與開發

1. 有時候不要依框架工作。如果面對框架不能完成或難以完成的工作,不妨試一點比較「穢」的方法。框架是輔助你的工具,不是限制開發的牢獄。

2. 同上,避免用上一些把低階收起,只開放高階介面的框架。拿 Hibernate 為例,即使它是一套 O/R Mapping 的工具,你仍可選擇以 SQL 拿取資料。

3. 要衡量使用框架後所增加的工作量。我的準則是計算框架設定與商業邏輯(Business Logic) 的比重:如果設定比想好商業邏輯更辛苦的話,還是不要用框架為妙。

4. 有時候不要被框架琳瑯滿目的功能所矇蔽。要先釐定出你所需要的功能,再以學習難度,設定複雜程度等等因素挑選合適的框架。

5. 嫌框架還是太繁複的時候,可以考慮在框架上另編寫自己的框架簡化重覆的步驟。

6. 不用太在意自己是否符合 Best Practices;除非有碰釘,程式碼過於複雜等等問題。If it ain’t break, don’t fix it.

7. 不少框架也鼓勵模組化(Modularized)和重用 (Reuse),但有時候應不應該把自己的程式碼拆散成散亂的碎塊。要肯定自己可以隨時會用到自己建立的模組,那便可以避免出現雞肋問題。

8. 使用模組時,如果時間許可才採用模組陌生的功能。時間不足寧可選擇較麻煩的方法。

9. 不要用說明不詳盡的框架。

10. 簡單的東西,例如方便自己的小工具的編寫,cron job 等等東西,除非有其他原因,最好不要碰框架。

Aspect-Oriented Programming

因為近來用 Spring 的緣故,順道也接觸了一點關於 AOP (觀點導向編程) 的知識。

傳統 OOP,就拿 MVC 這套 pattern 來說吧–例如我們要建立一個留言板的話,Controller 的結構大概是這樣的:

class MsgBoard implements Controller {
private void post(name, title, content) {
Validator.isSpam(getIP());
Validator.sanityCheck(name);
Validator.sanityCheck(title);
Validator.sanityCheck(content);
Post p = new Post(name, title, content);
post_id = DB.store(p);
Logger.log(getIP(), post_id);
displayView('result');
}
private void reply(post_id, name, title, content) {
Validator.isSpam(getIP());
if (!DB.exists(post_id)) displayError();
Validator.sanityCheck(name);
Validator.sanityCheck(title);
Validator.sanityCheck(content);
Post p = new Post(post_id, name, title, content);
reply_id = DB.store(p);
Logger.log(getIP(), reply_id);
displayView('result');
}
void handleRequest() {
if (IS_POST) post();
if (IS_REPLY) reply();
}
...
}

以上的結構,有兩個問題:

  1. 程式碼混亂
    一件簡單的動作,因為不同方面的要求(例如怕留言者破壞皮面而檢查留言有沒有不合規的 HTML tag,檢查來源是不是垃圾郵件黑名單,IP 記錄等等)而使程式碼穿插多個不相關的模組/類別,修改上來得穿插多個不同模組逐個修改,費時得很。
  2. 程式結構鬆散
    同時是 post,reply,性質上不太相近但卻要進行多項同類的檢查和記錄,但又不是完全相同可以簡單到用一個程序包著(例如 post() 不用檢查原post的存在),修改某部份之時很可能會忽略其餘地方而造成錯誤,難以維護。

於是研究人員向「分離不同關注點」這個方向下手,AOP 是。AOP 的規劃可以分為三個部份,包括「觀點分離」(Aspectual Decomposition),「關連實作」(Concern Implementation) 和「觀點重組」(Aspectual Recomposition)。

譬如上述例子,真正的工作是把新文章儲存到資料庫裏去,其他檢查,記錄等等分散在不同程序,位於外部的附加工作,在 AOP 的世界裏被稱之為橫切關注點 (cross-cutting concern)。為了有效可以管理這堆散漫在程式結構裏的步驟,便有了觀點 (Aspect) 這個容器。每一個 Aspect 可以對某個工作的不同階段(AOP 稱之為 Pointcut)附上不同的關注點工作。例如:

public aspect storePost {
pointcut sanityCheck(name, title, content) : call (Post.new(name, title, content)) && args(name, title, content) {
if (Validator.sanityCheck(name) && Validator.sanityCheck(title) && Validator.sanityCheck(content)) proceed(p);
}
pointcut log(*) : call (* DB.store(Post p)) && args(*) {
Logger.log(getIP(), *);
}
}

每一個觀點限定了在程式執行到某一個pointcut 的時候(例如某個封包裏某個方法被執行,又或是某個類別的實體被當作傳回值),定義的 pointcut (可以當作執行條件) 內容便會被執行。諸如上面,每當 Post (文章)物件的建構子被呼叫的時候,便會先執行 Validator.sanityCheck()檢查每項參數,通過才可以繼續。資料庫儲存部份亦一樣(我不太跟語法了),每當儲存指令被執行的時候(無論是甚麼地方也好),Logger 便會將一切記錄在案。

AOP 可以簡化程式的邏輯,達到不用修改源程式碼而添加功能。不但如此,AOP 也可透過設立不同的 point cut 來限制條件(Design by Contract),而限制程式碼不會跟真正工作的程式碼糾纏在一起。

我們且看看 AOP 會否流行起來吧。

延伸閱讀:
Javaworld: I want my AOP!
AspectJ – Java AOP Implementation
Wikipedia – Aspect-Oriented Programming – Implementations on various languages

PHP Design Patterns

自從拙文「為甚麼 PHP 沒被大企業採用」登出以後,不少人問「是否你不愛 PHP 了?PHP 在你心目中是不是沒有價值啦?」當然不是!PHP 是強大的語言,開發中小型系統最好不過,但是由於 PHP 平台對分散系統的先天支援不足,所以通常那些跨洋越洲的系統大多選上 J2EE 或 .NET 作開發平台(對了,還有很多系統還用上 C/C++,Perl,etc)。
Continue reading

被遺忘的 template

現在差不多大家也在談 PHP 呢(拜各種實用軟體如 WP,phpBB,postnuke 所賜)。PHP 的好處(也是害處)就是 HTML 和 Logic 撈在一起。好處是,PHP 不會像 Perl 和 Java Servlet 那樣要每行用程式碼把 HTML 輸出到網頁上(echo, print, println),也不用將那些 double quote/single quote 逐個逐個 escape,那麼輸出 HTML 便方便得多。不過,在編程的角度看,方便隱含難以維護的意思。好像除錯、明白別人的程式碼,如果程式碼沒有經過精心的包裝,讀者可能便會遇上老鼠拉龜的情況。對人來說,同時理解兩種電腦語言也許太難了。
Continue reading