顯示具有 Programming 標籤的文章。 顯示所有文章
顯示具有 Programming 標籤的文章。 顯示所有文章

星期六, 1月 15, 2005

Office Rule

#待在辦公室的時間,應注意的原則 (In Python Syntax)

function beingOffice(aCrew):
If (能夠在上司/同事開口問之前就早一步完成工作事項 or
甚至在他們還沒有想到之前就已經完成):
return Great
elsif (比同事晚走 or 比同事早來 or not(比同事早走 and 比同事晚來))
return OK
else:
if name == ’Poya’: raise exception
return (U Got Fired)

星期五, 10月 29, 2004

Embedded a Scripting Engine in Java Apps

在開發應用系統時,使用者有時往往會需要動態地執行程序或更新某些參數。
例如像是電信業的計費公式為了因應三不五時要推出特惠方案而更動、
或是銀行業核准信用貸款的判斷準則等。

但這個時候您可能又不想大費周章地自已搞一套Parser
來解析處理這些公式或規則,
嘿嘿~那麼最好的選擇就是內嵌一個Scripting Engine進來。
而且目前開源項目中已有許多使用Java實作出來各種語法的
Scripting Engine可供我們選擇囉~

更棒的是不但如此,大部份開放源碼的Scripting Engine
還支援了BSF(Bean Scripting Framework)。
http://jakarta.apache.org/bsf/index.html
不過講起來Java的世界就這點很奇怪,Framework特別多,
啥米東東不來個Framework這些人身上好像是會癢 :p

好了~再廢話我怕您會想扁我。言歸正傳…而這個BSF又是個啥米東東哩?
簡單講嘛沒啥就是提供一個共通的介面
將各家不同實作的Scripting Engine包裝起來。
於是乎我們可以很輕易地在系統中切換各種不同Scripting語法,
不過有個前提是這些Scripting Engine有支援BSF。

如此一來便可輕鬆提供多種不同語法供使用者選擇,
這一點相信可帶給系統使用者很大的便利。
甚或是我們可以內建一些predefine function
讓使用者能更直覺地用邏輯概念來組合出其所需的功能出來。

下面介紹一下,小弟實驗過確認可在BSF下執行正常的幾個Scripting Engine:

Rhino: JavaScript for Java

http://www.mozilla.org/rhino/index.html

註記:
雖說目前FAQ上寫支援BSF的版本為Rhino 1.5R2 or Rhino 1.5R3。
但經實測似乎只有Rhino 1.5R2這版可運行正常。


JRuby: Ruby for Java

http://jruby.sourceforge.net/index.shtml


Jython: Python for Java

http://www.jython.org/index.html


BeanShell: Lightweight Scripting for Java

http://www.beanshell.org

註記:
若是您覺得您不太想去重新學習或適應另一套Scripting語法,
想使用一個支援Java語法的Scripting Engine的話。
您可以選擇使用BeanShell。


最後提供一個Expression Evaluator的範例程式,大家可以參考試試看囉 ^_^
對了!!!執行前要記得將各個要用到的
Scripting Engine相對應的jar檔設定到classpath下喔~

import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import org.apache.bsf.*;

