《黑天鵝效應》:Random walker 的預測無用論

11/30/2008
書名:黑天鵝效應(Tha Black Swan)
作者:納西姆.尼可拉斯.塔雷伯
翻譯:林茂昌
出版社:大塊文化
出版日期:2008-4-28

一言以蔽之:Random walker 的預測無用論。

這本書我是跳著看,感覺作者用很多文字談了很多東西,可是又好像只談了一點點。之所以跳著看,除了許多內容無法吸引我,多少也因為有點受不了作者的敘述方式--太冗長、談太多拉里拉雜的東西。有點像走一趟遠路,路上的風景似乎不怎麼美麗,但偶爾在路旁的草叢裡可以撿到一點有用的東西。

這裡不重複太多網路上已經有的書摘內容,僅寫點自己特別關注的部分就好。

氾濫、重複的資訊

「我注意到,幾乎所有人對當前事物都知之甚詳。各種報紙的內容嚴重重複,因此,你讀得越多,可以得到的資訊就越少。然而,每個人依然迫不及待地想要了解每一份剛出爐文件中的每一件事......大家成了誰見了誰、哪個政治人物對哪個政治人物說了哪些話的百科全書。然而,這一切都是徒勞無功。」 (p.42)

話雖如此,每天早上搭火車和捷運的上班途中,我還是會在車上瞄一下別人手上的報紙或雜誌什麼的。我自己是從沒拿過這些報紙,因為我不希望手上沾了油墨,而且,通常我手上都已經有一本書了。那些免費發送的報紙,我發現許多內容都挺煽情、八卦的(難怪叫做「爽報」?),有時我也禁不起好奇瞄個幾眼。

每天餵養社會大眾靈魂的,有多少是知識?資訊?抑或大多是垃圾?

學術研究的歪風-馬太效應

作者在前言中寫道:

「請注意,我這本書並不靠收集選擇性「佐證」這種惡劣的手法。根據我在第五章所說明的理由,我稱這種過度舉例行為為天真的經驗主義(naive empiricism)——挑選一連串合適的文章以拼湊成一個故事,並不能構成證據。任何尋求確認的人,將可以找到足夠的故事來欺騙自己——毫無疑問,還有欺騙他的同儕。」

第 14 章又提到 Robert Merton 提出的「馬太效應」(在社會學裡稱為「累積優勢」;cumulative advantage):

「如果有一個人寫了一篇學術論文,文章中引用了五十位從事相關主題研究者的文章,......另一個研究相同主題的研究者,會從這五十個人中,隨機抽取三人出來,以做為自己論文的參考文獻。Merton 證明,許多學者並未真正讀過他所列的參考文獻的原作;而是讀一篇論文,就從該文的資料出處抽一些出來,以作為自己的參考文獻。因此,研讀第二篇論文的第三個研究者,會從前一篇文章中抽出三名作者以作為自己的參考文獻。這三名作者會累積越來越多的聲譽,因為他們的名字已經和現有的這個主題緊密地結合在一起。勝出的這三人,和原始研究大軍的其他成員之間,其差異主要在於運氣:他們一開始就被選上並不是因為比較行,而只是因為他們的名字出現在先前文獻上的方式使然。......請注意,學者主要是由其作品被其他人引用了多少次來評量,於形成了相互引用的派系(就是『我引用你,你引用我』的這種把戲)。」 (p.317-318)

一針見血!點出了學術論文的「灌水文獻」以及「互推」現象。這跟推推王的推文功能還真是有異曲同工之妙啊。

謬論、誤導、過度簡化

作者在好幾個地方,用了好些篇幅、故事、專有名詞來討論一些邏輯思考上的錯誤,例如:
  • 「幾乎所有的恐怖份子都是回教徒」這個命題,是否就表示「幾乎所有的回教徒都是恐怖份子」?很明顯不是。但若有人提出第一種說法,聽者很可能會立即對回教徒產生刻板印象:他們很可能都是恐怖份子。同理:所有的白馬都是馬,你看到的馬一定就是白馬嗎?
  • 幼稚泛化(naive generalization)。躺在鐵軌上一夜沒死,可以宣稱臥軌是安全的嗎?
  • 過度因果化。這從報章雜誌,尤其是金融市場的評論最為常見,例如 2008-11-21 日有一篇美股盤後的評論,標題為「美股盤後─憂衰退期延長 道瓊大跌445點 S&P 500創11年半低點 」。隔天,同一家機構發出的美股盤後評論標題為「美股盤後─歐巴馬提名Geithner任財長 道瓊大幅收高494點」。反正不管股市漲還是跌,就是要分析個理由出來不可。就好像某一天台股大漲 500 點時,我們也不禁會問:「發生什麼事了?」是一樣的道理。這些媒體和評論員,正好給了社會大眾一個簡單的理由。所以......我們的心就終於可以安定下來了,因為我們不喜歡不確定、複雜;我們要簡單、確定的理由。
  • 沉默證據。故事:有人拿一塊畫板給無神論者看,上面畫了幾個信徒在禱告,並告訴他,這些人在一次船難中都倖存下來。隱含的意思是禱告可以保護你不被淹死。無神論者問到:「那些禱告而後來淹死的人,他們的畫像在哪裡?」哈,問得好!隱藏事實所產生的誤導,適足以令大眾迷信。
