物件導向技術的光環效應

11/24/2008
要是你以為穿上一雙 Nike 球鞋,就可以像喬登一當抓球飛身灌籃,這叫做「錯覺」,是自欺欺人,不可能發生的事。
--Phil Rosenzweig, 《光環效應》

近日聽到一些有關 OOAD 的正反意見,這篇文章只是在整理自己對這些意見的一點感想。

光環效應:過度渲染 OO

在碰到推廣 OO 技術的場合,常會聽到傳統的程序導向分析和物件導向分析的比較,並宣稱如果團隊採用 OOAD 方法,軟體專案將能夠獲得許多好處。以下是我最近聽到的一些說法:
  • 更模組化。理由:藉由類別封裝,應用程式都會被切成適當大小的單元。(真的嗎?)
  • 可提高重複使用性。理由:物件導向有繼承機制。(反面來看:牽一髮動全身的連鎖效應?)
  • 應用程式更容易擴充。理由:未來如果需要增加一項新功能,我們只要增加一個類別,再動態「插入」既有的框架就行了,用戶端程式都不用修改。(如果設計得宜的話)
  • 應用程式更好維護。理由:將來如果有一個地方要修改,我們就只要改 XX 類別就行了,其他地方都不用動。(如果設計得宜的話)
  • 更自動化、更一致的開發模型。理由:我們使用自動化工具來設計和產生類別骨幹,程式設計師只要填肉進去就行了。(高度懷疑此說法,包括其實用性以及產出的品質;此外,我們是否正在將程式設計師塑造成不動腦筋的 coding machine?)
  • 文件更清楚、更好管理。理由:我們全部使用 Use Case 規格來描述功能需求,所有的分析設計文件和模型都是用工具管理,所以文件更集中、好找,也更能清楚表達系統規格。(用工具集中管理的確有好處,但是跟文件內容是否清楚達意無關)
每當聽到有人宣稱只要採用 OO 就能獲得上述優點,我不禁懷疑,他曾經帶領或開發過幾個成功的 OO 專案?或者最起碼,寫過幾個 OO 程式?如果沒有用一個實際的小案例將整個設計 walk through 一遍,光憑這些接近廣告的說詞,實在很難確定他的團隊是否有把 OO 技術用在對的地方。

OO 技術可以協助設計師思考如何切割系統,將一個複雜的系統分出條理,切成幾塊,再針對各部分逐步細化、各個擊破。Grady Booch 等人在 《物件導向分析設計與應用》裡面指出:「對軟體的複雜性不夠了解,是導致專案延遲、預算超支、以及無法滿足需求的主要原因。」因此真正的關鍵在於如何對付軟體本身固有的複雜性,至於上面所說的那些 OO 優點,很多都是跟人如何用 OO 去設計,以及團隊的開發流程與專案管理實務有關。

淑女和賣花女的差別不在於她們的行為舉止,而是人們對待她們的方式。
--蕭伯納《賣花女》

光環效應:聽說 OO 太理論

另一種極端,是對 OO 技術棄如敝屣,認為那根本是空談、是理想、空有理論的東西。就我個人的經驗,實際上抱持這些想法的人,或多或少都曾在 OO 的路上跌跤,或者受到過多反 OO 言論的感染,而沒有機會實作 OO、深入了解 OO 實際的優點(和缺點)。我想道理很簡單:如果未曾試著了解某件事物或某個人,又怎麼能對它妄加論斷呢?

我不是說每個不贊成 OO 技術的人都是如此,這只是陳述我自己碰過的情形。其實,就算在軟體專案中嘗試導入 OO 技術而不幸失敗,也不見得是 OO 本身的問題。專案失敗的因素通常很多,若沒有深入分析,就把失敗原因歸咎於採用 OO 技術,恐怕是太武斷了。

一位著名的統計學家指出,十九世紀的美國因為酒醉被捕的人數,和牧師的人數呈現明顯相關性。我們認為兩者人數的同時增加的確有明顯相關性,但卻沒有因果關係;此現象反而是另一個因素造成的:美國人口大幅增加。
-- Stephen Jay Gould,《生命的壯闊》