public class ExpressionEvaluator
extends JFrame implements java.awt.event.ActionListener {
private JPanel ivjContentsPane = null;
private BorderLayout ivjContentsPaneBorderLayout = null;
private JLabel ivjLabel1 = null;
private JPanel ivjPanel1 = null;
private GridLayout ivjPanel1GridLayout = null;
private JPanel ivjPanel2 = null;
private BorderLayout ivjPanel2BorderLayout = null;
private JPanel ivjPanel3 = null;
private GridLayout ivjPanel3GridLayout = null;
private JPanel ivjPanel4 = null;
private JButton ivjButtonClearResults = null;
private JButton ivjButtonClearScript = null;
private JButton ivjButtonEvaluate = null;
private JComboBox ivjLanguageChoice = null;
private JTextArea ivjTextAreaResults = null;
private JTextArea ivjTextAreaScript = null;
private String language = "javascript";
BSFManager _mgr = null;
Hashtable _htEngines = null;

public ExpressionEvaluator() {
super();
initialize();
}

public ExpressionEvaluator(String title) {
super(title);
initialize();
}

public void actionPerformed(java.awt.event.ActionEvent e) {
if ( (e.getSource() == getButtonClearResults())) {
try {
getTextAreaResults().setText("");
}
catch (java.lang.Throwable ivjExc) {
handleException(ivjExc);
}

}
if ( (e.getSource() == getButtonEvaluate())) {
try {
this.buttonEvaluateClick();
}
catch (java.lang.Throwable ivjExc) {
handleException(ivjExc);
}

}
if ( (e.getSource() == getButtonClearScript())) {
try {
getTextAreaScript().setText("");
}
catch (java.lang.Throwable ivjExc) {
handleException(ivjExc);
}

}

}

public void buttonEvaluateClick() {
evaluate();
}

public void evaluate() {

language = getLanguageChoice().getName();
String scriptText = getTextAreaScript().getText();

System.out.println("Evaluating: {\n" + scriptText + "\n}");
System.out.println("Language: " + language);
Object oResult = null;
try {
getTextAreaResults().setForeground(java.awt.Color.black);
oResult = _mgr.eval(language, "Evaluator", 0, 0, scriptText);
}
catch (Exception ex) {
getTextAreaResults().setForeground(java.awt.Color.red);
oResult = "Exception: " + ex.getMessage();
ex.printStackTrace();
}
System.out.println("oResult:’" + oResult + "’");
getTextAreaResults().setText(oResult.toString());
}

private JButton getButtonClearResults() {
if (ivjButtonClearResults == null) {
try {
ivjButtonClearResults = new JButton();
ivjButtonClearResults.setName("ButtonClearResults");
ivjButtonClearResults.setText("Clear results");
}
catch (java.lang.Throwable ivjExc) {
handleException(ivjExc);
}
}
return ivjButtonClearResults;
}

private JButton getButtonClearScript() {
if (ivjButtonClearScript == null) {
try {
ivjButtonClearScript = new JButton();
ivjButtonClearScript.setName("ButtonClearScript");
ivjButtonClearScript.setText("Clear script");
}
catch (java.lang.Throwable ivjExc) {
handleException(ivjExc);
}
}
return ivjButtonClearScript;
}

private JButton getButtonEvaluate() {
if (ivjButtonEvaluate == null) {
try {
ivjButtonEvaluate = new JButton();
ivjButtonEvaluate.setName("ButtonEvaluate");
ivjButtonEvaluate.setBackground(Color.lightGray);
ivjButtonEvaluate.setText("Evaluate");
}
catch (java.lang.Throwable ivjExc) {
handleException(ivjExc);
}
}
return ivjButtonEvaluate;
}

private JPanel getContentsPane() {
if (ivjContentsPane == null) {
try {
ivjContentsPane = new JPanel();
ivjContentsPane.setName("ContentsPane");
ivjContentsPane.setLayout(getContentsPaneBorderLayout());
ivjContentsPane.setBackground(new Color(172, 179, 191));
getContentsPane().add(getPanel2(), "North");
getContentsPane().add(getPanel1(), "Center");
}
catch (java.lang.Throwable ivjExc) {
handleException(ivjExc);
}
}
return ivjContentsPane;
}

private java.awt.BorderLayout getContentsPaneBorderLayout() {
java.awt.BorderLayout ivjContentsPaneBorderLayout = null;
try {
ivjContentsPaneBorderLayout = new java.awt.BorderLayout();
ivjContentsPaneBorderLayout.setVgap(10);
ivjContentsPaneBorderLayout.setHgap(10);
}
catch (java.lang.Throwable ivjExc) {
handleException(ivjExc);
}

return ivjContentsPaneBorderLayout;
}

public BSFEngine getEngine(String langname) {
if (_htEngines != null) {
return (BSFEngine) (_htEngines.get(langname));
}
return null;
}

private JLabel getLabel1() {
if (ivjLabel1 == null) {
try {
ivjLabel1 = new JLabel();
ivjLabel1.setName("Label1");
ivjLabel1.setFont(new java.awt.Font("dialog", 1, 12));
ivjLabel1.setText("Language");
}
catch (java.lang.Throwable ivjExc) {
handleException(ivjExc);
}
}
return ivjLabel1;
}

private JComboBox getLanguageChoice() {
if (ivjLanguageChoice == null) {
try {
ivjLanguageChoice = new JComboBox();
ivjLanguageChoice.setName("javascript");
ivjLanguageChoice.setBackground(Color.white);
ivjLanguageChoice.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JComboBox cb = (JComboBox) e.getSource();
ivjLanguageChoice.setName( (String) cb.getSelectedItem());

}
});
}
catch (java.lang.Throwable ivjExc) {
handleException(ivjExc);
}
}
return ivjLanguageChoice;
}

private JPanel getPanel1() {
if (ivjPanel1 == null) {
try {
ivjPanel1 = new JPanel();
ivjPanel1.setName("Panel1");
ivjPanel1.setLayout(getPanel1GridLayout());
getPanel1().add(getTextAreaScript(),
getTextAreaScript().getName());
ivjPanel1.add(getTextAreaResults());
}
catch (java.lang.Throwable ivjExc) {
handleException(ivjExc);
}
}
return ivjPanel1;
}

private java.awt.GridLayout getPanel1GridLayout() {
java.awt.GridLayout ivjPanel1GridLayout = null;
try {
ivjPanel1GridLayout = new java.awt.GridLayout(2, 1);
}
catch (java.lang.Throwable ivjExc) {
handleException(ivjExc);
}

return ivjPanel1GridLayout;
}