這些邏輯思考上的錯誤其實都有點類似,作者花了好多篇幅談這些東西(而且散在各處),看得有點累。要是可以再整理得精簡一些,讀起來應該會輕鬆許多。

預測與運氣

在「如何尋找鳥屎」這一章,作者舉了一個例子來說明很多發現、創新、與成功都是偶然的。他說,1965 年貝爾實驗室的兩名天文學家架了一具大型天線,這具天線接收時有些雜訊,而他們認為可能是天線碟盤上的鳥糞造成的,可是就算清了鳥糞結果還是一樣。過了一些時間,他們才發現那是微波幅射。

後來,貝爾實驗室總裁曾經盛讚發現此微波的天文學家為「文藝復興級的人物」。作者對此的評論是:

「文藝復興個頭。這兩個傢伙當時是在找鳥屎!......而且和大多數這類案例一樣,他們並沒有立即瞭解到這項發現的重要性。」 (p.251)

真敢說啊!難怪作者在前言中說「我冒著被攻擊的危險來表達我的主張」。他也認為微軟之所以在作業系統市場上打贏蘋果電腦,是因為運氣使然。這點個人並不贊同;我相信凡事多少要有點好運的幫忙,可是成敗全歸咎於運氣,這會不會也犯了過度簡化的毛病呢?

很明顯的,作者是一名 random walker,認為世界上一些重大事件其實都是隨機、無法預測的。他之前還曾寫過一本談隨機理論的投資書籍:《隨機的致富陷阱》(Fooled by Randomness)。

槓鈴策略(Barbell Strategy)

如果預測是沒用的,我們該怎麼辦?作者在第 13 章提出他的構想:

「如果你知道你會被預測錯誤所傷,而且,你接受大多數的『風險指標』--基於黑天鵝事件--都有瑕疵,那麼,你的策略就是盡可能的超保守和超積極,而不是溫和的積極或保守。」

這也是他在當交易員時所採用的策略。這個策略對股市投資人來說應該能有一些啟發吧,也許是:不要預測平時的小幅波動,耐心等待重大事件的發生,當機會來臨時,狠狠地大撈一票。

小結

不用放太多心力在常態分布(鐘形曲線)中最集中、比例占最大的瑣碎部分,而要注意那些極少發生的極端特例(事件)。但不用費心預測何時會發生那些重大事件(因為它們是隨機的),只要隨時準備好,抓住機會,因應事件的發生。剩下的,就交給運氣吧。

索引的翻譯

11/26/2008
在翻譯索引時,有一些自己慣用的譯法。本文只考慮頁頁對譯的情況。

英文索引是依字母的順序編排,而且通常是多層巢狀的結構。例如下圖是字母 I 開頭的索引範例:



這個範例最深有三層縮排,但只有第一層的第一個字母用大寫,其餘詞彙都是小寫。

準備工作

建立一份 Word 文件,先把英文索引全複製到這份文件裡。如此一來,往後我們只要直接翻譯這份文件就行了。

英文索引通常採 two-column 的編排方式,所以中文索引的文件可以先在第一頁插入一個兩行的表格,然後把第一頁英文索引的文字複製過來。接著調整字型大小和頁面邊界,讓中文索引的一頁正好可以放得下一頁英文索引。調整完畢之後,以後每一頁就可以直接複製第一頁的格式。

第一層的詞彙以英文為主,接著用括弧顯示中文

範例:

I
Inheritance(繼承)

第二層以上的詞彙則以中文為主,必要時加註英文

範例:

I
Inheritance(繼承)
  元素語意與~, 299
  的度量, 319
    多重
      類別之間的, 106–9

善用文字搜尋取代

索引通常有很多重複出現的詞彙,因此,為了加快翻譯速度,在每碰到一個詞彙時,若往後有可能重複出現,就直接用編輯器的文字取代功能一次處理完相同的詞彙。

注意:第一層的詞彙不要用這種方式置換,因為同一詞彙不可能重複出現在第一層,而第二層以後的中文表現方式又跟第一層不同。

以上所描述的,只是我自己在翻譯索引時的習慣和一點心得,其實都是些枝微末節的東西,記下來方便日後參考而已,倒也沒甚麼特別的地方。

物件導向技術的光環效應

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 位居第二。此排行榜係取自 TIOBETCP-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)

套用在軟體開發領域總覺得怪...
技術提供:Blogger.
回頂端⬆️