以下是我所聽到的一些關於 OO 的批評與反面意見:
  • OO 其實是很古老的技術了。
  • OOP 還有些幫助,但 OOAD 的 reuse 根本是謊言,business objects 根本不能重複使用,每一個專案都要重寫。(儘管 business objects 很難跨專案 reuse,但分析設計的 patterns 還是可以重複使用。不要只看 code reuse,對設計師來說,design reuse 也很有幫助。記得要 reuse in the large)
  • 其實台灣根本沒有多少人真正實行 OO 技術,甚至大學課程都沒什麼在教了,因為太理論了,上不了戰場。(呃...我沒有數據,但這說法似乎有打迷糊仗的嫌疑,以及因為自己不用或用得不好,所以也同理可證地認為別人沒在用或用得不好。)
  • OO 方法設計出來的程式效能很差。(一般來說,如果類別階層較深,執行速度是會稍微慢一些,但如果「效能很差」指的是數倍以上的速度延遲,那可能得看程式或架構的設計,才能判斷是因為 OO,還是人的因素。)
  • 現在的 OOAD 都被程式語言限制住了,大家都只會 Java、C++ 這些,所以思考方式都被程式語言的語法框住了,沒辦法想出更好的設計方法。(是程式語言本身的表達能力過於侷限而阻礙了人的思考,還是人的知識、技能、與想像力不夠?)
  • 對一個問題的設計,John 可能會用 5 個類別來解決,Vivid 可能會有 3 個類別,而 Michael 可能就只用一個類別來解決。那麼,誰來決定哪一種設計是正確的?OO 的問題就在這裡,不像關聯式資料庫,還有正規化理論可以驗證;OO 設計根本沒有標準可言,那我們怎麼確定你的設計就是對的?(That's why we need architects and reviewers.)
人的思維的確會受限於既有工具的框架,但是專案的失敗或程式品質不良,真的絕大部分都是因為開發人員受到程式語言或工具本身的侷限而無法達到他所想要的設計嗎?這點我是挺懷疑的。

此外,最後一項批評認為:OO 設計沒有任何標準可茲驗證其正確性。這個說法我認為似是而非。我們不妨把「OO 設計」替換成其他字眼,應該就能看出它的問題在哪裡,例如:「結構化分析設計」、「敏捷開發方法」、「C++/Java/VB」。

好比蓋房子,工程師根據設計圖蓋了一棟大樓,是否有標準方法可以驗證這棟大樓的設計一定「正確」,因此住戶住起來都一定覺得舒服?如果有這種標準,我們買房子時就不用先看屋了,只要用工具檢測一下就知道這棟大樓設計的「正確性」。這跟防震、輻射檢測安全標準、或建築法規完全是兩回事;它牽涉的是設計的部分,比較偏向藝術,而非精確的科學。

軟體開發技術不斷改進,是為了提供更好的方法,以協助開發人員設計出品質更好的產品(當然不見得每個新方法都是好的)。我們可以試著遵循一些方法和最佳實務來改善設計的品質,但軟體該如何設計存乎一心,就像每個廚師都能用同一套工具和食材變出不同口味的菜色--哪有要求驗證料理的口味是否符合「統一標準」的道理呢?

小結

這裡我就自己所見的情況整理了一些有關 OO 的正反兩面說法,並加入了個人的意見。我想,輕易全盤相信一套說詞總是不妥,我們能夠做的,還是多看、多學、多實作,並相信自己的體會吧。

最後謹以 Frederick Brooks 在《人月神話》中引用 David Parnas 的話作結尾:

「我們是否能寫出好程式或爛程式,跟使用什麼樣的工具並沒有關係。除非我們教大家如何設計,否則這些語言發揮的效用就會很有限,結果就是大家用了這些語言做出了爛設計。」

《UP 學》:如何避免成為渾球

11/23/2008
《UP 學:所有經理人相見恨晚的一本書》閱讀筆記

利用程式發送 MSN 訊息

11/22/2008
會寫這個程式,主要是因為一個重要的 Web 應用程式三不五時會掛掉,而系統管理員希望能在第一時間發現這個情況(以免使用者來電開罵)。

要偵測伺服器是否掛點,可以用 .NET 的 TcpClient 嘗試連接伺服器的特定 port,這種簡單的方法不僅可以用在 Web 伺服器,也可以用於資料庫伺服器(例如:嘗試連接 Oracle 伺服器的 1521 port)。

一旦發現伺服器無法正常運作,程式可以發送 mail 通知系統管理員,可是系統管理員不見得會經常收信,這樣的時效性就不夠快。現在 MSN messenger 已經很普遍,如果發現系統出問題時,能夠發即時訊息給相關人員,似乎是個不錯的辦法。

這裡我用來發送 MSN 即時訊息的元件是 MSNPSharp。這個元件有附一個 Windows Forms 範例程式可以參考,此範例就像一個陽春型的 MSN Messenger,可以讓你登入 MSN 伺服器、發送訊息給聯絡人等等。

仔細研究這個範例程式,大概就可以瞭解 MSNPSharp 的基本用法,同時也可以發現,此元件大量運用了非同步處理的程式撰寫模型。這種非同步的撰寫方式不僅增加了學習門檻,除錯也比較麻煩,更重要的是,這並不是我想要的。

我的需求很簡單:當程式需要發送 MSN 訊息時,就先登入 MSN 伺服器,然後依事先設定的聯絡人逐一發送文字訊息。訊息發送的對象有可能是離線狀態,這沒關係,繼續發送給下一位聯絡人即可。

針對上述需求,我寫了一個簡單的 wrapper 類別:SimpleMsnMessenger。這裡我不打算詳細說明原理,謹列出幾個重點步驟:
  1. 建立 Messenger 物件 => messenger。
  2. 利用 messenger.Connect() 登入伺服器。
    關鍵事件:messenger.Nameserver.SignedIn
  3. 利用 messenger.CreateConversation() 建立 Conversation 物件 => conversation。
    關鍵事件:messenger.ConversationCreated
  4. 利用 conversation.Invite(("someone@hotmail", ClientType.PassportMember); 邀請對方加入對話。
    關鍵事件:conversation.Switchboard.ContactJoined (已成功邀請對方加入對話)
  5. 利用 conversation.SwitchBoard.SendTextMessage() 發送文字訊息。
有興趣研究的朋友可以參考這篇文章:MSNPSharp傳送信息程序詳解,大致瞭解其設計原理後,再對照範例程式來研究,應該就比較容易瞭解 MSNPSharp 的基本用法。

SimpleMsnMessenger 的完整程式碼可按此連結下載。Note: 此程式碼還有許多改進空間,尤其是錯誤處理的部分,但基本上還堪用。

以下是使用此 wrapper class 的範例:

class ServerAliveChecker

{

private SimpleMsnMessenger msn = new SimpleMsnMessenger("robot@hotmail.com", "password");

private void SendMsn(StringBuilder text)

{

string receivers = ConfigurationManager.AppSettings["ReceiverMsn"];

if (String.IsNullOrEmpty(receivers))

{

return;

}

lblStat.Text = "正在傳送 MSN 訊息...";

Application.DoEvents();

string[] msnMail = receivers.Split(';');

try

{

msn.Connect();

// 等待登入動作完成。

while (msn.IsConnecting && msn.ErrorCount <= 0)

{

Application.DoEvents();

}

if (msn.Connected && msn.SignedIn)

{

// 登入成功

foreach (string mail in msnMail)

{

msn.SendTextMessage(mail, text.ToString());

}

// 等待訊息全部發完,但只等待一段時間。

DateTime now = DateTime.Now;

while (!msn.MessageQueueEmpty)

{

Application.DoEvents();

System.Threading.Thread.Sleep(500);

TimeSpan ts = DateTime.Now.Subtract(now);

if (ts.Minutes >= 3)

{

break;

}

}

msn.Disconnect();

}

else

{

string err = "MSN Messenger 登入失敗";

if (msn.ErrorCount > 0)

{

LogError(err + ": " + msn.LastError.Message);

}

else

{

LogError(err + "。" + msn.LastError.Message);

}

return;

}

}

catch (Exception ex)

{

LogError(ex.ToString());

}

}

}



按此連結下載完整的類別與範例原始碼

OOADA3:程式語言的編年史與排行榜

11/15/2008
《Object-Oriented Analysis and Design with Applications 3rd edition》的附錄 A 裡面有一張圖描繪了自 1960 年以來的部分程式語言編年史(圖 A-1)。這張圖有個蠻明顯的錯誤,就是所有的年代都標示為 1960。

中文版會修正這個錯誤,如下圖所示:



若讀者有興趣看看完整版的程式語言編年史,可以到 Éric Lévénez 的網站:http://www.levenez.com/lang/。

另外,原文書的表 A-1 是一份程式語言受歡迎程度的排行榜,其中第一名是 C 語言,Java 位居第二。此排行榜係取自 TIOBE 的 TCP-index,但從官方網站的長期趨勢圖可以看出,Java 從 2005 年擠下 C 語言奪得冠軍寶座之後,就一直獨占鰲頭。可見原文書的表 A-1 應該是 2005 年以前的排名結果。中文版會改用 2008 年 11 月份的 TCP-index 排名。

Position
Nov 2008
Position
Nov 2007
Delta in PositionProgramming LanguageRatings
Nov 2008
Delta
Nov 2007
Status
1 1 Java 20.299% -0.24% A
2 2 C 15.276% +1.31% A
3 4 C++ 10.357% +1.61% A
4 3 (Visual) Basic 9.270% -0.96% A
5 5 PHP 8.940% +0.25% A
6 7 Python 5.140% +0.91% A
7 8 C# 4.026% +0.11% A
8 11 Delphi 4.006% +1.55% A
9 6 Perl 3.876% -0.86% A
10 10 JavaScript 2.925% 0.00% A
11 9 Ruby 2.870% -0.21% A
12 12 D 1.442% -0.26% A
13 13 PL/SQL 0.939% -0.24% A
14 14 SAS 0.729% -0.40% A--
15 18 ABAP 0.570% -0.08% B
16 19 Pascal 0.511% -0.13% B
17 17 COBOL 0.510% -0.20% B
18 25 ActionScript 0.506% +0.04% B
19 23 Logo 0.489% -0.04% B
20 16 Lua 0.473% -0.27% B

Configuration Management:形態管理?

11/01/2008
Configuration Management 這個術語比較常見的譯法有「組態管理」和「建構管理」,另外還有「配置管理」、「形態管理」等等。

我在翻譯時採用「組態管理」,主要原因是:
  • Configuration management 跟我們一般講的軟體「建構」不完全一樣。的確,它是有包含軟體建構過程中的版本控制與發行作業,但這些並不等同於 configuration management。
  • 「建構管理」很容易聯想成 "construction management"。
  • Configuration 個人多譯為「組態」。
這裡無意比較各種譯法,只是......把 configuration management 譯為「形態管理」,並將 configuration 解釋為「形」(外觀)和「態」(功能),這會不會有點牽強呢?摘錄其解釋如下:

形態管理 (Configuration Management, 以下縮寫 CM ) = 產品 的 "形" 與 "態" 的 管理 !!
"形" = 物理特性 (Physical Characteristics) = 產品 的 外觀 (How the Product looks like)

"態" = 功能特性 (Functional Characteristics) = 產品 的 功能 (What the Product is suppose to do)

套用在軟體開發領域總覺得怪...

前 100 名最佳軟體工程書籍

9/16/2008

舊文打包:Java 網站應用程式入門實作

9/10/2008
有位網友來信詢問五年前寫的幾篇 Java Web 應用程式設計入門的文章:

1.0 前言
2.0 Servlet 程式設計初步(含 JDK 與 Tomcat 的安裝與環境設定)
3.0 JSP 程式設計初步
4.0 JSP、Servlet 與 JavaBean 的組合應用
5.0 JDBC 入門
6.0 Model-View-Controller 範例

我把以上文章全都包成一個壓縮檔,有需要的朋友可按此下載。解開後開啟 index..htm 即可。

不過,這些文章有點舊了,裡面有些東西或許有一些過時了,建議可以找一些新發表的文章或書籍。

讀蔣勳《孤獨六講》的一點聯想

8/02/2008
我的記性不好,平日工作的一些瑣事常過耳即忘,以致於常出槌、鬧笑話,不僅如此,就連小時候的童年記憶都非常少。每聽到有人回憶童年往事,不禁納悶,為什麼小時候的事情我都想不太起來?能記得的事情寥寥可數。照某些心理學的說法,可能我的童年大都是些不堪回首的痛苦回憶,所以大腦選擇忘記它們吧!

雖然能記得的童年往事不多,但有些記得的部分卻格外印象深刻,只要受到一些外在事物的刺激,那些記憶就會突然湧現。閱讀蔣勳的《孤獨六講》,便令我想起小時候祖父過世的情景。當時家裡長輩請了和尚來誦經,我們家三個小孩年紀都很小,對喪禮的規矩並不清楚,只知道依大人指示行禮、跪拜。我記得的其中一幕,是一些親戚長輩們對我們猛喊:「快哭!要哭!哭大聲點!」我跟祖父相處時間不多,不能說感情深厚,只覺得他是個慈祥又有點滑稽的老人,可是聽到那些大人的命令,我反而更哭不出來,只覺想笑。不知為何,別的記不牢,這件事情的印象卻特別深刻。

蔣先生在書裡面說:「如果你仔細觀察,便會發現在群體文化中,婚禮喪禮都是表演,與真實的情感無關。」

群體文化從小時候便不知不覺地影響著我們,逼迫每個人就範,必須待在大人畫的框框裡。長大以後,情況有改觀嗎?好像沒差多少。在生活周遭、職場上,壓抑個人言行的事情還是屢見不鮮。好比說,曾聽一位朋友提起,有一次他穿件 polo 衫去上班,衣服上面印有某家公司的標誌,主管見狀,便質問他為什麼要穿這種衣服來上班,好像在幫別家公司宣傳。

對比竹林七賢的嵇康,夏天穿著厚棉衣在柳樹下燒火打鐵,被指為違背社會禮俗,最後壓至刑場砍頭。這樣看來,古今皆然--特立獨行就是不對,跟別人不一樣就是不合群、該打。即使是現代,選擇展現自己的獨立意志、表達自己的立場,還是得面對不少衝突。更何況,穿著印有特定字樣的衣服,根本還稱不上特立獨行或標新立異哩。

生命的意義

偶爾還會想起一件事,就是小時候(讀小學的年紀)站在自家後門口,獨自望著後院的天空,憂慮:「如果我死了怎麼辦?我會去哪裡?我對這個世界發生的事都一無所知了,好恐怖。」我也不知道同年齡的小孩會不會也這樣想,但我到現在都還會有這些想法。阿佳小姐說:「你死了,世界還是繼續運轉啊,根本沒影響,你以為世界繞著你轉嗎?」我知道我不是世界的中心,只是那股莫名的恐懼感偶爾還是會浮上心頭。也許是自己對死亡、生命的意義不了解所產生的恐懼吧。

蔣先生認為,生命的意義或許就是在尋找意義的過程,「當你開始尋找時,那個狀態才是意義。」又說:「不管生命的意義為何,如果強迫把自己的意義加在別人身上,那是非常恐怖的事。我相信,意義一定要自己去尋找。」誠哉斯言!

想到另一位蔣先生--故總統蔣中正先生--說的話:「生命的意義在創造宇宙繼起之生命。」小時候老師並沒有解釋這句話是什麼意思,我們只是把它背熟用來考試而已,原來翻譯成白話,就是繁殖下一代。嗯,這也是一種看法,簡單明瞭,只是用詞太拐彎抹角,偉大不掉。
技術提供:Blogger.
回頂端⬆️