private JPanel getPanel2() {
if (ivjPanel2 == null) {
try {
ivjPanel2 = new JPanel();
ivjPanel2.setName("Panel2");
ivjPanel2.setLayout(getPanel2BorderLayout());
getPanel2().add(getPanel3(), "South");
getPanel2().add(getPanel4(), "North");
}
catch (java.lang.Throwable ivjExc) {
handleException(ivjExc);
}
}
return ivjPanel2;
}

private java.awt.BorderLayout getPanel2BorderLayout() {
java.awt.BorderLayout ivjPanel2BorderLayout = null;
try {
ivjPanel2BorderLayout = new java.awt.BorderLayout();
ivjPanel2BorderLayout.setVgap(5);
ivjPanel2BorderLayout.setHgap(5);
}
catch (java.lang.Throwable ivjExc) {
handleException(ivjExc);
}

return ivjPanel2BorderLayout;
}

private JPanel getPanel3() {
if (ivjPanel3 == null) {
try {
ivjPanel3 = new JPanel();
ivjPanel3.setName("Panel3");
ivjPanel3.setLayout(getPanel3GridLayout());
getPanel3().add(getButtonEvaluate(),
getButtonEvaluate().getName());
getPanel3().add(getButtonClearScript(),
getButtonClearScript().getName());
getPanel3().add(getButtonClearResults(),
getButtonClearResults().getName());
}
catch (java.lang.Throwable ivjExc) {
handleException(ivjExc);
}
}
return ivjPanel3;
}

private java.awt.GridLayout getPanel3GridLayout() {
java.awt.GridLayout ivjPanel3GridLayout = null;
try {
ivjPanel3GridLayout = new java.awt.GridLayout();
ivjPanel3GridLayout.setColumns(3);
}
catch (java.lang.Throwable ivjExc) {
handleException(ivjExc);
}

return ivjPanel3GridLayout;
}

private JPanel getPanel4() {
if (ivjPanel4 == null) {
try {
ivjPanel4 = new JPanel();
ivjPanel4.setName("Panel4");
ivjPanel4.setLayout(new java.awt.BorderLayout());
getPanel4().add(getLabel1(), "West");
getPanel4().add(getLanguageChoice(), "Center");
}
catch (java.lang.Throwable ivjExc) {
handleException(ivjExc);
}
}
return ivjPanel4;
}

private JTextArea getTextAreaResults() {
if (ivjTextAreaResults == null) {
try {
ivjTextAreaResults = new JTextArea();
ivjTextAreaResults.setName("TextAreaResults");
ivjTextAreaResults.setBackground(Color.lightGray);
ivjTextAreaResults.setFont(new java.awt.Font(
"monospaced", 1, 12));
ivjTextAreaResults.setEditable(false);
}
catch (java.lang.Throwable ivjExc) {
handleException(ivjExc);
}
}
return ivjTextAreaResults;
}

private JTextArea getTextAreaScript() {
if (ivjTextAreaScript == null) {
try {
ivjTextAreaScript = new JTextArea();
ivjTextAreaScript.setName("TextAreaScript");
ivjTextAreaScript.setBackground(Color.white);
ivjTextAreaScript.setEditable(true);
}
catch (java.lang.Throwable ivjExc) {
handleException(ivjExc);
}
}
return ivjTextAreaScript;
}

private void handleException(Throwable exception) {

System.out.println(
"--------- UNCAUGHT EXCEPTION ---------");
exception.printStackTrace(System.out);
}

private void initConnections() {
getButtonClearResults().addActionListener(this);
getButtonEvaluate().addActionListener(this);
getButtonClearScript().addActionListener(this);
}

private void initialize() {
setName("ExpressionEvaluator");
setTitle("BSF Expression Evaluator");
setSize(426, 240);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container cp = this.getContentPane();

cp.setLayout(new BorderLayout());
cp.setBackground(new java.awt.Color(228, 223, 228));
cp.setForeground(new java.awt.Color(0, 48, 104));
cp.add(getContentsPane(), "Center");

initConnections();
initializeBSF();
}

protected void initializeBSF() {
if (_mgr == null) {

System.out.println("Initializing");
_mgr = new BSFManager();
_mgr.registerScriptingEngine("", "", new String[] {});
getLanguageChoice().addItem("javascript");
getLanguageChoice().addItem("ruby");
getLanguageChoice().addItem("jython");
getLanguageChoice().addItem("beanshell");
}
}

public static void main(java.lang.String[] args) {
try {
ExpressionEvaluator aExpressionEvaluator = new
ExpressionEvaluator();
aExpressionEvaluator.setVisible(true);
}
catch (Throwable exception) {
exception.printStackTrace();
}
}
}

星期三, 9月 22, 2004

Java連線版之怒火燎原

沉寂以久的連線版最近又開始熱絡了起來,
在一陣你來我往的爭論中,果然牛肉就跑出來了。 ^_^

感覺上重點應該是擺在建立節省不必要記憶體浪費的觀念,
而非是GC是如何實作。尤其當一個團隊在合作開發時,
若成員中缺少這方面的共識,一旦出現OutOfMemory的問題時。
萬一起因為memory leak,不能裝闊加ram解決時,
靠~那可不是開玩笑,要debug起來真是會de死人 >_<

不過參與討論時,一個基本的態度應該是先把整個討論串看完。
不然真是會討論到張飛打岳飛、打的滿天飛~
沒想到為了這種鳥事還跟人吵了一架。

結論:Java果真是殺人於無形呀~ -_-|||

星期四, 7月 29, 2004

想偷偷推一下JBuilder

最近看到yoshi講他一氣呵成寫完程式再到Compile時,
只有幾個exception忘了catch,其它竟然完全沒錯。
突然覺得若是他平時習慣的是一套強力的IDE工具。
如Eclipse or JBuilder之類。
搞不好就真的一氣呵成寫完包jar直接發佈出去哩。

老實講是覺得習慣一套IDE工具對工作效率提升有很大的幫助,
當然工具好不好用往往跟習不習慣是正相關的,
我也見過真的有人就只用Ant + 純文字編輯器一樣工作效率很高。
只不過這樣的高人就像是天邊漂流的浮雲般令人望塵莫及,
記憶力薄薄大概只有如二張紙片的我,也只好想辦法尋求凡人的救贖之道。

先感謝Borland製作了JBuilder這般神奇的工具。
但其實也並不是對Borland有所信仰,每次聽說別家有一些神奇的新功能時,
也是會興致勃勃地去灌來試用看看。
但到目前為止最終留在硬碟裡的還是JBuilder。

讓人脫離不了JBuilder,主要是因為那些基本的語法自動檢查、程式自動排版外,
其它還有像是find Definition、find (Local) References等…
上述功能配上整合GUI環境的Debug mode,追流程、查bug真的是超easy

快速開發上提供了JavaBean Express及與各種framework整合的Deamon,
Deamon設定完順便還可產生簡單的Test Client。
另外對refactoring的支援也不錯,至少一般常用的都有了。
接下來習慣hot-key後,工作效率馬上再次提升至少一個檔次以上。
該怎麼說呢?這就好像一個用慣嘸蝦米輸入法的人開始學會打簡碼的感覺。

再加上還可設定與CVS的同步、簡單的DB Pilot,程式寫完自動包成jar檔…
好用的功能真是數也數不清,像是java doc那些,也是用介面簡單key-in就好,
不然誰記性那麼好去背那些tag呀 :p

在Borland買下Together後也有推出與JBuilder整合的版本。
爽的話還可以來個雙向工程作業,畫畫圖code框架就跑出來,
不然code寫完,像sequence diagram這類的鳥圖自動幫您生出來,
相信在為了緊急應付一些紙上作業時真的會讓您感到愉快許多 XD

廢話講了那麼多,講真格的有時夜半無人自已用用JBuilder都嘛會偷笑。
神呀~這世上怎麼會有這麼好用的IDE,
我真怕有個萬一Borland倒了以後用不到了要怎麼辦呀 XD

星期六, 10月 11, 2003

Software Fashion


http://www.softwarereality.com/soapbox/softwarefashion.jsp#id27


蠻搞笑的文章,原來軟體也可名列時尚業呀~
談到一些不適當的技術應用,加上誇大的宣傳、過度的銷售
讓人更能體會所謂的追求軟體時尚是怎麼一回事

生活上的例子就像讓胖妞穿比基尼,讓模特兒穿孕婦裝一樣
而在軟體開發上,就如同使用EJB來開發小規模的商用軟體
將XP應用在短期的專案上;利用taglib來加入一些新的meta-language
最後發覺除了製造混亂外,似乎對開發毫無益處
或是當團隊中的那個人閱讀了GOF後,
就瘋狂的想要把所有可能的pattern塞進設計裡

文中還有一個爆笑的面試對談
面試官:呃~請問你最愛的Design Pattern是那一個呀?
求職者:喔~我愛死Decorator,啥米地方我都想來一下Decorator耶~
(我哩~果然是有怎麼樣的考官就會有怎麼樣的答案)

而當宣傳超過人們能客觀地評估技術的時侯,就是開始發生技術誤用的時刻
就像許多時侯人們選用XML的原因,就是因為它是XML XD
這段調侃XML的部份,讓我想到最近電視常在打的廣告
命運騎寵系統狂飆上市的那隻豬,哈~我哩我還飆豬哩

順便還虧了Sams的Teach Yourself xxx in 21 days系列一把
講這些出版商唯恐天下不亂
還會趕緊出本Teach Your Micro-Horse to Sing in 21 Days!

不過當我們選用某項新技術時,到底是因為它正好適合我們的開發需求
或著只是想到這項新技術寫在履歷表上看起來還蠻不錯的?
啥…你問我是怎麼想的,呃~我只能學呂副總統回答你"嘿嘿嘿"

在Popularity vs. Platform Size那段的最後
提到IT廠商不會再咬第二口蘋果也真是神來之筆
apple fans抱歉了:)

接著就是大戰的開始
提到了三項作者認為有遭到誤用的時尚技術
1. VB.Net
2. Struts
3. XP

講到Struts時一開頭還特別挑戰了Struts的使用者
希望他們儘量放馬過來,講講為啥要用Struts
這裡的用詞有點誇張,講的似乎Struts一無是處
還要透過xml的設定用迂迴的方式增加不必要的層級
啥米用了Struts簡直是花了二倍的功夫
簡單的web ap會變複雜,複雜的web ap卻還是沒簡化到哪裡去

這裡似乎又講到一個職場的現實
這年頭出來找頭路,許多面試官也受到時尚技術的影響
於是乎想寫個web ap(java solution),似乎無可避免的還得要會Struts
不過最後的結論我蠻同意的
不管是啥米東東啦…XML現在似乎是用的太泛濫了些

對XP的評論更毒
講的是好像XP將開發速度定下了個20哩的速限
超過速限的就要抓起來
因為開發者不愛互相溝通,就來個pair programming
因為開發者不愛跟客戶溝通,就讓客戶加入開發小組中
因為開發者不愛測試,所以寫code前要先寫測試…etc

好了,可想而知在該文後面還有一大團,以上各技術愛好著的反擊
大家有興趣的可以慢慢欣賞
諸如像VB.NET是C#的窮親戚,
或是VB.NET不過就是C#之上的語法糖果之類的爭論

雖然我想作者是故意寫給人家批的
不過所點出的現象很值得大家思考

難道選用熱門的時尚技術
是因為,嘿~大家都在用,呀那個國外大廠也嘛在用,還有大師的加持哩
喔~拜託一下,有沒有就是在我們週遭的成功案例呀

老是在講彈性、彈性
切割了許多層來達到所謂的低耦合
到底實不實際

台灣真正的軟體公司到底有幾家呢?
在講究快速開發(結案收錢)的情況下,
設計出那麼多的可擴充性又如何?
我們真的需要那麼多彈性嗎?

覺得國外的成功案例是有時空背景因素在,
而過了水到了台灣後,或許我們又得因應這樣的環境來調整開發的方式。

星期六, 8月 23, 2003

讀Refactoring一書有感

重構

其實很早就拿到這本書原文電子檔
不過語言上的隔閤卻讓我對這道美食始終難以下嚥
總是翻個二、三頁就去見周公去了
時日一久竟也忘了這本書的存在
真是要感謝侯老師及熊節先生的無償提供前1-6章的中文譯本
火熱下載點:http://www.jjhou.com/jjtbooks-refactoring.htm

首先強烈建議先閱讀本書第一章
因為實在是寫得太黯然、太銷魂啦
我真怕以後看不到這樣的好書該怎麼辦
此章透過一個逐步重構的實例來點出重構技巧的神奇
讓一隻堅硬如石的程式慢慢軟化
相信就算您是個修道多年
信仰忠貞以設計為先的道徒
看完這章大概也會馬上拋開所有禮教
還俗投入重構的美麗新世界中

好吧…我承認這樣講是有點誇張,
但是不誇大哪會有噱頭引您往下看哩

其實重構的步驟也不用想得很複雜
重構的目的並不是為程式增加新功能
只是為了提高程式的可讀性及重用性
重構有時只是改變一下程式碼的位置或取個更有意義的變數名稱,
再將其放置在適當的位置
例如像當A類別內某個函式的頻繁的操作B類別的屬性
或許這就是一個暗示,暗示我們應該讓這函式回歸至B類別處
讓資料和引用這些資料的操作總是在同一個類別之中發生

而Design Pattern則是為Refactoring建立了一個依循的方向
所以當我們透過良好的設計範式來切割類別間的關係時
有些類別間比較複雜的函式根本不會知道外面的世界已經變天哩

再來什麼時候你需要重構哩
例如當你發覺程式寫好一週後,再回去看它時
突然懷疑一週前你是不是有被火星人附身時
你肯定需要重構一下你的程式

另外在書中也提到
我們可依循三次法則
事不過三、三則重構

而若是對於已發佈介面published interface進行重構
則我們可以保留舊介面,用其呼叫新介面
但千萬不要再犯copy-paste的錯誤
並可透過deprecated來標記舊介面
提醒及避免其他人再繼續呼叫這個介面

有時為了撰寫上的方便
我們會讓暫存變數被賦與二次以上的值
像類似這種一時的便宜行事,卻會造成事後對程式的意圖造成理解上的困難
於是像這樣的地方,我們也應該透過重構的技巧來重整它
書中常見的手法就是將拆解成多個足以自我說明其意義的變數
然後我們可將新的暫存變數宣告成final,
便可透過compiler來檢驗是否仍有重覆賦值的缺失

而對於Java為何選擇pass by value而非pass by reference有疑問的人
可以看一下Remove Assignments to Parameters這個重構手法
其實重點就在於強化程式的清晰度及減少非預期的邊際效應

相信你一定有這種經驗
看到一個超肥的大型函式…讓人一時之間慌了手腳不知從何剖析它
這時我們可運用必殺技Replace Method with Method Object
將此大型函式獨立宣告成一個物件
如此一來函式內的變數就成了該物件的欄位
然後我們就可任意肢解這個大型函式,而不必傳遞任何參數
使其各自成為精巧且更具可讀性的小型函式

另外書中有段話雖然跟重構無關,但我覺得實在是講得太好了
也順便節錄一下
"懶惰是程式員的美德
所以能立即查閱的東西
千萬別記在腦子裡
免得把腦袋塞爆"

而書中有些教條式的守則
我想就算一時間不能體會
背起來也是無妨
例如:見到黑影就開槍
喔~不對、不對....
是看到switch就想到polymorphism
或是
當你感覺需要撰寫註解前請先嘗試重構,試著讓所有註釋都變得多餘
(設計良好的程式本身就應具有解譯自身意圖的能力)

在第四章提到了撰寫自我測試程式的重要性
測試是重構的前提
而一般慣用的手法都是寫test main()
不過缺點就在於難以執行多種測試
所以在此章裡介紹了如何透過JUnit來執行測試

總的瀏覽本書前一至六章一遍後
我想起我的前小組長也十分愛玩重構的遊戲
每每看到我寫得亂七八糟的垃圾一到他手裡就被重構的井然有序
內心深處總是覺得十分的佩服…
曾幾何時我幾乎認為那是我達不到的彼岸

因為覺得自已即不是記憶力超強的陳俊生
也不是火星來的假面怪客
能在腦中憑空勾勒出理想中的設計模型

不過現在若是能一步步透過書中所介紹的重構技巧…
或許能使得平凡如我,也能有機會一窺外星人的境界

也記得有陣子我看到OO就很煩
總感到造成追縱程式流程的困難,就是在不斷的delegation之後
看了本書中p.61間接層及重構後
仔細想想才體會到原來間接層所帶來的利益為何

慢慢發覺我的壞習慣是太愛追根究底
實際上好的切割及命名法則,可使我們更能憑著直覺,
來理解程式的執行

而一如GOF的Design Pattern般的鉅作
本書照慣例創造了許多術語
不過感覺上各項重構的命名是容易會意的多,若是為了溝通方便
其實倒是蠻容易記憶的
請想像一下以下的討論場景

強者H:嘿…我覺得這裡該嘗試用Extract Method來重構
小呆P:嘩~醬子這個Method得傳入一狗票參數耶
強者H:呀不然這邊再搞個Preserve Whole Object
小呆P:鳴鳴鳴…Object之間的界定還是很難搞定呀
強者H:好吧…那就出必殺技Replace Method with Method Object吧
小呆P:救命!!! 我頭昏了啦 @_@

是不是覺得有了術語的協助,其實更能增進溝通的效率呢?

雖然從現實角度來看一個軟體專案的執行
往往都因deadline緊迫而壓縮整個開發的時程
這個時候去考量重構來讓往後開發或維護更加順利似乎是有點緩不濟急
不過方法在這裡,如何巧妙的應用及選擇合適的時機點切入
相信就要由聰明的您自已來判斷了

最後我想這本書讓我感到最珍貴的
就在於作者Erich Gamma將平時一些難以言傳的重構技巧
作一個有系統的整理及說明
讓想要學習重構技巧的人能感到有所依循
跟隨著大師的腳步前進
相信總是比憑著自已的直覺要來的準確的多

看到這裡,大家有沒有開始覺得手癢起來了呢?
對於你一直看不爽的code,現在就讓我們動手來肢解它們吧!!!

後記:
雖然書中也提到重構不是建構軟體的銀子彈
至多只能算是把銀鉗子
但我還是感到十分的興奮
迫不及待的想把讀後心得分享出來
並且開始對Smalltalk產生了好奇心
有沒人要來澆盆冷水的呀 :p

星期四, 7月 03, 2003

Oracle SQL statement Tuning tips

1 衡量table筆數,以便拆解statement時選擇適當的順序來執行
2 拆解statement,利用sub query的方式
,可分段check response time找出效能缺口
在8i之後在select,from,where後均可加入sub query
重點在於先將筆數多的table拆解出來。
tune完整段仍有問題時,則應檢查index、或是where部分是否仍為效能缺口
3 針對where條件欄位加入index or 移除不必要的index
4 使用Hint,透過Hint可強迫DB在執行各項Query時採用特定的方式,
不過似乎並無特定的rule可尋,只能依經驗或靠tuning tool來協助
找出最佳解。
EX: select /*+ first_rows */ name,department from dept;
5 check index
check fragmentation(類似硬碟重整)
adjust chain row(用以調整一次抓取資料的Block範圍)
6 不能以null作索引,任何包含null值的列都將不會被包含在索引中。
也就是說如果某列存在空值,即使對該列建索引也不會提高效能。
7 避免萬用字元%在搜尋字首出現,因會導致Oracle無法以此欄位建索引。
在很多情況下可能無法避免這種情況,
但是一定要心中有底,萬用字元的使用會降低效能。

通用原則:
1 not in比in費時(避用)若要用則應改寫為NOT EXISTS子句
同樣的在Oracle中幾乎可將所有的IN操作符子查詢改寫為使用EXISTS。
2 distinct、order by費時(應拆解至細部sub query,避免擺至最外層)
3 要避免直接對driven table作運算
例:where to_char(date,’yyyy/mm/dd’)=’2003/07/02’
應改為:date = to_date(’2003/07/02’,’yyyy/mm/dd’)較有效率
4 若比對條件式中含有常數,則應將此段query擺在前頭

補充:
1 雖然用Hint 可快速解決當下Sql 速度慢的問題.但須經常重新Tuing,
因為一段時間之後,Table 的筆數增長各有不同.
所以時間久了,原本可改善的Rule 反而不管用.
2 增加Index 並非萬能,因為多增Index 會影響Table
在執行 DML (Insert/Update/Delete) 的時間.
3 在 Oracle 的 Performance & Tuing 裡,
除了Sql 下的好不好以外, DB 的參數設定值亦是關鍵.

星期三, 8月 21, 2002

A little thoughts about TIJ2

Thinking in Java

關於TIJ2這本書,無庸置疑的是一本內容精彩的好書
且原作者Bruce Eckel十分慷慨的在網路上開放了本書的所有內容

就如同侯老大的譯序中所說,我們很容易找到同樣閱讀過本書的同好
而大家可以在同一基調上針對書中的內容開始討論。

也因此許多高手也推薦此書給入門者,稱此書為絕佳的入門教材。
而許多人也因而隨之起舞,用力的為此書大大宣傳。
這陣子,大概只要在網上問:請問Java入門書那本最好?

必然會有一群熱心人士,努力回覆並介紹TIJ2給這位初學者。
不過這樣真的好嗎?TIJ2真的適合初學的人使用嗎?

我想分享一下我初學Java時的看TIJ2的感覺。
當時我正為Java到底是Call by XXXX的問題所迷惑。
如果你想看看我當時的疑問,請點下面這行字

【EZ Java 】Call By XXXX?!


於是網友yiwen建議我看TIJ2,那時看完書中說明後還是有點模糊不清。
不太能體會其中真正的含意。

不過,我想既然TIJ2這本書這麼好。
於是我把原本正在看的入門書籍先擺在一旁。
想說那我就把TIJ2當入門書就好了嘛。

沒想到這正是困惑的開始。
由於書中提供的資訊太多了。
對於那時完全沒有物件導向概念及Java基礎的我。
閱讀此書的經驗簡直是場惡夢。

常常讀到一小段,就為了不明瞭其含意的句子而苦惱不已。
那種感覺就像是遇到網頁上的超鏈結地獄一樣。
往往從一個疑問連結到另一個疑問。
最後變成一團混沌。

最後我放棄了以TIJ2為入門書這個念頭。
回頭重拾原先那本已看到一半的入門書。

那時我心中有個預感。
或許我該等我對物件導向有點概念,
且對Java的架構有些概觀後再回頭來看TIJ。

直到最近侯老大與王建興先生合譯的TIJ2終於出版了。
昨日去誠品翻閱後,可能是因免除了語言上的隔閡。
也或許是由於心中對Java已有了點小小的概觀。
重讀TIJ2後,心中感到十分充實。

先講譯筆好了,的確譯的十分清楚明白。
雖然第一章的某些部份有點繞舌。
不過我想有些英文的詞彙要翻成中文就是怪怪的吧。
但是還是很容易了解其所要表達的含意。

另外很多人批評的排版問題。
我倒是沒覺得看起來特別的難過。唯一覺得不太習慣的部份,
應該是程式碼的字體吧,太大了點,感覺有點奇怪。
不太喜歡看一小段程式碼還要翻頁的感覺。

我想重新閱讀TIJ2讓我對之前很多模糊不清之處。
有了一個重新複習與反芻思考的機會。
尤其是當我們習於try & error的學習方式。
往往會知其然而不知其所以然。

有本醬子的書籍提醒、整理算是相當不錯
也感謝侯老大及王建興先生譯了這本好書 ^_^

星期六, 7月 06, 2002

Things to Consider When Building Large Business Systems

最近小弟我在看Marstering in EJB2
(可在TheServerSide.com上Free DL ^_^)
在第一章Page38-39中列出了的一項大型商業系統需求清單

在要開始往下了解為啥米要使用EJB前,
先了解大型商業系統所需達成的目標。
所以我想這份清單蠻重要的。
小弟現將其翻譯出來與大家分享

原書中這份列表只是將這些項目列出來並稍作說明。
小弟將我所能理解的意思照翻。
希望大家發覺有錯誤之處能加以指正。
或是覺得原書中過於簡略說明的部份,想加以補充也歡迎修正。

希望這樣的補充能對大家思考如何建置一個完備的系統有所幫助。

Things to Consider When Building Large Business Systems

建置大型商業系統時需列入考慮幾項部份

Remote method invocations.

我們需要將server-client之間透過網路連結的關係邏輯化
這包含了分派服務需求、管理參數及其他更多的細節。

Load Balancing.

Clients應該是以最輕負載來對Server發出請求服務。
如果某一台server發生超載,
那麼應選擇由另一台server來執行此項服務。

Transparent fail-over

一旦某一台server掛點或是網路掛了。
可以在無中斷服務的情況下快速導向至另一台server嗎?
如果可以,那麼有多快可達成錯誤回復?是幾分?還是幾秒?
這是指你的商業服務所能忍受中斷的回復時間。

Back-end integration.

商用資料在寫回資料庫時需考慮與原先舊有系統的資料間有良好的整合。

Transactions.

當有二位客戶同時存取資料庫中的同一欄位時。是否會使資料庫資料損毀。
交易的確認及保護是此項議題的重點。

Clustering.

如果server所保存的狀態毀壞了,這個狀態的值是否已備份至其它server上了?
而clients是否可以繼續使用不同的server所提供的服務。

Dynamic redeployment.

當系統正在持續運作時,我們該如何對它來作更新的動作哩?
你需要暫時的關機停止服務或是能夠持續地執行服務呢?

Clean shutdown.

如果你需要將server關機時,你能很順利的管理資源的回收或資料的保護,
而又不中斷目前正在服務的項目嗎?

Logging and auditing.

當系統出現錯誤時,我們能擁有完整的log來解決或發現問題原因嗎?
完整的log可幫助我們發掘問題的關鍵點並使它不再發生。

Systems Managemetn.

當災難性的錯誤發生時,誰來監控我們的系統?
我們需要一項軟體來自動監控,
以便當災難發生時自動去呼叫管理者來處理。

Threading.

假設現在我們有許多的clients要與server作連結,
而server必須有能力去處理這些client同時發出的服務需求。
這表示server必須是具有多執行緒的能力。

Message-oriented middleware

clients-server間是以明確的訊息型態為基礎來構成此鬆散的架構。
我們需要一些基礎架構來包含處理這些訊息。

Object life cycle.

存在於server上物件的產生及消滅,由client的需求而定。

Resource pooling.

如果某一client不再使用先前所取得的server端資源,
那麼server端的資源將被集中在一處(Resource pool)
等待其它clients連結後再利用。
這包含了像是sockets(例如與資料庫的連線)也如同一些存在於server端的物件。

Security.

系統及資料庫皆須要保護以免受到外來的惡意破壞。
執行使用者命令前,
應確認使用者所執行的是經由允許且他們有權執行的操作指令。

Caching.

讓我們來假設一種情況,
這兒有些資料庫的資料是要讓所有clients所共享及使用。
比方如:一般的產品型錄。
那麼為何我們要讓server一次又一次不斷的去和資料庫取得這些相同的資料。
我們可以讓這些資料保存在server的記憶體中
去避免往返於資料庫之間的存取動作。

當然還有更多更多建置大型商業系統時需列入考慮部份

上述的每一項議題都是一項可分離的服務,
皆須要認真的思考如何處理這些伺服端的運算。
而這些服務是在任何商業問題及各種獨立的企業都所需要的。
現在這些服務被稱之為中介軟體(middleware)

星期三, 3月 27, 2002

Lottery Lucky Number Generator


import javax.swing.* ;
import java.util.*;
public class EZLottery {
private static int allNum[]=new int[42];
public static void main ( String args [] ) {
for (int i=0;i < class="blue">//把42顆彩球裝箱
allNum[i]=++i;
}
String output="";
int[] luckyNum = getLuckyNum();
Arrays.sort(luckyNum);
for (int i = 0; i < luckyNum.length-1; i++) {
output += "【" + luckyNum[i] + "】";
}
JOptionPane.showMessageDialog ( null , output +
"特別號【" + luckyNum[6] +"】" );//秀出結果
System.exit ( 0 ) ;
}
private static int[] getLuckyNum() { //將前七個彩球隨機打亂
int selectNum[] = new int[7];
for (int i = 0; i < selectNum.length; i++) {
int num = (int)(allNum.length * Math.random());
int tmp = allNum[i];
allNum[i] = allNum[num];
allNum[num] = tmp;
}
for (int i = 0; i < selectNum.length; i++) {
selectNum[i] = allNum[i];
}
return selectNum;
}
}