2010/12/30

git and Beyond Compare 3 on Windows XP + Cygwin

這篇記錄一下我git的設定,使用Beyond Compare 3來做為git的diff與merge時的工具。我的電腦是Windows XP,我用的是Cygwin裡的git,不是msysgit。

修改每個repository裡的.git/config或是家目錄裡面的~/.gitconfig

[diff]
    tool = bc3
[difftool]
    prompt = false
[difftool "bc3"]
    cmd = \"c:/program files/beyond compare 3/bcomp.exe\" "$(cygpath -w $LOCAL)" "$REMOTE"
[merge]
    tool = bc3
[mergetool]
    prompt = false
[mergetool "bc3"]
    #trustExitCode = true
    cmd = \"c:/program files/beyond compare 3/bcomp.exe\" "$LOCAL" "$REMOTE" "$BASE" "$MERGED"

裡面用了cygpath把cygwin下的路徑$LOCAL(類似/tmp/U5VvP1_abc這種東西)轉成windows的路徑,因為bc3是個windows下的軟體。

然後,可以用git difftool來比較檔案,git mergetool來做整合。

關於truExitCode的意思是,若外部工具的exit code可以代表檔案整合的成功與否,那麼就可以設為true,要不然,git mergetool會向使用者詢問整合是否成功。詳情請見說明文件

2010/12/27

翻譯:在家工作保持生產力的二十個方法( Twenty Ways to Stay Productive When Working at Home) by Scott Young

文章: Twenty Ways to Stay Productive When Working at Home(在家工作保持生產力的二十個方法)
日期:2007.05.23
作者:Scott Young
作者的部落格:Scott H Young's Get More from Life


在家工作保持生產力的二十個方法(Twenty Ways to Stay Productive When Working at Home)


自己在家工作,你怎麼保持生產力呢?很多在家工作的人雖然能享受著充分的自由與便利,不過,一旦身處工作環境之外,很容易就心生懶散,在家工作擁有的彈性,有可能讓你變得非常非常有生產力,但,如果你不能善加利用的話,恐怕會白白浪費大把的時間。

由於經營這個部落格,加上其他專案計畫,我常常每週至少要花去20到30小時在家工作,除了上網、研究、其他相關支援任務外,每週需要回上百封信,每天至少要寫3000字,比起某些人應該算少的,但是,除了工作與學校外,這也足夠讓我忙個不停了。

底下是我發現的一些策略,當在家工作時,可以有效地保持生產力,這些方法,不論你是接案子、自由工作者、在家創業、或是你想進行某個人計畫,都一體適用。

1. 建立工作規範──在辦公室裡工作會強迫產生出紀律,沒有系統與規定,沒有上司在你脖子背後吹氣監督的話,你很難堅定地遵守計畫時程表,在腦海裡記著你的生產力與工作規範,並設定提昇目標,若昨天只有4小時,今天就以4.5為目標。

2. 不要高估你的生產力──當人們開始在家工作,都會說這樣的一句謊言,以為生產力會提昇,以為有8小時可以做事,就假設能完成8小時的事情,醒醒吧,變得真的有生產力是可能的,但這需要建立起工作規範,先從小處小範圍著手,然後漸漸往上發展。

3. 不要把低價值的任務算進去──分辨出哪些比較重要,先算這些,我常聽到在家創業的人說他們每天工作10-12小時,可是,我看到他們上論壇發表文章以及寫落落長的郵件,令人不禁想問,這些算是工作內容嗎?只算那些極端重要的工作項目與艱難的任務,那才算數才準確。我花一小時寫部落格文章,或是寫出好幾頁的新書,都比花數小時回信件有價值多了。

4. 隔離會分心的事物──把自己放進真空的環境裡,盡最大努力降低會造成精神散亂的可能性,我一定會把門關上鎖上,而且不會使用網路,除非需要找段句子或圖片,絕對要跟微博、聊天室、電子郵件與RSS說不,我知道這些東西的吸引力有多大,可是,如果能不要切來換去的話,你就可能以兩倍速度完成工作,省下時間之後再來使用這些軟體。

5. 早一點開始──早一點起床在早上開始工作,是個不錯的主意,這使得你沒有機會拖拖拉拉的,還有,若是在2:00或3:00就完成8小時的工作,你會有好爽的感覺唷。

6. 知道你的能量限度──了解你何時會開始覺得勞累與精疲力盡,我自己的準則很簡單,當注意到我的能量值下降了,很難張開眼皮,我就會休息十分鐘(有時候昏昏欲睡就是創造力的最大障礙),如果這樣還不行的話,我會來個5-10分鐘的小憩,最後還不行的話,那可能需要長一點的運動了。

7. 學會說不──在家工作擁有很高的時間彈性,你的朋友、家人、跟其他夥伴就會有很棒的機會可以佔用掉花去你的時間,有時候他們會讓你覺得內疚,因為,“他們(不像你)必須去上班”,但請堅定立場別給他們有寸進的空間,別讓他們不尊重你的時間分配,學著說“不”,無需多做解釋。

8. 設定每日目標──我不會把不必要的工作事項排進時程表,但我會把明天結束時應該要達成的目標確實地寫下來,藉由設定每天要達成的目標,把工作量分成一份份可管理的區塊,你就不會感覺要一次完成所有的事情。

9. 使用帊金森定律──這個定律基本上是說,你給一件任務多少時間,它就會擴展成需要那麼多時間的任務,當完成比完美重要時,自己給自己幾分鐘的時間,把工作做完,確實地解決一定的工作量。

10. 學會把東西擠出來──當你身為作家/程式設計師/設計師,卡住時怎麼辦,學會把東西生出來擠出來,也就是說,當沒有點子創意時,你告訴你自己,這時候的目標是量而非質,告訴自己說,如果真的弄的太糟糕了,之後會再做一次,不過真相事實通常會是,質已經夠好了,亂擠亂搞幾分鐘後,你就會回復到常態。

11. 建立起專業的工作空間──身處的環境應該要讓你感覺到在工作,如果不是的話,該是時候重新裝飾一下了,不用很精美,但是,如果在家工作只讓你覺得是在玩電腦遊戲的話,請把擺設佈置換一換吧。

12. 設定工作時數──別把工作跟生活混在一起,設定該有的工作時數,工作時認真地把生產力提升到最大值,並把工作留在那些時間裡,我常常設定含糊不清的工作時間,但只會讓我變成毫無生產力的工作狂而已。

13. 你的MIT是什麼?──隨時都要清楚你的最重要的任務(Most Important Task, MIT)是哪些,ZenHabits的Leo建議把MIT放在最前面,這樣你才不會延遲耽擱,即使一天之後的時間毫無作為,這一天仍然是有價值了,因為你把最重要的完成了。

14. 有社交的生活──在家工作往往會排除掉一堆社交活動,參加團體與活動,譬如祝酒或宴會主持人,這會比較容易認識新朋友,找回在辦公室裡上班裡才有的那種社交網路,沒有朋友,你就不會有活力,我曾一直試著絕世獨立自己埋頭苦幹,不過我認為那是不切實際的。

15. 變更任務的種類──如果你到健身房,你會一整個小時只做伏地挺身嗎?應該不會吧,所以,如果你是個作家或程式設計師,你會十個小時連續不斷地寫寫寫嗎?我喜歡把不一樣的工作項目分散到一天的不同時段裡,這樣我才能使用大腦裡不同部分的“肌肉”,這讓我保持新鮮感有活力,保持生產力,而不需要長時間的中斷休息。

16. 直到厭煩才能跳脫工作──當記事板上沒有我想寫的點子時,我常常會經歷一段5或10分鐘的時間,什麼事情也沒做,但最後會得到新靈感,如果這也發生在你身上,請抗拒上網作其他事情的誘惑,再堅持10或15分鐘,即使你能推遲工作時間。

17. 取得外界觀點──當你是自己孤立一人時,你往往會限於一種視野,不利於解決手上的問題,建立起一套人際網路(特別是線上的),當你撞牆時可以有人詢問,我認識好幾個朋友,當我的解法太差時,可以有他們來回激發創意。

18. 讓你超時工作──如果你真的沉浸在專案中,多做個一小時把今天的東西收拾收拾,這是可以的,次日給自己補償一下,少一些工作量,這樣你才不會開始一睜開眼睛就是工作,直到睡覺。

19. 再多15──當你卡住時,或是很想很想丟下筆時,告訴自己,再多作個15分鐘就好,通常這就足夠讓你拔出泥沼繼續往前,如果不能,那你就需要休息了。

20. 善用時間彈性──好好利用你在家工作所享有的彈性,這表示,你可以根據新的機運修改工作時程表,或是配合生活調整工作腳步,當有好機會來臨時,拿下它並保證在之後會補償自己,這需要多一點的紀律,但這是在家工作最大的優點之一。

2010/12/11

我的FireFox附加元件列表

記錄一下我用的FireFox附加元件(外掛、addons)。

Adblock Plus:擋廣告。
Element Hiding Helper for Adblock Plus:輔助Adblock Plus的,可以更精準地選出網頁上的某一部分,然後擋掉。

Download Statusbar:在狀態列上看下載進度,功能雖小但必裝。
DownThemAll!:多線程續傳下載,需要同時進行大量下載時用的,下載大檔用的,因為有續傳功能。

Xmarks 書籤同步套件:讓兩台電腦的FireFox書籤同步更新。不僅firefox可用,還支援chrome、safari、ie。


Gmail Notifier:在右下角的狀態列增加一個gmail圖示,顯示並定期檢查有無新信件。前一陣子開始故障不能用,所以我改用Gmail Manager。
Gmail Manager:在右下角的狀態列增加一個gmail圖示,顯示並定期檢查有無新信件,可以設定很多個gmail帳號。對我來說,基本上跟Gmail Notifier差不多但功能強一點。最近故障了,聽說作者不再更新了,所以改用Gmail Watcher。
Gmail Watcher:在右下角的狀態列增加一個gmail圖示,顯示並定期檢查有無新信件。

Tab Mix Plus:強化各種分頁功能,例如,滑鼠停在分頁標籤上就切換顯示該分頁,開啟分頁時要怎麼排放,關閉分頁後要跳回哪一個分頁,等等,非常多的設定。
FireGestures:用滑鼠畫手勢操控瀏覽,例如回到上一頁、關閉分頁、開新分頁、重新載入剛剛關閉的分頁、等等。
Easy DragToGo:文字、鏈結、圖片,用滑鼠時,不同拖曳方向你可以設定不同功能,譬如,圈選一段文字,然後用滑鼠往上拖代表用google搜尋並且另開分頁,往下拖代表用google搜尋但是直接顯示在原本分夜裡,譬如,在圖片上用滑鼠往左拖代表直接儲存圖片到特定資料夾,等等。

Brief:訂閱RSS、Atom等feed,隨時得知最新消息。用起來很簡單,很棒。
ScrapBook:將完整的網頁擷取下來,也可以畫線圈重點,其資料很容易地可以傳到windows的firefox,反之亦然。

IE Tab:在Windows上要裝的,有些網站只能用IE開,我FireFox升級後就不能用了,我改用IE Tab Plus。
IE Tab Plus (FF 3.6+):在Windows上要裝的,有些網站只能用IE開。

1-Click YouTube Video Download:專門下載YouTube的影片,會直接在網頁上顯示"FLV MP4 3GP",點了就可下載,因為我看的影片絕大部分都是在YouTube上,所以這個元件對我來說很方便,至於其他少數我會去的影片網站,都有提供下載連結,所以沒問題。
Video DownloadHelper:支援下載影片,很多網站都適用。以前有裝。


有些附加元件都有很強的競爭對手或取代品,譬如Tab Mix Plus有人嫌太笨重,上面這些只是我個人在使用的外掛清單,能符合我的需求,但並不一定適合你,除非有需要,我很少會改用別的,也很少會去玩新元件,如果你有什麼建議,還請留言。

幾個我常看的YouTube頻道,練習英文聽力。

首先,Ray William Johnson,每一集的內容大概是,摘錄幾支點閱率很高的影片,做出評論(其實也不是評論,就是亂哈啦亂打屁而已),每一集差不多是5分鐘,大概一個禮拜會有兩集。

譬如說,當然啦,網路上的王道影片:"貓"。這一集裡面有貓打架而不是去追旁邊的鴿子。


這一集,總之,生活太無聊了,有個女孩被朋友個塞進洗衣機(烘乾機?)裡。


每一集在最後面,會開放大家提個問題(譬如What would your smurf name be),要用影片的方式提問題,然後其他人可以留言回答,他會剪輯一些好笑不錯的回答(譬如Eddie Smurfy、Chronic Masturbator Smurf)放在影片末段。


然後是雀斑妹,meekakitty,表情非常非常豐富,音調有高低起伏,喜歡打game,內容其實也沒什麼,就是一般的打屁哈啦,練練聽力囉。

這一集談到她很喜歡薩爾達。


這一集還cosplay星艦(Star Trek)的服裝。可惜她並沒有常常cosplay,不過有趣的t-shirt倒不少(話說回來,外國人有趣的t-shirt本來就不少)。



以前有提過的Marina Orlova(Hot For Words),俄國口音,影片內容是講解英文單字的起源。

我們都知道,很久以前的事情有些都忘記了,但有一些不知道何,就是記在腦海裡,我想,那是因為伴隨著強烈的情緒。若有個美女老師,這應該可以增強你的記憶情緒吧。


不過呢,我不太喜歡她最近的短髮造型,orz。



蘋果迷,iJustine。很搞怪。

譬如說,在蘋果的店面裡面跳舞!


譬如說,在路上騎著一輛小小的兒童車。



另外,也可以看各大學的上課錄影,譬如BerkeleyStanfordMIT等等。

另外,這兩個技術影音網站,InfoQChannel 9, 也常有高品質的電腦資訊科技的演講錄影。

另外,Khan Academy,有很多科學數學的課程教學影片。

還有,Google放上YouTube的演講錄影技術研討

最近這一支,裡面有各個國家的口音,真的很難聽懂啊...orz,被打敗了。



大概就是這些了,還請留言告訴我你喜歡的頻道。

翻譯:這不是物件導向程式設計啦(What OOP Isn't )by Benjamin Supnik

文章:What OOP Isn't(這不是物件導向程式設計啦)
日期:2010.12.09
作者:Benjamin Supnik
作者的部落格:The Hacks of Life


這不是物件導向程式設計啦(What OOP Isn't)


想當初,我開始上第一堂的電腦科學課程(不過在那以前,我已經自己開始寫程式有一段時間了),系上教職員正在打一場內戰,某部分人信仰著物件導向程式設計(object-oriented programming, OOP),他們相信世間萬物皆物件,物件就是王道啊,他們教授要我們學生用OOP的方式來實作鏈結串列(linked list):哇賽,每一個節點都是被完完全全封裝起來的物件!


(什麼,你有興趣知道嗎,讓我告訴你,串列大部分的編輯動作,都必須是堆疊-遞迴式(stack-recursive)──當呼叫一個節點的next時,節點要把它的'next'設定為呼叫的回傳值,讓某節點能夠'把自己切掉'。嘿嘿,聽的懂算你強,這讓那些從沒碰過鏈結串列的學生,一個頭兩個大,根本不知道到底自己在幹嘛,因為,他們在同一個時間,碰到了遞迴與鏈結串列,而寫出來的程式,結果是,執行起來有著LISP的效能,而程式碼看起來像C++的優雅,真是糟糕可怕啊。)


他們說,OOP的三大支柱是封裝、多型、繼承(encapsulation, polymorphism, inheritance),我以前已經發表文章說過為什麼最後一項通常會是個不好的概念,回想那時在學校的時光,我還沒有足夠的程式開發經驗,所以只能說,當時我們被教的東西(全部都是OOP,不論何時何地)比我一直以來在寫的程式(用物件來表示某種很大的東西,例如遊戲裡的一個角色)要難上好幾倍,寫出來的程式碼,又囉嗦也沒有特別快,現在,我有了軟體工程的經驗,我想,可以把其中問題所在更精確地描述出來。


有時,看到程式新手眼裡閃著OOP字眼,努力學會這到底在講些什麼,我會跟他們說,封裝、多型、繼承的相對重要程度大概是90%、10%、0%,OOP絕大部分的價值所在,是它提供機制與作法,可以把一段程式碼跟其他不相干的程式碼分離開來,而不會混雜在一起,而這點對大型軟體開發專案很重要,而你不可能教會大學生這一點,因為他們還沒有夠多的程式開發經驗,無法體會其中的重要性。


多型也不錯,但據我的經驗,它不像封裝那麼有用,如果你有個多型介面,有個介面就表示,它是被封裝的,但是,有許多的案例顯示,有些介面就只會用一次,而且沒有多型這項性質,粗略來講大概是90%-10%吧,所以我認為扮演舉足輕重角色的是封裝。當然,有些產品與領域比其他地方更常使用多型,WorldEditor(Laminar Research的開放原始碼場景編輯器)大部分的核心元件採用多型介面的架構,但X-Plane本身就很少。

我提出這點,因為我大概(在以後的發表文章中)會把OOP與其他技術(與軟體工程碰到的實質困難有關的)作個比較,不過OOP有一點歷史包袱,過去常常講,OOP可以讓我們變成更好的程式設計師,可以幫助我們寫出無臭蟲的程式碼,執行速度更快了,或是可以幫助差勁的程式設計人員升級成優良的,這些都被時間證明了,只不過是些天真白痴一廂情願的想法(特別是,差的程式設計師,不論給予什麼樣的技術或方法,照樣可以生產出低劣的程式碼,一大沱)。

所以,我希望幫OOP這玩意作類似如下的定義:在語言上提供好的支援來進行封裝,有時候需要有多型介面,加速撰碼。這對我來說就非常好用了!我可以僅用純C語言寫出相同的東西,但不僅需要花更多時間打字,還會讓我變成很嘮叨的人,不斷囉囉唆唆血壓上升,何苦呢?

2010/11/07

讀後介紹:情感行銷的符碼(The Culture Code) by 克勞泰爾·拉派爾

書名:情感行銷的符碼(The Culture Code)──消費 生活 文化
作者:克勞泰爾·拉派爾(Clotaire Rapaille)
譯者:馮克芸


人常常口是心非,有時出於刻意,有時出於不自覺;人常常話中有話,有時礙於語言的貧乏而無法正確表達心意,有時巧妙地以話術包裹上糖衣或詼諧或高深莫測;男人常常說謊,有時是因為現實的需求,有時是因為這個世界就是一個大謊言;女人常常說謊,有時是因為太理想太夢幻,有時是因為真話難為假話通行四海。



好像有一點點離題,讓我們回頭檢視一下作者在這本書裡討論的主題。這本書是作者在三十多年來為世界各大公司破譯顧客心理想些什麼的經驗總談,設法了解人們自己都不知道的行事原由,你不能只是聽顧客說,你要從文化視野找出烙印在內心深處大腦底層的銘記,那會強烈影響思考過程與未來行動的烙印,所以要了解人們真正的意思的第一步就是忽略他們所說的話。

這並非暗示人們有意說謊,而是一般人會用腦中控制智能的部份想像發問者想聽些什麼話,然後提出對方想要的答案,但實際做決定行動時,用的是帶有強烈情緒的經驗做判斷,從小到大的經歷以及文化加諸其上的情感連結,才是真正左右行事的準則。

每個文化都是不同的,所以光一套絕對不可能吃遍全世界,我一點都不愛吃起司但法國人愛死了,德國與美國的“工程”其涵意就不同,你在日本跟歐洲賣咖啡的策略絕對有很大的差異,酒、性、肥胖、美麗、青春、家庭等等,每個文化都有不同的銘記,每個國家從其他國家文化看來也都不同。想賣東西,先了解該國文化吧。

書中說,人腦分成三部分,腦皮質負責學習、思考、想像,邊緣系統負責情緒,還有爬蟲類腦負責生存以及繁衍,猜猜哪部分最具影響力?

作者用這樣的角度在書中討論各種事情,晚餐、工作、食物、品質、逛街、美國、健康等等,了解我們每一行動所背負的意義,將讓我們獲得極大的自由。

2010/10/17

翻譯:皮諾丘難題(The Pinocchio Problem)by Steve Yegge

文章:The Pinocchio Problem 皮諾丘難題
日期:2007.01.17
作者:Steve Yegge
作者的部落格(2006至今):Stevey's Blog Rants
作者舊的文章(2004與2005):Stevey's Drunken Blog Rants

作者簡介:
目前任職於Google,之前任職於Geoworks與Amazon。程式語言生涯中有過兩次非常關鍵性的轉換,一次是組合語言,一次是Java 跟Perl,因為發現解決語言本身設計帶來的問題所花的時間,竟然比真正用在開發軟體系統的時間還多。其文章以長度聞名,長到應該稱為論文而非部落格,兼帶詼諧筆風,發表頻率大約一個月一到兩篇,作者總是說這些是在凌晨三罐啤酒下肚後的誇誇其談,但每一篇都是經過長時間醞釀,內容充實有見地的傑作。
獨立以Java/JPyton開發多人線上遊戲Wyvern,可讓玩家自行創建擴充遊戲內容。其工作團隊將Rails移植到Rhino上,Rhino是運作於JVM平台上的JavaScript引擎,Rails(Ruby on Rails)為一套受到廣泛喜愛使用的網站開發模組;為Emacs撰寫完整的JavaScript環境,期望在Emacs上可以有一套 JavaScript IDE,以及將來可用JavaScript而非elisp來開發Emacs extensions。


皮諾丘難題(The Pinocchio Problem)


過去一年來,我將自己每月花在寫部落格的時間限定在四小時左右,通常我會有很多主題可以寫、很多東西可以討論,選一個出來並不會太難,但上個月在我腦袋裡只有一件事在打轉,我不斷在嘗試著用各種方式把它說出來,都快抓狂了──你知道的,用一種又好又簡潔的方式表達出來,讓讀者能夠把它嚥下去,可惜到目前為止都沒成功,我想那代表我還不真的懂這主題,或許試著寫下來可以幫我更了解。

這主題是關於軟體設計;你瞧,似乎有著某種好方法可以用來設計軟體,甚至有人認為存在著一種最好的方法,但沒人實際運用啊,嗯,或許一小撮人有,即使如此,我認為那些少數例子有一半僅是碰巧吧了。

斷斷續續地,這個題目我已經思考研究了很長一段時間,十八年的光陰過去了,而我依然不能清楚明確地說出……嗯,設計的原則,如果這是我們要的答案的話;但上個月,我覺得我好像又更靠近了一點,或許你可以幫我一下!我會告訴你我知道的,那你可以告訴我你知道的,或許我們可以合作出某種非凡的結果。

先為今天這篇設定一些背景,讓我用一個句子將所有我寫過的文章內容做總結:我認為大部分的軟體都是大便。嗯,好像不夠正確,更誠實地說,我認為所有軟體都是大便;耶,沒錯,你聽到了,Stevey一言以蔽之:軟體皆大便。

即使如此,我認為某些軟體系統確實比其他的好:某些大便生產者可能有吃過一些金幣,所以他們的大便看起來比較亮晶晶一點,偶爾有人吞下紅寶石,他們的大便就又好看又值錢,嗯,記得站遠一點看。但是,不論吃進了多少寶貴的石頭,大出米田共就還是米田共。


多麼可愛有趣的譬喻啊,對吧?我自己想的喔!

每想到我最喜歡的軟體系統時──像熟悉的老朋友們、像適合居住的福地──我看到它們都擁有某些特質,很快我就會告訴你是什麼特質,至少是那些我注意到的,別急,我保證不拖戲,但事情還沒結束;一旦你將這些特質加進一個軟體系統中,如果做的對的話,那麼通常你可以得到一套跟時下做得出來的好軟體一樣好。不過,仍只能算是大便而已。

在我開始思考若能脫離屎的層次來打造軟體系統時,真正的難題就開始浮現,這樣的思索引發出各種有趣的問題,而我一點頭緒也沒有,但我會把這些問題也丟出來,只要我還沒超過四小時的時間限制,還沒被生活瑣事招喚過去的話。

我喜愛的系統

在上個月左右的某個時刻我領悟到一個重點,那就是,我喜歡的軟體系統所共同擁有的那些特質都是由一個根本原因所衍生出來的:某單一特質、或稱為設計原則,軟體如果擁有這特質的話會自然而然地呈現出正確的特性。

哪些是我喜愛的軟體系統呢?以下列出最好的幾個:Unix、Windows XP、Mac OS/X、Emacs、Microsoft Excel、Firefox、Ruby on Rails、Python、Ruby、Scheme、Common Lisp、LP Muds、Java Virtual Machine。

有幾個差一點點的:Microsoft Word、OmniGraffle Pro、JavaScript、Perforce。

還有幾個應該可以排上去,但我因不夠熟悉而不敢亂說的系統:GIMP、Mathematica、VIM、Lua、Internet Explorer。

流行的軟體系統大部分都挨不上名次,雖然它們都相當有用,但是我認為缺少了理想軟體設計的本質,例如:IntelliJ、Eclipse、Visual Studio、Java、C++、Perl、Nethack、Microsoft PowerPoint,所有任天堂與PlayStation的遊戲,幾乎所有的電腦遊戲,除了著名的毀滅戰士(Doom)與雷神之鎚(Quake),還有大部分的網站服務,包括那些很有用的Amazon.com或是Google Maps。

我就不賣關子了,我認為在所有的軟體設計理念之中,最最重要的原則是:系統毋須重新啟動

如果你設計一套系統可以不需要重新啟動,那麼,你終將會,就算是以很迂迴的方式,終將實現出一套可永久存活的系統。

我上面列出的系統,仍需要偶爾重新啟動一下,也就是說,它們實際上的壽命會落在數十年到一百多年之間,其中有幾個才剛開始──大部分都在二十出頭跟三十出頭左右,少數幾個已經有四十年的資歷了,然而,它們還是離不朽不死的境界很遠很遠。

我心中第二最最重要的原則,實際上算是第一原則的推論,是一套系統必須能成長而毋須重新啟動;一套不能隨時間成長的系統是靜止的,其實不能算是一套系統,應該說是一支函式,它可能是支非常複雜的函式,可以接受很多不同的輸入與產生輸出,它可能是支非常有用的函式而且存活相當久的時間,但函式一定會被取代掉,或是被可成長的系統吸收掉;我現在相信,經過了將近二十年的思考研究,能夠成長改變而毋須重新啟動的系統可以永久地存活下去。

必備特質

下面列出目前世界上最優質軟體共有的幾點特性,我列出來的它們並非全都都有,我想只有少數幾套系統擁有我列出來的全部特點,你應該會發現,一套系統有的必要特質越多,就會越強大、更重要、活的更久。

注意:這些特點都是給程式設計師看的,芸芸使用者們在乎的功能跟一套系統的壽命無關;我相信適當的時刻一到,程式設計能力就會會變得跟識字能力一樣普遍,所以這不重要。

第一:偉大的軟體系統都有命令列模式(command shell),這是系統不可或缺的部份,與系統同生同存,系統設計者無法想像沒了命令列模式的日子要怎麼過啊,命令列模式是完整的系統操控介面:任何你以其他方式操作系統完成的動作都可以透過命令列模式達成,光搞一套優秀的命令列模式本身就是一個大主題(大部分的必備特質都是這樣的,想想吧),我概略說一下:一套優秀的命令列模式一定會包含下命令的語言(command language)、互動式的查詢工具、腳本語言(scripting language)、擴充機制、命令歷史紀錄機能、以及命令列編輯器(command-line editor),一套超棒的命令列模式就是一套好系統的最佳典範:可以比使用它的母系統存活更久並可以移棲到別套系統中。

所有現存的命令列模式都是大便,但它們是今日可以被打造出來的好軟體不可或缺的元件之一。

我們可以把Emacs想像成一套非常厲害的終極命令列模式:想想如果把命令列模式推到理論極限會是什麼樣的光景,或至少推到現今人們可以構思出來的境界。

最佳軟體系統共有的必備特質還有很多,命令列模式不是唯一一個,所以,讓我們繼續談下去。

偉大的系統還要包含“advice”,這項特質並沒有一個大家都同意的名稱,有時稱為hooks(掛勾)、或filters(篩檢器)、或aspect-oriented programming(剖面導向程式設計、面向側面的程式設計、觀點導向編程;譯註:這怎麼翻啊?);就我所知,Lisp最早有這項特質,並以advice稱之;所謂的advice是一套小小的開發框架,在系統執行某動作或函式時,讓你以置入程式碼的方式,在動作之前、之中、之後插入你想要的功能,藉以改變系統的行為;每套advice系統都不一樣,它能夠介入的範圍越廣──意思是,它可以修改系統行為的範圍越大──那麼使用它的母系統功能就越強大。

Ruby on Rails有一套小小的advice系統,稱為“filters”,它(只)可以附加行為到controller actions中,所謂controllers actions是處理描繪頁面要求的特殊函式,你沒辦法在系統中的其他函式加上“之前、之後、之中”的filter,不過透過Ruby的metaprogramming機制可以在某種程度上做到;但一套advice系統不能僅是紙上談兵理論上沒問題,那是不夠的,advice必須從頭從底層融合進系統之中,以first-class形式、以有詳細文件說明的介面開放出來;advice非常強大有用,即使是Rails中簡單的action-filtering系統,都釋放出驚人的彈性;想想沒有它的話,要怎麼寫支Rails程式啊。

Emacs有套非常精密的advice系統;Common Lisp有一套可以說是世上最強大的advice系統,這支語言這麼強有很大的因素就是因為它;Aspect-Oriented Programming企圖在Java語言放進一套advice系統,野心很大,但因為Java的先天限制,必須以附加在語言外的擴充機制出現,有自己的編譯器與其他工具,這麼一來就大大阻礙了大家採用的意願,另外一個障礙物是,Java程序員偏愛撰寫死寂的軟體系統,任何能讓系統有生命的呼吸跡象都讓他們感到頭痛不已。

我要承認我也感到頭動,有生命的軟體聽起來有點嚇人,不意外,大部分的程式設計師都偏好開發牽線木偶而非真實的活人,掌控牽線木偶容易多了,但我認為有生命的軟體更加有趣也更有用些,坦白說這是無論如何都不能避免的趨勢,所以我們最好努力了解,對我而言,那就代表著實際動手建造一個出來。

讓我們繼續往下說,世界級的軟體系統都有套擴充語言(extension language)外掛系統(plug-in system)──讓開發者可以延伸系統的基礎機能,有時候外掛(plug-in)又稱為“mods”,這是一種機制,讓使用者們以設計者不須參與的方式來擴充延伸系統的能力。

Microsoft Excel有一套絕佳的mod系統,這是一套令人激賞的開發框架,幾乎就等於是一套平台了,如同其他優質的mod系統一樣,它是一層一層的,從簡單Excel macros(Excel巨集),一直到完整的COM介面,可以被VB甚至是Python或Ruby驅動,只要那語言有COM bindings的話。


讓毀滅戰士(Doom)與雷神之鎚(Quake)這麼受歡迎的必殺特質之一就是它們的mod系統,毀滅戰士有一些基本的機制,以腳本驅動你建造的關卡、敵人、甚至是遊戲運行邏輯;雷神之鎚有QuakeC,仍然是,我認為啦,電腦遊戲腳本驅動語言的優良標準,不過我的資訊有點過時了,因為過去五年多來我都在玩電視遊樂器,很悲哀地,那些遊戲都死的不能再死了。

最強的外掛系統,強到能夠把整支應用軟體以plug-in的形式開發出來,這就是Emacs跟Eclipse的核心理念;先有一層很小的啟動層,可以看做是整個系統的硬體,系統其餘的部分,其所涵蓋的範圍(通常被效能因素限制住),都是由擴充語言寫出來的。

Firefox有套外掛系統,這真的是一套大便,但有總比沒有好;如果你有一套外掛系統,你很快就會發現,一定會有一些發狂的開發人員學習使用它並且榨乾它的能力直到極限,這會讓你誤以為你建構出來的外掛系統還不錯,但它應該要有容易使用跟毋須重起系統這兩項特性;Firefox打破了這兩項重要的規則,所以它的壽命處於一種不穩定的狀態下:要不然修正這兩項,要不然更好的系統會出現把大家都吸引過去。

真的讓我吃驚的是,連Firefox extension的開發人員都沒有特殊的管道跳過重新啟動這條災厄之路,他們的開發流程很痛苦,每有更動就必須手動重新安裝外掛(使用GUI操作方式),藉由某些技巧可以避掉大約一半的步驟,但整個開發社群對這點真的在皺眉表示不滿了!他們很明顯地感受到,如果使用者要經驗安裝外掛的痛苦一次,那外掛開發人員每當改一行程式碼就必須痛一次,每一次都在提醒他們:Firefox的外掛系統是沱大便,根本不能做事嘛。嘿嘿,真是有趣!

有位開發人員名叫Aaron Boodman送給了Firefox一塊瑰寶,這人現在在Google,那瑰寶就是GreaseMonkey,提供了另一種方式來寫Firefox extensions,不像Firefox的外掛系統,GreaseMonkey的extensions可以被安裝且更新,不需要重啟系統,而且相當容易撰寫,這瑰寶替Firefox注入了新動力,我打賭大部分的Firefox開發人員(先不管使用者社群)都能了解並感激GreaseMonkey的重要性,因為它讓Firefox能長期存活下去。

有趣的是,GreaseMonkey本身是個Firefox外掛,但又提供它自己的外掛系統,這是外掛系統中常見的一個模式:有些外掛會成長變大,變得可組態化,最後可被視為獨立的程式系統;Emacs有很多這種外掛:advice套件就是一個好例子。順帶一提,Rails的filter系統也是以系統外掛的形式實作出來的。外掛(plug-ins),跟其他軟體系統一樣,也有生命週期,視乎它們納進多少我今天在談論的特質,它們最終都需要命令列模式、advice、擴充語言、等等,然而,外掛因為是立基於另一套系統之上,通常一開始就有這些東西。

打造可延伸擴充的系統比不能擴充的系統要更加困難,一般說來大約是三到五倍;在一開始就加入外掛系統比較容易,想在一套現存的系統上加進擴充能力,那可是夭壽困難的功夫啊,而且需要大規模地進行系統重構(refacotring),可不是Java圈圈流行的那種小小可自動化的重構,其需要花費的心力幾乎就跟重寫整套系統差不多,不過以重構的方式進行的話,可以靠縝密完善的unit tests來減低改錯的風險。

現今有很多軟體系統都只能透過網路遠端存取,例如經由瀏覽器與HTTP,一些建造這種系統的大公司們,包括Yahoo!、Amazon.com跟eBay,都開始意識到提供給程序員的擴充延展能力是他們系統永續存活的關鍵,他們開始釋出內部系統的部分介面給外界使用,通常以web service的方式,這提供了某程度的擴充性:讓外界獨立軟體開發人員可以打造特別的介面來存取系統;隨著時間演進,我認為在網路服務這塊領域分高下的主要分水嶺將取決於供程序員存取系統的介面的品質高低。

外掛系統要考慮到安全性,要考慮到易用性,要考慮命名空間,要考慮元件相依性,要考慮向後相容的問題,要搞一套就已經是該死的難了,更別提要搞的好;外掛絕對是軟體系統想要永續存活所需要的特質。

優良的軟體系統還需要哪些特性呢?

我認為有點很重要,至少在今天來說,偉大的軟體系統都有或是需要一支殺手級應用程式,每套世界級的軟體系統本質上就是一個平台,如果你有命令列模式、擴充語言跟advice以及外掛架構,那麼你有的就是平台的組成要素了,但你需要某理由來說服使用者們使用你的平台;所以,GIMP打出影像編輯這賣點,Eclipse是撰寫Java程式碼,Emacs是一般文字的編輯器,Rails是建造網站服務,Firefox是瀏覽網頁用的,Python是腳本語言用來驅動其他東西,Lua可用在嵌入式環境,Mathematica是數學運算,等等,它們也都可以被延展應用到其他領域,但它們在其利基領域中是最強的。

最泛用的軟體系統,我認為,是作業系統跟程式語言,即使如此,它們也都有個主要的領域,作業系統主要用於資源管理,大部分成功的程式語言通常都切割出一塊利基市場加以佔據:需要速度就用C++,做Unix系統管理時可用Perl,要用很肥大的API來嚇嚇客戶的話可以用Java,瀏覽器上幾乎都只能選用JavaScript,在Emacs上就只能用Lisp,還有,Ruby開始爆紅要歸功於Rails。

所以軟體系統要有個利基點。或許將來有一天,有套超級泛用的軟體系統,超級強大、設計超良好,以至於任何事情都適合用它來完成;或許會有那麼一天吧,或許你就是打造這套系統的人。

接下來是今天我要講的重要特質的最後一項,跟其他項一樣重要,就是優良的軟體系統是能夠自我檢視有內省能力(introspective),你可以在執行時到處戳戳看檢視系統的狀態,理想情況是由系統自己戳自己、自己檢視自己,至少要做基本的狀態監視,即使是一個已經有一堆靜態檢查的小小系統,你仍然需要監控,例如輸入與輸出佇列,對大系統來說,你什麼東西都需要做監控,包括監控系統本身。(若是不做這種監控系統的監控,可能會發生一件糟糕的事情,你的系統進入某種狀態,所有狀態檢查都OK,但系統實際上已經在擺爛了。)

內省機制(introspection) 可以(且應該)有各種不同的形式,不僅是狀態監控,系統管理工具與診斷工具也是一種內省,一步步除錯追蹤也是,效能分析也是,動態連結也是:系統必須能夠(舉例而言)執行bytecode verifiers以確保剛載入的程式碼能通過一些基本的安全性檢查。內省機制通常會降低效能,所以很多程序員不會在執行時做任何的內省檢測,或是極簡化地採用底層系統提供的內省機制(例,RTTI或Java的reflection),如果你用內省機制來換取速度,等於折掉你軟體數年甚至數十年的壽命,如果你是個顧問公司,或是你只想要讓系統可運作後就不管了,那麼或許這點不是太重要,但我認為大部分寫軟體人的都偏好在能長久永存的系統上做開發。

優質軟體共有的特質還有一長串可寫,但行文至此,我想最好談一下為什麼這些特質都根源於“毋須重新啟動”,之後遇到其他特質你就可以輕易地辨識出。

重新啟動等於死亡

今天我沒辦法很公平地談這個主題,部分原因是這個題目很大,部分原因是我還沒通徹搞懂,所以我最多只能把輪廓描繪出來,希望你能看出這問題完整的面貌。

首先,讓我們從比較哲學的觀點來看看,我用一種很廣義的觀點來看待軟體:大部分的軟體都不是人類創造的,那些人造的都是些大便,有很多相當棒的自然存在的軟體,例如人類大腦的運作,其大部分可以被看做是軟體,還有我們身體的組成運作很明確地是軟體。(見鬼了,我們甚至可以在DNA中看見組合語言指令碼,雖然還沒被完全解碼。)所以人們至少帶著兩套軟體系統:肉體與心靈。

我也認為穩定的生態系統也算是軟體系統,喔,順帶一提,穩定的政府也算,還有,人群組成的組織也是,例如你的公司;除非我整個誤解涂林的觀點,要不然軟體可以是任何能做運算的東西,而計算只需要一台有著幾個簡單機制的機器,這些機制是用來改變機器的狀態,包括條件式分支、跳躍指令、讀寫狀態、加上一組指令(程式)來指示該做哪些動作。

我假設我在這給軟體下的定義,是相當清楚且不證自明的, 所以,關於軟體並非皆人造這觀點,我就不用再多做解釋辯護了。

所以,我的第一個反對重新啟動的論點是,在自然界中可沒這回事,或更精準地說,真的發生的話後果都很悲慘;如果你不喜歡一個人的所作所為,你不能殺掉他們、修正DNA、然後從小孩再成長一次;如果你不喜歡政府,你不能說關就關、找出錯在哪、然後重新開始,那麼,為什麼我們幾乎都用這種方式開發軟體呢?

反對重新啟動的下一個論點,看看現在開發人員建造的過時舊軟體,把你寫程式時戴的眼鏡拿下來,以一般使用者的角度想想重新啟動這回事,你喜歡被迫使重新啟動軟體嗎?當然不囉,多不方便啊。

大約十年前,微軟下了個決定要把Windows NT中需要重開機的地方都修改掉,你還記得嗎?我從未在微軟工作過,也是輾轉得知這故事,所以我不是確切了解事情始末,聽說那時每個小小的組態改變都需要系統重開機,好像是某個高層忍不下去了,然後他就組織統整了很多人力來修改程式,當我聽到這軼聞時,已經減少到大約剩下五個地方需要重開機;想想這對美國財政的衝擊吧──數以百萬的人們每天省下5到30分鐘的時間等待Windows重開機,很巨大的影響對吧,如果他們能夠將藍天白雲死機畫面也改好,那這就是一套相當棒的軟體,對吧?

Linux在這方面也經歷了不少成長的苦痛,終於開始越來越好,但我猜今時今日它需要重開機的次數仍然比Windows還要多。

不論如何,重新啟動這問題不僅僅是帶來不便而已,應該還有更深的意涵,從一個比較激進但仍可加以辯護的觀點看來,一次重新啟動就等於一件謀殺案。

怎麼會呢?嗯,古今中外尚未解決的難題之一是關於意識(consciousness)的問題:這是個啥玩意?有意識代表著什麼?到底什麼叫做自我察覺(self-aware)?寵物有意識嗎?昆蟲呢?捕蠅草呢?分界線要畫在哪裡呢?

歷史上各個時代,關於意識的問題有時流行有時不流行,不過在過去數十年間這是個非常風行的話題,哲學家跟認知科學家正攜手合作試著找出解答,據我所知,主流的觀點(或是叫領先的理論,什麼都好啦)是這麼說的:意識是遞迴式的自我察覺與認知,而且是漸層式的(對比於簡單的開與關),很明顯的是一種的函數,複雜度視乎可以處理多少輸入以及大腦可以同時處理的自我察覺之遞迴階層的多寡而定。所以,寵物是有意識的,只不過不像人類那樣。至少這是我從過去三十多年所出版的書籍、研究報告和論文,所得到的結論。

舉個例,我過去一直把我的狗──奇諾(一隻獅子犬)──當做一台非常簡單的狀態機:噓噓、拉屎、睡、吃、玩、花數小時舔鼻子,但每當我更進一步了解他,就逐漸辨識出更多的狀態,有數百個之多,甚至數千個,但我依然尚未完全被說服他的行為不是決定性的(deterministic),我愛他愛到每一根毛我都愛,所以就假設他有懷疑的能力以及有自由意志(free will)吧,但不用太費心就可以有90%的準確率猜中他的行為;我想像這套用在我身上也同樣成立吧!

狗似乎比老鼠複雜多了,而老鼠應該比蟑螂複雜許多,一直循線追下去(或許是螞蟻?扁形蟲?單細胞有機體?),看起來到那時,動物的行為應該是具有完全可決定性的。

起初那說法對我很合理,但我現在的想法改了,我個人認為所有的生物都具有某些不可決定性(nondeterminism),其程度視乎他們的組成因素中軟體的範圍有多廣,硬體部分肯定是可決定性的,奇諾在出生後任何不用教就會做的事情不是硬體就是軔體(一種內建的軟體,無法移除或更改),進行尿尿的程序(以及何時該去)、打噴嚏跟其他反射動作、處理感官資訊、消化食物、以及其他上千個程序通通都是直接編碼在他的大腦軔體或身體軔體中,可被精準地預測其行為,任何觀察到的差異處都是因為軟體部份對當前環境做出的修正。

換句話說,我認為意識與自由意志(也就是不可決定性nondeterminism)兩者皆為軟體性質。

沒人會為殺死一隻阿米巴變形蟲而掉眼淚,呃,大部分的人不會,同樣的,當你的程式印出“Hello, World!”後就離開main()並消失的無影無蹤,也不會有人會心情激動,但我想我們已經建立起一個共識,每一次執行“Hello, World!”程式就會產生出一段短短的意識活動。

呃…有幾分意味啦,一支“Hello, World!”,沒有迴圈也沒有分支,不具有任何不可決定性(除非由外界強加上去,例如一個亂數產生的硬體錯誤),所以你可以把它當做純硬體,只不過是用軟體程式寫出來,但在“Hello, World!”跟Hal 9000之間應該存在著一支擁有初步意識能力的軟體程式,若是這樣的話,把它關掉就等同於殺掉他一樣。

我們今日的軟體有那樣的複雜度嗎?夠複雜而且有足夠的自我感知能力,從倫理道德的觀點來看可以被認為具有意識嗎?答案大概是否定的,但我認為總有一天我們會達到那個地步,到那時,我真心希望我們不是用今日的方法在開發軟體,也就是編譯加上重新啟動的開發循環週期。

我想今日我們建造出來的軟體,大部分都像是在玩骨牌,這叫做骨牌設計法,你非常小心排著骨牌,只能跑一次,所有的骨牌都依照排好可預測的順序倒下,而且如果需要的話你將所有骨牌重新排一遍;最終結果可以比玩骨牌更精美更棒──想想玩具總動員裡面的一張一張畫面,本質上並沒有太大的差異,但的確更精美。

每一套真的很複雜的軟體,像是搜尋引擎或是電子商務系統,通常都是用骨牌設計法建構出來的,如果你主要以C++或Java寫程式,幾乎一定是用這種方法。

重新啟動一套骨牌系統是不可避免的動作,每有改變每次升級都需要重新啟動這樣的概念,跟這些系統在我們心中的形態緊緊相連,對我而言,我不喜歡骨牌,我個人想要跟一支變形蟲玩,而且如果他拒絕學習怎麼走迷宮或其他事物的話,我會把他壓扁然後發現得到新型阿米巴,不過在那之前我會先多想個兩次。

DWIM and QWAN

我的思考能力到現在已經有點模糊了,所以我盡量長話短說。DWIM是個可愛的頭字縮寫,我想是由Larry Wall發明的,意思是“Do What I Mean”,Perl社群常常使用這個字眼。

DWIM背後的概念是完美的軟體就好像一個從瓶子跑出來且滿懷感激讓你許願的精靈,我不是在說那些你對著噴泉或流星所許的不值錢願望,大家都知道你必須注意許願時的遣詞用字,因為許願精靈會以字面的意思給你要的,而不是你真正想要的,就好像所有你在使用的軟體一樣;相對的,DWIM精靈站在你這邊,可容忍文法或邏輯上的錯誤,不會得到錯誤的結果。(“一個男的走進酒吧,帶著迷你鋼琴跟一把十二英吋的鋼琴家…”)

每個程式設計師表面上都試著把DWIM寫進他們的軟體內,但幾乎都是用臆測的方式,事先假設使用者的行為會如何如何,有時候是以協力過濾(collaborative filtering)或其他以規則演算的方式來寫,但同樣也是會錯誤百出;唯一能讓DWIM不再只是驚鴻一瞥的方法是創造一支真正有智能(intelligent)的軟體──不僅是有意識,而是有智能,希望也有智慧和感知能力,以及(咽口水)友善的。

但這就會令人憂心了,大家都知道“智能”並不必然對你會產生有同理心,特別是你做了一些白目的事情。

所以到底要不要DWIM啊?就一方面而言,我們希望軟體可以更好,預測你想要的,回應你的需求,所以你可以過著你一直渴望的快樂幸福的生活,就另一方面而言,想達到這樣的境界的唯一方法是打造比我們更聰明的軟體,到那時,好一點的話我們要擔心會不會被邊緣化,壞一點的情況是我們要擔心會不會被奴役或被消滅掉。

我認為這解釋了,至少某部分解釋了,為什麼我們業界大部分都在打造越來越大的死系統來達到假假的DWIM(而且,打造這種大而麻木的系統,有什麼語言會比Java更好嗎?),死系統很安全,它們是決定性的且完全可控制的。

讓我們野心先別那麼大,省下口水先假設在我們有生之年不可能建造出有意識、有智能的軟體,那麼,比起現今我們大多數人產出的一般般的大便,有可能建造出比那更好的軟體嗎?

有另外一隻精靈叫做QWAN,建築師Christopher Alexander所發明的詞彙,意思是“Quality Without a Name”,而且(就跟這篇論文的其他難懂的觀點一樣)這是他早就了解的概念,終其一生不斷嘗試想把它描述出來跟找方法確實把它打造出來;簡短一點講的話,QWAN是一種無形無影“看見了自然就懂了”的空間或結構的特質,帶有 (a) 經由有機成長可以達到的境界,以及 (b) 詭秘地跟人類大腦中某部分硬體或軔體有關係,因為每個人都會有那靈光一閃抓到那模糊意義的時刻,但沒人真的知道為什麼會這樣。

在過去晦暗的時代,一些軟體專家們領悟到軟體也可以有QWAN,然後又發現在軟體跟從實體結構中想把它揪出來都一樣困難。

我在這裡主張,在之前列出我喜愛的系統,剛剛好在這些系統中可以找到明顯的QWAN,而我說那些缺乏重要特質的那些系統,都沒有QWAN的蹤影。(我之前有列舉出幾個較明顯的例子,然後含糊帶過其餘的,還記得嗎。)

人們都看出Emacs擁有QWAN這特質:美好、有生氣、舒服、正確,好像舊舊的牛仔褲那麼合身,猶如圖書館內火爐旁舒適溫軟的椅子;我現在說的恰恰是非常偏右腦的東西,情愫與感性:剛剛好這正是搞軟體的人很憋腳不擅長的,難怪我們不知道怎麼把這玩意放進軟體內,但不像使用者介面設計,軟體QWAN只可能從程式設計師手底下出現,因為對那些在你的軟體平台上開發的人來說,你擔任的角色就猶如室內裝潢師、主廚、人體工學顧問一樣。

那就是為何我認為大部分的軟體都是大便的原因,我不是在講一般使用者的使用經驗與感受,我是在講開發人員的開發經驗與感受(如果有的話),設計是一種藝術,不是科學,而且芸芸眾生皆非天生的藝術家,所以當QWAN出現在軟體系統中,即使只有一點點,也是很非凡的成就。

注意,順帶一提,軟體系統給一般使用者的使用經驗跟給開發人員的開發感受根本就是兩回事,Visual Studio提供相當精緻的使用者經驗,在這裡我說的使用者是指寫C++或C#程式碼的程式設計師(相對的另一方是,寫工具軟體幫助其他人寫程式,或是幫助別人把一些常做的事情自動化);Emacs讓使用者超難上手,但給開發人員的介面無與倫比好的不得了;Eclipse在兩者之間,但看得出來比較偏向一般使用者那一邊。

最後,QWAN有某部分是無法言喻的,把我的配料(命令列模式、擴充語言、advice系統、等等)加進去會讓系統更好,但不保證QWAN就會浮現出來,QWAN那些部分最終還是要回歸到品味(taste),既然品味人人皆不同,而且QWAN遠遠比不上DWIM那麼聰明,一個人的QWAN或許會是另外一個人的惡夢。

不過我依然認為我們應該試著將它打造出來。

型別系統(type systems)扮演的角色

太好了,來龍去脈說的夠多,我終於可以解釋一下我對型別系統的看法。

簡單講,型別系統是用來建造硬體的。每套軟體系統都有台機器在底下運轉──其實應該說有一整疊的機器,很多很多,從馮紐曼機器的CPU與暫存器與匯流排,往下到半導體元件,再到原子與夸克,以及量子力學的理論基礎。

不過我對硬體有更廣義的定義,硬體可以是任何事物,可以產出決定性的運算結果,非常硬而沒彈性,你必須先把它弄破才能做點修改要不然就要整個換新。所以,它並不只是由原子組成物理結構意義上的硬體;就我的觀點看來,一台機器的硬體部分也包含了那些需要重新啟動才能做修改的軟體。

型別系統的概念跟“編譯期間”與“靜態檢查”緊緊相連,我對型別系統也有非常廣的定義,我認為所有加諸在運算上的限制都是某種型別系統,包括scoping跟visibility(public/private/protected/friend/...)的限制,安全性限制,甚至程式的基本運算架構也算,我的看法中的“靜態”型別檢查其實包括了某些發生在執行週期的檢查。

但當談到靜態型別系統時,大部分人指的都是編譯週期的檢查與驗證(語言的語法中的型別標示,從AST建立推論出來的型別資訊),這些是在執行時就會不見了的東西。

跟把限制與檢查延到執行時才做相比較,靜態型別系統有一些優點,其一,程式碼跑的比較快,因為如果你執行前就做好檢查的動作,而且你若能保證執行時程式不會有改變,那你就不必在執行時做檢查,另外一個,靜態的限制條件,通常都可以用編譯器之外的工具加以分析(例如你的IDE),這可以幫助你了解程式執行的流程為何。

真是太棒啦。

靜態型別系統沒什麼不好,只是你必須知道,當你用它時,你是在建造硬體,而非軟體。

對一個寫好的程式而言,靜態型別系統絕不會對執行效能有所影響:不論系統提供多少的型別可用,產生出來的機械碼是一樣的,有個恰當的例子:C就只有那麼一點點最基本的型別,但C++程式不會比C跑的更快,C沒有動態型別檢查(dynamically typed),但也不太能算是靜態型別,單單用C也可以寫出又快又穩的程式。(Emacs跟Linux核心就是兩個好典範。)

靜態型別系統的正確使用時機是當我們想把軟體固定下來變成硬體的時候;每當一組運算法則(例如OpenGL繪圖指令)變得很普遍很穩定時,就值得犧牲一些彈性來將它轉到機械層以獲得較高的效能,也就是轉成硬體,但通常效能最佳化會對彈性造成很大的損害(其中非常小的一部分是標準化過程所帶來的,我想)。

因為眼下大部分的程序員都偏愛打造牽線木偶而不是會讓人恐慌的真人小孩,大部分的程式設計傾向於建構一層又一層的硬體;C++跟Java程式設計師們(我想C#也是)基本上在一開始就用型別系統來塑模任何問題,也就等於把每一行程式都轉成硬體的形式。

僅用陣列、鏈結串列、雜湊、樹結構與函式就可以用C++跟Java寫出鬆散型別檢查(loosely-typed)的程式,但這樣會被兩個陣營的人強烈抨擊(或至少皺眉不屑),在兩個陣營裡,嚴格型別檢查跟詳細塑模設計在過去十年來逐漸成長成主流,他們認為型別檢查鬆散的程式會危害生產力(也就是指會影響開發時程),也會危害彈性(也是指會影響時程表,因為沒彈性表示很難納進新的功能)。

Hindley-Milner型別系統(源於學界,幾乎打不進業界)的虔誠教徒相信H-M型別系統遠遠優於Java或C++的,因為(理由之一)它漏洞較少。

H-M不被業界所使用,各位,聽我說,正是因為它沒有任何漏洞。如果你正在開發軟體,但你相信(同大多數人)開發方法是在一個長又痛苦的循環中不斷地建造硬體然後丟棄,直到那塊硬體是你想要的東西才停止,那麼有時候你會需要掙脫型別系統的限制:告訴型別系統閉上鳥嘴、我知道我在做什麼、我的程式寫的沒錯正是我想要的,型別轉型(type casts)、縮減或放寬的轉換、用friend functions來繞過類別的存取保護機制、把自訂的迷你語言放進字串內然後自己手動解析,有數十種方法可以跳過Java跟C++的型別系統檢查機制,而且程式設計師們一直都有在用,因為(很少人知道這點)他們真正試著建造的是軟體,並不是硬體。

以沒路用的形式上的數學觀點看來,H-M是很優美的,它處理起某些運算結構與概念特別巧妙;在Haskell、SML、OCaml可以找到的樣式比對後分發(pattern matching dispatch)非常非常好用,但不意外地,它處理起其他一般常見且大家都需要用的運算結構與概念非常笨拙,不過那些擁護者反而辯解說成是你錯了、其實你不需要這些東西,例如像是,你知道的,設定變數這種基本動作,你才不想要這種東西咧,相信他們吧。(OCaml讓你做,但提到這點時他們的目光都下垂看著自己的鼻子。)

沒錯,加上一點努力,你可以用Haskell打造出漂亮柔軟的牽線木偶,但永遠就是個小木偶皮諾丘,絕不會有好心腸精靈讓你美夢成真變成小男孩,Haskell中幾乎沒有動態程式碼載入或是執行週期的反射機制(runtime reflection)這些東西;這些概念對他們來說太怪異了,以至於連想跟他們討論這些概念為什麼有用都很困難:他們的世界觀裡沒有軟體是活生生的可以成長可以呼吸這樣的思想。

讓我們來看看動態型別檢查的天地裡稍微不那麼體面的語言,大家都知道很多程序員都把動態語言跟玩具看做同一類;主要流行的動態語言包括Perl、PHP、Python、Visual Basic、JavaScript、Ruby、Tcl跟Lua,除了這些語言設計者應得的尊敬之外,我不得不說他們在學生時代的編譯器課程應該是被當掉的吧,舉個例:他們都沒弄好lexical scoping;諷刺的是,他們的腳本語言放到鎂光燈下後反而讓他們(Larry, Guido, Matz, Brendan, ...)搖身一變成為世界級的語言設計者,這也讓他們,跟Salieri一樣,能夠以大部分人不了解的觀點來理解領會他們設計語言的不足與弱點(現在想修正已經太太困難了)。

Scheme大有前途,但它有個致命缺陷,就是它不能成長,跟已被業界廣泛採用的語言與平台情況不同,它們是為了保住廣大的使用群,Scheme是為了維持小而美才能佔據它的利基市場,也就是用在電腦科學教學課程上。

多方看來Common Lisp是個理想的選擇:它是動態型別檢查的語言,但可選擇性地加上型態標記(換句話說,你建造軟體,然後可以選擇要不要轉成硬體 ),很多好工具可用,說明文件也都有,具有好軟體之必備特質,我在這篇文章舉出來的它都有,而且還有相當程度的QWAN,然而,它已經停止繼續發展了,程序員就像鯊魚嗅到一樣敏感察覺到它沒氣勢了,Common Lisp擁有的能量跟William F. Buckley, Jr.和Charleton Heston激辯不相上下。(我看過一次,我發誓他們兩個一定有一半時間在打呼)。


單純的Lisp缺少了C的語法結構,在C語法根絕之前:這項任務可能要花上五十年,我們絕不可能在電腦運算與語言設計上有什麼真正的進展,在那之前若想往前走,唯一之道是把程式語言中的模型(AST)與表示(語法)分離開來,允許語法外衣,讓愛用者們繼續用C語法直到他們全死光,Common Lisp本可以加進額外的語法規則,但它既然已不再成長,也就不可能發生。我會到別處尋找下一個主流物(the Next Big Thing)。

結論


時間是凌晨三點三十分,已經超出我每月部落格寫作限制時間兩小時了,你下個月或許會在我這看到一篇簡短的部落格!不論如何,我想我已經把胸中的不吐不快都寫下來了。


我想,我們的理想是軟體能夠按照你的意思執行動作,不過因為DWIM只可能發生在真正有智能的軟體上,而想要依據變動中的世界來預測軟體該怎麼寫太困難了,話雖如此,我認為那是我們想要的。

我懷疑短時間內不可能有那樣的東西出現,因為大部分的程序員一股腦地專注在打造硬體上,勤奮地將型別系統使用在他們的軟體上,太過度了反而搞壞了原本還不錯的軟體。

在魔法油燈變出DWIM前,我認為我們應該建造有生命的軟體,或許只是像樹一樣的生物,但那就足以喚醒其體內的QWAN,任何只要有一丁點的QWAN的系統都真的很棒、值得使用──至少對寫程式的人來說;一般使用者對這些系統對評價參差不齊。

有生命的軟體,擁有命令列模式,因為你需要能像個成年人一樣跟他說話,擁有擴充語言,因為要能夠幫助他成長,擁有advice系統,因為你需要訓練跟修正他,擁有一塊利基市場,因為他需要使用者們才能成長茁壯,擁有外掛系統,這樣你才能幫他打扮參加舞會,而且他是有自我察覺(self-aware)能力的,能力的最大值只會受限於外在效能的約束,這些特質都必須巧妙優雅地整合在一起,花在每個子系統上的心力與詳細程度都跟整個系統一樣。

而且你不應該在每當需要修改時就要謀殺它一遍,如果你對待你的軟體像個活跳跳的生物,那麼最終他就會開始變得像個真的。

如果我們能喚醒真的人工智慧,我想皮諾丘是個適合的名字。

2010/10/11

讀後推薦:程式設計師的自我修養:連結、載入、程式庫 by 俞甲子/石凡/潘愛民

我看了這本書,覺得還不錯,對我很有幫助,釐清了很多概念與疑問。

書名:程式設計師的自我修養:連結、載入、程式庫
作者:俞甲子/石凡/潘愛民
出版社:碁峯




史瑞克說妖怪像洋蔥一樣,是有層次的,資訊科學這玩意兒更是如此,從上到下不知有多少層,有應用軟體層、有整合開發套件跟永遠看不完的類別庫與函式庫、有作業系統提供的API跟系統呼叫、有軔體層、有硬體層,每層都還可以繼續細分下去,另外還有網路服務跟雲端運算,各種數也數不清的結構與架構,嘿嘿,看來咱們比妖怪更有層次啊。




這本書的主旨就是副標題所說的,關於軟體程式從寫好開始,編譯成組合語言,組譯成機器指令,加上執行階段程式庫靜態連結成執行檔,執行時由作業系統載入到記憶體裡,動態載入與連結所需的程式庫,這一連串的過程;這本書解說了在x86架構下的ELF檔與PE檔格式,分別是在Linux與Windows系統下所使用的檔案格式,用來儲存執行檔(無附檔名或.exe)、中間目的檔(.o or .obj)、靜態程式庫(.a or .lib)、動態程式庫(.so or .dll)等等,書中有概念的闡述,也分解簡單的小程式來當實例,對我來說,幫助我釐清了很多觀念,例如什麼叫做runtime(runtime environment, runtime library, 執行階段程式庫)、編譯器之後的靜態連結器要處理哪些東西、動態程式庫(.so or .dll)背後的道理是什麼、符號表(symbol table)到底有多重要、在main()執行之前作業系統做了哪些事情、等等,真是太棒了,好書一本。



有一些書,偏重理論與概念,例如鐵甲武士惡鬥吐火龍,對於一個在應用軟體層的人來說,較不實用,我想要的是實際上用的工具與技術(compiler, dynamic linking, etc..)的概略說明,我想要的是當前廣泛使用的作業系統(Linux, Windows)與工具(gcc, Visual C++)與檔案格式(ELF, PE)的探討,當理論書籍說有哪些方法可以用來實作出什麼什麼技術,本書則告訴你Linux與Windows用的技術是什麼;這樣當我在其上開發軟體時,才不會被華麗文藻包裝過的說明文件迷惑,搞不懂共用物件與plug-in的差別。

PS 不要誤會,龍書是經典,編譯器也是資訊科學必修的課程。



還記得當初寫第一支程式的時候嗎?從寫好到執行看到螢幕上印出hello, world.,其實中間經過了許許多多的關卡,編譯器、組譯器、靜態連結器、作業系統載入、動態連結、虛擬記憶體系統、等等,不說不知道,稍稍往下鑽研就會被嚇到,疊床架屋一層又一層的技術,才能讓我們鍵入少少幾行程式按下個按鈕就可以寫出hello, world.,當我們在其上享受各種新式技術與便利之餘,也別忘了要了解一下底層的原理,因為三不五時,底層的東西會跑上來嚇人,有時候程式當的亂七八糟,可是又看不懂錯誤訊息,有時候甚至連錯誤訊息都沒有,這時若心理有底層技術的概念,解決問題的機會就會多個幾趴。




如作者所言,關於載入器(loader)與連結器(linker)的資料是不多的,就算有也是那種看起來很硬很技術性的著作,有這麼一本算是研究心得的著作,要謝謝作者所花的心力。

2010/09/07

翻譯:Windows程式設計的革命簡史(A Brief History of Windows Programming Revolutions) by Ron Burk

文章:A Brief History of Windows Programming Revolutions(Windows程式設計的革命簡史)
日期:2009.12.01
作者:Ron Burk
作者的部落格:Ron Burk - Programming, psychology, and "stuff".
作者簡介:
曾擔任Windows Developer's Journal的編輯職務;正在寫一本書,書名為"The Pop Psychology of Programming";這裡有一段5分鐘的影片,Ron Burk講解三種computer programming的定義。



Windows程式設計的革命簡史

爬出DLL地獄──再一次


首先,我們有Windows API以及DLL地獄(DLL Hell),第一波的革命技術是DDE──還記得熱連結(hot links)讓我們可以產生出狀態列來顯示微軟股票目前價位嗎?

大約就在那時,微軟搞出了VERSIONINFO這玩意,用來揮除DLL地獄這夢靨,但微軟的另一個團隊發現DDE有一個致命性的缺陷:那不是他們發明的!

為了解決這個問題,他們創造出OLE(跟DDE差不多,看起來不同而已),而且我還深深記得在一場微軟討論會上,有位演講者公開聲明Windows API很快就會改寫成OLE API,螢幕上的每個控制元件將會變成OCX;OLE引進介面這玩意,用來跟DLL地獄說掰掰,還記得那"就地(in situ)"狂熱嗎,還記得那時我們幻想著有一天所有應用軟體通通內嵌在一支(很明顯地,非常大的一支)Word文件中嗎?

就在那時期左右,微軟改拜C++,MFC也出來了,再一次地解決老問題,但這一次有繼承(inheritance)這玩意,不過咧,OLE可不會坐著發呆,重新包裝後以COM之名現身,突然我們醒悟了,OLE(還是DDE啊?)才是王道啊──裡面包含了精心打造的元件版本系統,是用來避免陷入DLL地獄的,與此同時,微軟某搗蛋團隊發現MFC有一個致命性的缺陷:那不是他們發明的!

他們毫不猶豫地修正了那缺陷,創造出ATL,跟MFC差不多,看起來不同而已,並且試著把COM團隊費盡心思教會我們的技術細節通通藏起來,這可刺激到了COM團隊(還是OLE啊,搞不清楚?)重新改名為ActiveX後再出發,釋出數以百磅計的新介面(甚至有新的版本控管介面,用來防止DLL地獄的玩意),還有,讓我們的程式碼可經由瀏覽器來下載的能力,加上各種病毒(哈哈──想辦法跟上腳步吧,你們這群ATL傢伙們!);就像個被忽視沒人裡的小孩一樣,作業系統團隊大聲呼喊著看過來喔,"準備好等著迎接Cairo吧",ㄘㄟˊ,他們從來沒能好好解釋說明過那是啥東西,更別提出貨見人了,不過有一點功勞要算在他們身上,作業系統團隊確實導入了"系統檔案保護機制(System File Protection)",是用來遠離DLL地獄的玩意兒。

與此同時,微軟另一支團隊發現Java有一個致命性的缺陷:那不是他們發明的!怎麼補救呢?於是有了J、Jole、ActiveJ(老實說,我記不得名字了),跟Java差不多,看起來不一樣而已,很興奮吧;不過昇陽開始告微軟,用的是某古老的法條說一家公司不能在一年內放出太多的技術,很明顯地是在試著阻止微軟創造雷同但只是看起來不一樣的產品,結果是讓微軟有了全新的自由,可以把錢塞進國會議員的褲子裡;還記得J/Jole/ActiveJ的產品經理用他的鞋拍桌保證微軟絕對不會終止放棄他的產品嗎?傻孩子!這一切只代表了一件事──ActiveX(還是應該叫COM啊?)團隊得到的關愛眼神太少了,這一群身段柔軟的API打造者,以更強的姿態COM+(不是應該叫ActiveX+嗎?)還有MTS(我不懂,為什麼"MTS"裡沒有"COM"或"ActiveX"或"X"或"+"等字眼呢──這次我整個被他們嚇到了!)回來了,他們還威脅說不久之後就要在所有術語後面再加上一個"+";大約在那個時候,某人大聲嚷嚷著"Windows DNA"和"Windows Washboard"一段時間,不過在我搞懂之前就死掉出局了。

那時,微軟注視著網際網路(internet)的發展已有數年,越來越不安,他們發現,網際網路有個致命性的缺陷:哎呀呀,你大概知道我要說什麼了,於是把我們帶到.NET(唸起來像是"doughnut甜甜圈",看起來不一樣而已),跟網際網路雷同,只不過有著更多的文宣廣告與宣傳;讓我把一點說的非常非常清楚:.NET解掉了DLL地獄這個麻煩,.NET有一個新的程式語言,叫做C#(發現Active++Jspresso有個致命性的缺陷,所以下場是出局了),.NET包含一個虛擬執行機器,所有語言都在上面跑(發現依賴英代爾CPU有個致命性的缺陷),.NET只用一套登入系統(如果不把你所有的密碼都存放在微軟的主機上,那是有致命性的缺陷的),事實上,比較簡單的方式是把.NET沒有的東西列出來;毫無疑問的,.NET將會是Windows程式設計的革命性的徹底改革的新方式...到明年就不是了。

2010/08/22

翻譯:C++的編譯速度(C++ Compilation Speed) by Walter Bright

文章:C++ Compilation Speed(C++的編譯速度)
日期:2010.08.17
作者:Walter Bright
作者的部落格:Walter Bright Home Page
作者簡介:
Walter Bright是位電腦程式設計師,是D語言的設計者,第一套C++原生編譯器的主要開發員,也就是Zortech C++(後來變成Symantec C++,現在是Digital Mars C++),在C++編譯器之前,他開發了Datalight C編譯器,先以Zorland C後以Zortech C之名販售。



C++的編譯速度


我常聽到有人抱怨說C++程式碼編譯速度很慢,有時候甚至要花上整夜的時間,編譯慢是exported templates這玩意的源由之一,甚至列在發展Go語言的理由清單上,這點確實是個問題;既然我身在C++編譯器的產業中,三不五時就會被問到這點。

為什麼C++編譯速度慢?一旦我們合理假設開發C++編譯器的人都擅長於寫出效能高的程式碼,那麼,一定有某個深植於C++語言本身的原因;的確,不同牌的C++編譯器速度快慢相差極大,但還沒完喔,其他語言通常能夠快上一整個等級,而且厲害的編譯器專家應該不會只為其他語言寫編譯器吧(!)。

我從1987就在寫C++編譯器了,對比今日想當年,電腦可是慢的不得了,所以我投注極大的精神讓編譯器能夠快一點,花上大把的時間做效能分析以及微調各個小地方來讓編譯器更快,我發現,語言本身的某些特性讓編譯速度快不了。

理由是:


1. 轉譯過程中有七個階段[1]。雖然有些可被合併處理,但在前端處理原始碼最少要有三個階段,至少我還沒找到降到三以下的法子。要快的話語言設計時就只能有一個階段,C++0x惡化了這點,居然要求trigraph轉換與行尾為\與下行接合這兩個功能要能夠支援string literals[2]

2. 每個階段都相依於前一個階段,意思是,沒有可靠的方式可以做往前先看的動作,例如,往前先去找#include然後先去讀進檔案;編譯器沒辦法往前先看出是個string literal所以不要做trigraph轉換,必須先做trigraph轉換,但要做好回到上一步的準備;我從沒找出能夠平行編譯C++程式碼的方法,除了在make時加上-j參數這種很粗略的作法。

3. 因為#include是種文本逐字置入(textual insertion)的機制,而不是符號式(symbolic)的,當一個檔案被#include很多次,編譯器只能悲情地做白工地一再地處理,即使是被#ifndef包起來也一樣。(Kenneth Boyd跟我說,如果將標準文件讀的仔細一點,是有可能允許編譯器省略被#ifndef包起來的#include,但我不知道有哪一支編譯器利用了這點。)

4. 程式檔案中總是傾向於,通通#include進來就對了,當責任全部落在編譯器身上時,每一個.cpp檔通常都會連帶引出一拖拉庫的檔案要處理,在Ubuntu上,就算只把標準函式庫#include進來,居然需要處理74支檔案總共37,687行耶(不包括同支檔案被#include多次的情形);templates以及generic programming的興起更惡化了這點,而且,把更多的程式碼放進標頭檔(header files)中的壓力也逐漸升高,更是雪上加霜。

5. 語意上的與語法上的(不只是詞彙上的)處理單位依賴處在它之前的整個原始文本,意思是,沒有東西是上下文無關的;不把#include的東西先看一看,就不能正確地解析(parse)檔案,甚至是先做lex的動作也不行,標頭檔在第二次#include時可能含有不一樣的內容(事實上,確有標頭檔利用這點)。

譯註:語意上的 semantic,語法上的 syntactic,詞彙上的 lexical。

6. 因為第5點,編譯器在某個TU[3]所編譯的#include的結果,不能下一個TU共用,每個TU都必須從頭開始。

7. 因為不同的TU之間彼此不知道對方的存在,常用的templates在每個TU都會被產生出來,鏈結器(linker)會將重複的刪除,但當初所花的時間都白費了。

預先編譯標頭檔(precompiled headers)解決了一些問題,但那是對非標準的C++做出某些簡化後的假設,才可辦到,例如,標頭檔被#include還是會含有同樣的內容;所以你必須小心,不能違反這些假設。

想解決這些問題又要跟舊有的程式碼保持相容性,真是高難度的挑戰啊,我預期在C++0x之後,會有相當份量的心力花在這些問題上,但那至少是10年後了。

在那之前,並沒有哪個方法可稱得上是解答,exported templates被廢棄了,precompiled headers是不符合標準的,imports被踢出C++0x標準之外,以及往往你沒有選擇編譯器的權力,諸如此類的;現在來說,有效地使用make -j參數可算得上是最好的方法了。

我會再談談關於語言的設計,哪些特性能夠導致快速的編譯速度。


註解

[1] C++98標準文件的2.1章節, 七個階段是:

1. Trigraph與萬國碼轉換。
2. 行尾為\時接到下一行
3. 轉換成預先處理的標記(preprocessing tokens),標準文件註明說這是上下文相依的。
4. 預先處理的指令執行,展開巨集,#include的讀取以及再跑一次1到4。
5. 將原始碼中處在char與string literals的字元轉換成執行字元集(execution character set)。
6. string literal的接合。
7. 將預先處理的標記轉成C++的標記(C++ tokens)。

[2] 在C++0x標準文件中的例子在2.14.5-4:

const char *p = R"(a\
b
c)";
assert(std::strcmp(p, "a\\\nb\nc") == 0);

[3] 一個TU,也就是一個轉譯單位(Translation Unit),通常就是一支C++原始碼檔案,通常是以.cpp為副檔名,編譯一支TU會生出一個目的檔(object file),每個TU的編譯過程都與其他TU不相關,最後由鏈結器(linker)將目的檔整合成單一的執行檔。


感謝

感謝Andrei Alexandrescu、Jason House、Brad Roberts以及Eric Niebler給予這份文章草稿時的有用建議。

2010/08/16

翻譯:Java簡史(A Brief History of Java) by Jeff Foster

文章:A Brief History of Java(Java簡史)
日期:2010.08.13
作者:Jeff Foster
作者的部落格:Fatvat : Exploring functional programming


Java簡史

話說當年1995之時,昇陽(Sun)公司釋出Java程式語言,做為整個Java平台策略的一部分,當初喊著“一次編寫,到處運行”的口號,要讓Java遍地開花,從腕錶到手機到筆電到超級電腦,隨處皆可運行。



剛開始時Java的接受度有高有低,當出現Java力有未逮之處,就會有福音天使出來保證這技術將會改變世界,你看,靠Java運作的烤吐司機就在不遠的角落了。

隨著時間演進,為了守住“一次編寫,到處運行”的承諾,Java也逐漸背上更多的負擔,標記為廢棄的方法(deprecated methods)到處可見,但昇陽必須留下這些功能來保持向後相容性;java.util.DateTime此套件變成了劣質設計的同義字,差勁的命名規則總是在修正中(叫它size好還是length好呢?)。

微軟(Microsoft) 的.NET開始蠶食Java的領地,微軟團隊導入delegates,一種有做型別確認的函式指標,使得事件處理(event handling)變得容易許多;Java要趕快反擊,所以在版本1.1時,Java生出了inner classes,能夠有類似的效用,但以一種較有限制與用起來較麻煩的方式出現,一份Java白皮書斷定地說『bound method references是不必要的東西....這玩意減損了Java語言的簡單性與一致性』,但與此同時,將bound method references放進Java裡的勢力從沒消失過。

當Java到了版本1.4時,為了對抗微軟的.NET,昇陽決定要有一套新的策略手段,思索良久之後,昇陽將版本1.4改成“5”,試圖一舉超前.NET的2.0。

同時間附帶了另一個決策,實作generics,一種能夠有額外的型別安全檢查的技術,不幸的是,隨型別安全而來的代價是要多打字,工程師引入generics後,每次又要寫一遍List<Foo> foos = new ArrayList<Foo>敘述時,就會常被聽到咒罵聲。




大學很快地就接納了Java;學生們不再需要學習手動記憶體管理與指標的種種艱澀難懂的奧祕,反之,他們可以依賴Java來做這些苦功夫,集中精神在解決問題上,不幸的是,這也導致一批同等級的開發者,被稱作“設計模式使徒(Patternistas)”,手上只有鎚子且把所有問題都看做釘子去敲,在他們的領導下,Java命名規則越來越可笑,當這種類別名“RequestProcessorFactoryFactory”成為一種常態時,一些開發人員開始質疑無限制地構築抽象化高塔是否真為明智之舉。

當開發人員意識到他們終日所為僅是把數千行的程式碼搬來搬去而已,他們需要一個字眼來辯護他們的存在意義,那個字就是“重構(refactoring)”,所有的設計模式使徒欣喜不已;他們不但能運用工廠的工廠模式(factory factories)、獨身模式(singletons)與訪問者模式(visitors)來解決問題,而且還能朝三暮四改變心意,並用個時髦字眼來正當合理化!

整個產業的演進方向只是為了滿足設計模式使徒們而已,跟別人與別的語言比起來,老鳥們覺得Java越來越弱,所以新型開發環境出現了,IntelliJEclipse的目標是將開發人員受的傷害最小化,靠著極佳的程式碼自動補足機制(code completion)與重構功能,只需按幾個鍵而不用輸入一長串的程式碼來達到那想要卻沒有的語言功能




Java開始向企業端進攻,招攬了一些有領導地位的的架構大師,打造出一套會造成典範轉移的協同式架構方法來建置企業軟體,其結果不小於一場革命;爪哇豆(beans)現身了,Beans顯然是一種伺服端的元件架構,用來當企業應用軟體的建構基本模組。

使用generics所帶來的角括號障礙一旦減低之後,Java邁步向前跳上了XML的列車,藉由使用XML,開發人員就能將簡單明瞭的概念表達成一整個龐大囉嗦的角角惡夢,好處是XML檔案(不同於其他檔案類型)可以輕易地被電腦看懂處理,至於對人難以閱讀這種小代價是值得的,像是AntJBoss這些軟體都是由可執行的XML所建構出來的。

與此同時,在這些架構大師的宇宙之外,一群新種程式員認為將該死的工作完成遠比一整天都花在打字重要,這種想法誕生出一些框架,例如Rails,設計的重點在於不擋路讓你能解決真正的問題,其中心思路以“約定俗成先於設定(convetion over configuration)”之名廣為人知,Rails獲得正面的迴響,而且至少有一些Java信徒轉投向Ruby的陣營;Java不再能緊抓人心的第一個徵兆開始浮上檯面。

2006年8月,Java 7計畫啟動,很多開發人員都要求一個叫做lambda expressions的功能,毫無疑問地會簡化很多原先Java搞的很痛苦的撰碼作業,可惜,Java委員會四年後還在為這項功能的細微差別爭辯不休,而且有可能會被排除掉,Java 7的無作為引出了新一代更迷人的語言,例如ClojureScala,設計在Java環境中運行,但不需要Java語言。

2009年4月,甲骨文(Oracle)公司宣布計畫將收購昇陽,此乃敲下棺材釘的最後一鎚,由“黑暗王子拉瑞”所領軍的甲骨文是一部併購機器,擅長於企業軟體與賺進大筆鈔票,當甲骨文的律師們了解一份份的軟體專利文件,他們會挑個大目標然後引起戰鬥,而還有哪個目標比谷歌(Google)更大呢(一家網路廣告的領導品牌),所以甲骨文的律師猛撲而出,戰爭就此展開。

這會給Java帶來什麼後果呢?從15年前的小小開端起,在昇陽的領導下,Java爬上了最熱門的程式語言的頂端,而在甲骨文的控制下,不但到底會不會有下一版的Java情況不明,更別提開發人員渴望許久的功能了,這是Java的新開始還是結束呢?

2010/08/12

翻譯:命名專案的十項提示(10 Tips for How To Name Your Project) by J Wynia

文章:10 Tips for How To Name Your Project(命名專案的十項提示)
日期:2006.06.22
作者:J Wynia
作者的部落格:The Glass is Too Big


命名專案的十項提示


這已經是數年前我寫的一系列文章中的一篇, 但我想要再次分享出來,考慮到有這麼多人開發的產品與服務的名字,居然需要落落長的解釋與說明,才能夠了解、念出來或是正確寫出來,我想這篇的內容仍然還是跟我當初寫的時候一樣重要。


命名你的專案的方法(與避免事項)


1. 如果你想到的名字是直接取自於某科幻或奇幻小說、電影、漫畫等等題材,放棄吧,在軟體業中這些都已經被用爛了,不僅想出有原創性的名字的可能性相當低,而且,科幻題材中大部分的角色與地點名稱都已經被註冊了,你有被告的風險。

2. 如果你是從希臘、羅馬或古北歐神話中取材,再嘗試別種作法看看,我們不知收到多少封談到以“墨丘利(Mercury)”命名的軟體的電子郵件。

3. 拜拜股溝(Google)大神,找找你想要取的名字,找到的項目越少越好,如果什麼也沒找到,恭喜你囉。

4. 如果你想要錯拼幾個字母來打造獨特的名字,別!把你嶄新的視窗膽案系統稱作Phat32,使用者在搜尋引擎只會看到關於“fat32”的結果,你覺得他們會高興嗎。

5. 如果你取的名不能在五零或六零年代的電視上說出來,你的方向大概是錯的,特別是當你想要產品在工作環境中被每一個人使用,如果單單念出產品名就有可能會被告性騷擾,那自然沒人會推薦給同僚。

6. 如果你的產品名連發聲念出來都是件不可能的任務,你就得不到口耳相傳帶來的好處,同樣的,如果沒人知道怎麼念,人們也就不會試著大聲說出來詢問相關疑惑。你怎麼念MySQL?PostgreSQL?GNU?幾乎所有地球上有人用的語言都是有某種子音/母音的音節系統,輪流使用子音與母音來拼名字是個相當好的方法,確保某人可以發音出來。

7. 跟女人的裙子一樣,越短越好。

8. 查看看.com的網域名稱是否可用,如果已經被申請走了,這是一項很好的指標,表示某人已經想到這個名字而且比你搶先要用它。做這個動作即使你不打算申請網域名。

9. 別把產品本身的限制條件加在名字上,把產品叫做LinProduct或是WinProduct的話,那將來要釋出跨平台版本怎麼辦。

10. 別把你自己的姓名用在開放原始碼計畫上,如果將來你不再參與,那這計畫就必須改名,或是你的名字將會以你不喜歡的方式被運用。

2010/08/11

翻譯:專案之名有什麼意涵?(What's in a Project Name?) by Jeff Atwood

命名,看似簡單卻絕不容易,啟動新專案要有個codename(內部專案代碼),寫程式要替變數、函式、類別取名,當專案完成變成產品,那也要有個又酷又炫的名號;取的好心情佳,取的不好整天就不順;看看這篇關於專案命名的文章吧。


文章:What's in a Project Name?(專案之名有什麼意涵?)
日期:2007.11.12
作者:Jeff Atwood
作者的部落格:Coding Horror


專案之名有什麼意涵?

從我進Vertigo公司以來,曾經參與過這些個專案:

  • 米開朗基羅(Michelangelo)
  • 納許(Nash)
  • 威士忌小鎮(Whiskeytown)
  • 超大硬糖(Gobstopper)

這些我們內部使用的專案代碼,是從一份放有各種“東西”的清單中按照字母順序選出來的,每個新專案都是這樣被命名的,我們從A開始用,當到Z用完時,我們會選出一組新的清單,作為命名專案的靈感來源,你可以猜出上述專案名的靈感清單從何而來嗎?別偷看啊!

關於專案命名,我們有以下這些鬆散的方針:

  1. 我們偏好一個單字的名字。
  2. 必須相當容易就可以念出名字來,拼出來也很簡單。
  3. 對客戶來說須是親切適宜的。
  4. 在整個公司內這名字必須是獨一無二的,沒有重複使用。
  5. 我們需要一個夠多的靈感清單可以選,照字母順序。
當然,一篇關於命名的文章若要說得上完整,就一定要引用於達康(dot-com)狂熱之最高峰時出現在線上雜誌-沙龍(Salon)的經典大作,命名競賽(The Name Game)
最後,嘗試將命名一個專案所帶來的利益加以數字化,就如同試著量化一個名字所能帶來的好處,可能兩者同樣都很眼光狹隘,對一個找到跟他們一拍即合的命名商的幸運客戶來說,其邊際效益遠超出單純的取個名字,有新的詞彙字可以學,好玩的遊戲可以參與;還有,以百猴(一家幫人命名的公司)的例子來說,無可懷疑的溫暖與關懷,『我們得到的遠超出單單一個名字』九十八點六(98point6)的羅賓巴爾這麼說,『我是說,我替我女兒找了個好名,我們一個資深董事對‘梅斯卡蘭札(Mescalanza)’有強烈的認同歸屬感,大家不再稱呼他為吉姆(Jim),他的名字就是梅斯卡蘭札。』與此同時,她還說,『我們網路開發部門的資深經理就莫名地愛上了‘果醬餅乾(Jamcracker)’,以致於,哈維(Harvey)會議已經改稱果醬餅乾會議,這家公司有三百個人將果醬餅乾視做哈維的代名詞。』

巴爾用手捂住嘴巴,『喔天啊,』  她說,『我忘了,我不應該向一個記者提到這些名字,技術上來說,我們沒有這些名字的所有權,果醬餅乾這名字仍然是百猴的資產。』

巴爾停頓了一下,好像在思考些什麼,然後她爆笑起來,『聽著,』她說,『我收回剛說的,你想寫啥就寫啥,如果外面真有人想要將他們的公司命名為果醬餅乾,願神保佑,也祝他們幸運。』

不論如何,困難點在於,如何生出一些新的靈感用來激發專案命名時的來源,我們先看看微軟的專案代碼以及蘋果的專案代碼,當做想法的出發點,

這裡是過去不同時間點時,我們考慮用來命名專案的各種想法:

食物種類

電玩遊戲(Atari 2600大型機台, 等等)

啤酒品牌

羅馬帝王

卡通人物 / 節目

神話中的名字 / 神祇

汽車

GUIDs (個人最愛之一

寶石

咖啡飲品的種類

州名

鄉村名

植物

希區考克的電影


狗的品種

顏色

著名的探險家

樹木

美國稅務表

英國君王

名人(例: 沙岡

維基百科文章名

單一字母(包括萬國碼)

無線電通訊的字母系統

糖果品牌

恐龍

歷史地點

城市街道名

IKEA宜家家居產品名稱



扣件種類(螺帽,螺栓,鉚釘,等等)

滑雪度假村

國家公園

山之顛

第二次世界大戰時代的船隻

鳥類

海灘



Web 2.0的命名

魔獸爭霸的王國名

起司

國家

穀類早餐品牌名
如果有我沒列出來,但你認為是命名專案的好點子的話,還請留言。

開新專案之時,挑選一個新名字總是有其樂趣所在,我很驚訝我們很快就用光一整個A-Z循環,從我進公司的2005年算來,我們已經經歷過4次循環了,那是我們的作法,那麼,你又是怎麼命名你的專案的呢?

2010/06/25

Lisp + GNU Emacs + SLIME on Windows

上一篇講了GNU Emacs on Windows,其主要目的是為了這篇,安裝lisp系統與SLIME,on Windows。

首先是安裝lisp系統的部份,如果要從原始碼自行編譯的話,那會較困難,所以我通通使用已經打包好的套件。雖然只要一套實作即可,但我安裝了三個(CLISP、SBCL、CCL),這是為了試試看比較不同實作的差異,你不一定要這樣。

下面的鏈結是我使用的版本,你可以造訪官方網頁看看有沒有較新的版本。

首先是目錄的問題,太長或有空格都有可能會出問題,因為Emacs、lisp都有很深的unix背景,所以我新增了這些目錄:
C:\home
C:\home\bin
C:\home\bin\emacs (GNU Emacs放在這)
C:\home\yehnan (我的使用者家目錄)

開始下載安裝吧。

第一:CLISP (GNU CLISP)
在網頁上找到給Windows使用的套件,clisp-2.48-win32-mingw-big.exe(3.9 MB)。
我安裝在C:\home\bin\clisp下。安裝套件會增加這個路徑到環境變數PATH中。

有個小問題,安裝後執行,“找不到svm.dll”,解決方法是把libsvm\svm.dll拷貝到full\下即可,原因大概是Windows沒有symboloc link這種東西。

註:clisp-2.49-win32-mingw-big.exe修正了這個小問題。

執行後看到這個畫面就表示成功了。


第二:SBCL (Steel Bank Common Lisp,從CMUCL分支出來)
在網頁上找到給Windows使用的套件,sbcl-1.0.37-x86-windows-binary.msi(10 MB)。
我安裝在C:\home\bin\sbcl下。安裝套件會增加這個路徑到環境變數PATH中,並且新增一個環境變數SBCL_HOME指向這個路徑。

執行後看到這個畫面就表示成功了。

第三:CCL (Clozure CL,前身為OpenMCL)
在網頁上找到給Windows使用的壓縮檔,ccl-1.5-windowsx86.zip(34 MB)。
我解壓縮安裝在C:\home\bin\ccl下。

執行C:\home\bin\ccl\wx86cl.exe後得到這個畫面就表示成功了。

哇,很簡單嘛,lisp系統的部份已經搞定了。接下來就是安裝與設定SLIME。


SLIME全名為Superior Lisp Interaction Mode for Emacs,顧名思義,是一個Emacs的擴充套件(外掛),專門用來輔助寫lisp程式。包括一個slime-mode(minor mode)用來增強Emacs原有的lisp-mode,一個比較好用的REPL(read-eval-print-loop),SLDB(debugger),以及其他輔助工具。

怎麼取得呢?要用cvs指令,最好不要抓取一些網路上的壓縮檔(官方或非官方),因為那些可能都太舊了。
cvs -d  :pserver:anonymous:anonymous@common-lisp.net:/project/slime/cvsroot co  slime
怎麼安裝呢?把上面取得的整個slime目錄放進Emacs的load-path有設定的地方,我放在C:\home\bin\emacs\site-lisp\slime\

怎麼設定呢?這就困難了。
首先在C:\home\bin\emacs\site-lisp\新增檔案site-start.el,內容是
(setenv "HOME" "C:/home/yehnan/")
。因為Emacs預設的家目錄會是類似這種的C:\Documents and Settings\Username\Application Data,太長且有空格,所以改掉。

然後是在C:\home\yehnan\新增檔案.emacs,各種設定都會放在這裡。什麼,你沒辦法新增一個開頭是小數點"."的檔案?使用Emacs新增吧,其實Windows是容許這種檔名的。然後編輯,加入以下的內容:
;pathname of Lisp executable file, to run an inferior lisp process
(setq inferior-lisp-program "C:/home/bin/clisp/full/lisp.exe -B C:/home/bin/clisp/full -M C:/home/bin/clisp/full/lispinit.mem -ansi -q")

(add-to-list 'load-path "C:/home/bin/emacs/site-lisp/slime/")
(require 'slime)
(slime-setup '(slime-fancy))

以分號開頭的是註解。
inferior-lisp-program那一行,是設定你的lisp的執行檔與參數。參數是從網路上找來的
load-path那一行,將slime的路徑加入。
require跟slime-setup那兩行,是要Emacs載入SLIME。詳情可看這裡

怎麼執行呢?在Emacs下鍵入M-x slime(M代表Alt鍵,M-x表示按著Alt不放,然後按x,然後輸入slime,按Enter)。如果沒問題,應該就會看到以下的畫面。

這是SLIME的REPL,你可以看到buffer的名字是*slime-repl clisp*,在這裡就可以輸入各種lisp expression並作evaluation了,REPL的指令請看這裡

剛剛執行M-x slime,slime會進行以下的動作,先啟動在.emacs設定的lisp系統(在Emacs->Buffers會看到一個*inferior-lisp*);還有一個叫做"Swank"的server,並建立起Swank跟inferior lisp之間的連線,然後開啟一個REPL。

恭喜你,已經有完整的lisp開發環境了。

對了,剛剛不是裝了三套lisp系統嗎?
請在.emacs把inferior-lisp-program那一行換成這個:
(setq slime-lisp-implementations
'((clisp ("c:/home/bin/clisp/full/lisp.exe" "-B" "c:/home/bin/clisp/full" "-M" "c:/home/bin/clisp/full/lispinit.mem" "-ansi" "-q"))
(sbcl ("sbcl"))
(ccl ("C:/home/bin/ccl/wx86cl.exe"))
))

如果直接打M-x slime,預設會執行第一個lisp系統,也就是clisp。
如果打M-- M-x slime,然後輸入clisp or sbcl or ccl,就會執行指定的lisp系統。

哇,好棒,想開始使用SLIME的slime-mode有哪些指令可以用,就看這裡吧

參考文件:
1. Installing CLISP, Emacs, and SLIME on Windows XP from What’s In Peter’s Head。
2. Installing SBCL, Emacs, and SLIME on Windows XP from What’s In Peter’s Head。
3. SLIME User Manual from the offical website.
4. SLIME-HOWTO from Cliki

學習lisp :
1. Practical Common Lisp by Peter Seibel
2. The Common Lisp Cookbook
3. Structure and Interpretation of Computer Programs video lectures by Hal Abelson and Gerald Jay Sussman
4. Berkeley The Structure and Interpretation of Computer Programs by Satish B Rao and Brian HARVEY

GNU Emacs on Windows

問:這篇要講什麼?
答:要講如何在Windows XP上使用GNU Emacs,主要是給程序員看的。我的電腦是Windows XP。

問:為什麼?Emacs這個古董不是很難用嗎?
答:雖然常常聽說Emacs很難學難用,卻是功能最強大的編輯器,也是程序員終極的工具,所以我就想說用用看囉。

這是GNU Emacs的logo。


問:你欠揍嗎?難用還用?
答:或許吧,別打我臉啊~不~哪裡都別打~。

問:Emacs到底是什麼東西?
答:很難解釋,讓我試試看。Emacs是個功能超強大的編輯器,但這不是重點,重點是它的擴充延展性超強,任何人都可以在上面“開發”,所以有人說Emacs是一個完整的開發平台,可以跟火狐Firefox對比一下,任何人都可以在上面開發各種功能的外掛;一般普通的編輯器(或是其他軟體),如果沒有某項功能,你就無計可施,如果某項操作行為不合你意,你也莫可奈何,如果是功能強一點的編輯器,會提供很多設定參數讓你修改,譬如修改各功能對應的快捷鍵;但在Emacs上,遇到這樣的情況,你都可以自己動手寫程式加功能進去,或者修改原有的操作行為,譬如說寫程式時,關鍵字、變數函數名稱、字串、註解等等你希望用不同顏色顯示,你就可以自己寫出這樣的功能;其實既然可以在其上寫程式,那你想要什麼功能都是可以辦得到的,譬如執行shell、讀寫email、呼叫外部程式(例如compiler、spell checker)、科學計算機、甚至瀏覽器都可以。

這種可以讓使用者自己“擴展、延伸”原有軟體功能的特性,在其他軟體也可以看得見,Firefox的外掛就不用說了;還有Microsoft Excel,你可以因特殊需要來寫數學運算式;很多編輯器也都可以錄製巨集,把一連串的指令錄下來,重複使用節省操作時間。

累了嗎?打打打俄羅斯方塊吧。

在Emacs裡面顯示圖檔。

當然別忘了寫程式喔,詳細看看這張圖,其中有寫程式的、有列出目錄檔案的、有執行shell的、有列出函式清單等等,甚至可以執行版本控管指令(cvs, svn...)。

問:可是我不想開發那些功能啊?
答:Emacs已經有三十多年的歷史了,很多功能都已經開發出來了,一般來說你不必擔心,只要找一找,應該都有你想要的外掛功能。想想看Firefox上面豐富的外掛吧。

哇,編輯LaTex耶,好棒。

問:哦,那如果沒有呢?
答:那就要用Emacs的開發語言"Emacs Lisp(elisp, Elisp)"來撰寫,elisp是Lisp程式語言的一個分支,時至今日其主要用途就是在Emacs上開發各種功能,事實上,Emacs的核心部分是以C撰寫,其他大部分都是以elisp撰寫;所以如果沒有你要的功能,也沒有別人要開發的話,請你自己寫吧。本篇不介紹elisp。

問:聽起來很不錯,但是,看圖、打遊戲、讀email,我只要另外執行一支軟體不就得了,為什麼一定要在Emacs內執行?還有,你說的很多編輯功能,我的編輯器也都有啊?
答:是的沒錯,但我上面說的重點是:Emacs是個強大完整的開發平台,發現不足時,就會有人開發各種外掛,這是某些編輯器沒辦法做到的。

而上面強調說“你可以在Emacs裡面做任何事!”,你可能看不出有什麼好處,讓我解釋一下其中的歷史背景,在很久很久以前,沒有『視窗介面』的那個時代,你執行編輯器寫程式,寫一寫離開,執行compiler,在shell下執行程式看看結果,然後再回去編輯器修改,累了就執行email軟體,或是西洋棋,這樣跳來跳去很麻煩,因為整個畫面會被你的軟體佔據,不像現在一個軟體有自己的一個視窗,所以自然會產生希望“一支軟體通吃”這樣的想法;雖然後來這種文字命令列模式也發展出很多機制(譬如同時使用很多個終端機畫面,還有screen這隻程式讓你在多個軟體間跳來跳去)來因應,但對於習慣視窗圖形化操作介面與滑鼠的人來說,那些機制都不夠便利,所以“你可以在Emacs裡面做任何事!”對於以前在命令列下工作的人來說是一大福音,但現在我們在各種環境(Windows, Mac, Linux...)都有圖形化操作介面了,所以這點已經不是那麼有吸引力了。

不過再強調一下,因為Emacs是個強大完整的開發平台,如果你願意學習elisp,那你可以把Emacs調整成你最喜歡的樣子,如果你不願意,也可以找到一堆別人開發出來好用的外掛。


想想看以前沒有滑鼠的時代(嗯,好像很難想像),Emacs是那種時代的產物,所有的動作都要用鍵盤完成,想想看,你要把一整塊文字做搬移的動作,沒有滑 鼠游標可用,只有鍵盤要怎麼達成,很難吧;而且,Emacs還有個中心思想:讓雙手保持在打字區,利用各種按鍵組合完成任務,減少把手移動到鍵盤右邊(上 下左右方向鍵、編輯鍵Delete、Page Up、Home)的機會,所以要記憶很多按鍵組合。結論就是,對於習慣滑鼠操作的人,Emacs以鍵盤為主的操作方法很古老很難學。

有了視窗介面與滑鼠,就不需要記憶一堆指令與參數;現代人用電腦時大部分時間都只需要瀏覽器與滑鼠。

問:好吧,那麼Emacs都有三十多年的歷史了,說些故事來聽聽吧?
答:這就免了吧,可以拜拜孤狗大神,或是查查維基百科吧。

問:難道都沒有其他同等的好產品嗎?
答:有的,但每個人都有不同的看法。有人不管什麼程式語言都用UltraEdit,我以前在寫C/C++時,用的是Source Insight,但我很多同事都是用SlickEdit,當我在寫簡單的Java程式時,用的是TextPad,但現在開發Java的首選Eclipse,另外還聽說TextMate(Mac)與E Text Editor(Windows)很棒(聽說其外掛能力也很強大,但我只有些許的使用經驗),我最近寫簡單的程式時,都是用NotePad++,寫大程式是用Visual Studio(Windows)與Xcode(Mac),在unix上我還用過joe與pico,但資深的都用vi或emacs;如果你問其他人,這份編輯器清單會長到不像話,編輯器之優劣爭論似乎跟程式語言優劣爭辯一樣,永無止息之日,所以就此打住。

這張圖是Source Insight,是我第一個接觸到功能夠強大的編輯器,改用Source Insight後就再也不可能回到Visual C++ 6.0的編輯器了。

問:那你用Emacs是為了什麼?
答:雖然理想上我們希望一支編輯器走遍天下,但現實上,不同的情況會有不同的最佳選擇。而我用Emacs主要是為了學寫lisp程式(但非elisp而是common lisp與scheme),而寫lisp程式最好的開發環境似乎就是Emacs。所以我會另外寫一篇關於在Windows上安裝common lisp系統,以及SLIME(輔助開發的Emacs外掛)。

問:除了Emacs就沒有其他選擇來寫lisp程式嗎?
答:當然有,Lispboxvim+limpLispIDEJabberwocky Cusp on Eclipse。有空就自己試試看囉。

問:我不需要寫lisp,我的編輯器也夠強,我不想學Emacs,再見。
答:不送了。

問:好吧,我想用看看,聽說Emacs有很多版本?
答:Emacs有很多版本分支,例如GNU Emacs、XEmacs、Aquamacs等等,這篇用的是GNU Emacs on Windows。另外在Cygwin上也有GNU Emacs,但我用了覺得怪怪的,譬如一開始居然沒辦法關掉程式離開。

問:去哪下載?
答:在官方網站的下載區,可以下載原始碼,不過編譯好的Windows版已經準備好了(不支援95與NT之前的版本)。目前(寫這篇的時候)最新版本是23.2,進去後可以看到兩種檔案,一種是emacs-23.2-barebin-i386.zip,裡面只有編譯過後的執行檔,沒有elisp code以及一些文件,不是我們要的;另一種是emacs-23.2-bin-i386.zip(43 MB),這才是完整的。

問:怎麼安裝?
答:安裝只需把檔案解壓縮即可,但解壓縮後的目錄名最好不要有空格或太長,避免發生一些奇怪的問題。因為Emacs以及相關軟體都有很深的unix背景,為避免麻煩,我採用無空格的目錄名。還有,為了配合unix的一些習慣,我在C:\下新增了一些目錄:
C:\home
C:\home\bin
C:\home\bin\emacs (Emacs放這裡,我把解壓縮後的目錄名emacs-23.2改成emacs。)
C:\home\yehnan (這是我的使用者目錄)

PS 因為我之後還要安裝lisp systems,所以才會有這些目錄,如果你不需要,只要把Emacs解壓縮到任何一個地方即可。

然後執行C:\home\bin\emacs\runemacs.exe,哇,出現了。自己拉個捷徑到桌面吧。注意,不是emacs.exe,其實也可以,但會多出一個沒用的命令列視窗。
沒錯,不用安裝,Emacs也不會在其他地方產生奇奇怪怪的檔案,你甚至可以把Emacs放進隨身碟帶著走,沒有問題。

如果你想要文字模式的話,在命令列模式下輸入c:\home\bin\emacs\bin\emacs -nw即可。

問:我改變心意了,怎麼解除安裝?
答:把剛剛那些目錄通通砍掉,還有你建立的捷徑,這樣就好了。

問:接下來呢?怎麼用?
答:嗯,你可以看看Emacs Tutorial(Emacs快速指南),就在Emacs的開始畫面上;或是GNU Emacs Manual(官方手冊),可以線上閱讀或是下載;或是看本書Learning GNU Emacs 3/E,這本書我只有大概翻過,覺得還不錯。

問:這些文件怎麼看起來怪怪的?
答:我覺得Emacs官方寫的文件都很奇怪很囉嗦,因為:

第一,寫的人把用的人都當做初學者,沒有使用編輯器的經驗、甚至沒有使用電腦的經驗。看看這段話:
"Files are named units of text which are stored by the operating system for you to retrieve later by name.",拜託,我還需要你教我“檔案”是什麼東西嗎?

第二,寫文件的人似乎停留在1980年代,裡面很多術語都很老舊了,看看這個:
" We use the term frame to mean the entire terminal screen or graphical window used by Emacs."、"The main area of the frame, below the tool bar (if one exists) and above the echo area, is called the window.",哇哩咧,你的frame是我的window,你的window又是什麼鬼?

第三,寫文件的人還在緬懷以前的時光,有些在以前算特殊的功能,已經不再特殊了,例如:
"You are reading about GNU Emacs, the GNU incarnation of the advanced, self-
documenting, customizable, extensible editor Emacs.",啥?self-documenting?哪個編輯器沒有說明文件啊?extensible, customizable?現在很多編輯器多多少少都可以客製化了。

第四,有些功能太過強大,所以解釋起來很麻煩:
"You can yank text from the kill ring into any position in a buffer, including a position in a different buffer; the kill ring is shared by all buffers.",yank&kill在這裡等於cut&paste,而kill ring呢?大概是指你cut好幾次後,不會只剩下最後一次cut的東西,之前的都還在kill ring裡面。

第五,因為Emacs以鍵盤為主,雖然現在有滑鼠可以用了,可是其中心思想還是要求所有的功能動作都要能用鍵盤達到,以至於像“把一段文字圈選”這種以滑鼠可以輕易達到的功能,手冊要用好多篇幅講解鍵盤的指令。譬如說:
"Setting the mark at a position in the text also activates it. When the mark is active, Emacs indicates the extent of the region by highlighting the text within it, using the region face. After certain non-motion commands, including any command that changes the text in the buffer, Emacs automatically deactivates the mark; this turns off the highlighting. ",什麼鬼啊,滑鼠點一點拉一拉就好了啦。

傳說中,能學會Emacs眾多指令的人,可以得到美女的青睞。真的還假的啊?

我會建議你找找網路上的入門介紹,比較快上手,要詳細一點的話Learning GNU Emacs應該是本不錯的書,至於我嘛,我把GNU Emacs Manual當做參考手冊,不會一頁一頁看,而是碰到問題再去裡面找答案。而我接下來要做的就是幫你入門,介紹一些基本觀念。

注意:老實說我不熟悉Emacs,我只是將一些基本的東西寫下來,能夠用就好,慢慢地再去學高階一點的功能與用法。我使用Emacs最主要的目的是要寫lisp程式,並不打算將Emacs當做我唯一的編輯器。

問:首先講解一下畫面上的各個區域吧?
答:
首先,你看到的整個畫面,稱之為frame(一般的術語會稱之為window視窗),
然後在上面有一條Menu Bar(選單列,File Edit Options Buffers Tools Help),
然後是一些常用功能的Tool Bar(工具列),
最下面那一條叫做echo area(目前顯示著"For more information about GNU Emacs...");
在Tool Bar下面、echo area上面的整個區域稱之為window,是用來顯示編輯內容,window還包括灰色的那條Mode Line

重點:Emacs把整個畫面叫做frame,把編輯一個檔案的地方叫做window。



問:好,接下來,怎麼新增檔案、開啟舊檔?
答:
方法一:用滑鼠把檔案從檔案總管拖曳進Emacs的畫面。
方法二:使用File->Visit New File...,新舊檔都可以。
方法二:使用File->Open File...,開舊檔。

稍微介紹一下“visit”(Emacs術語),意思是,產生出一個新的buffer,把檔案內容拷貝進去,然後把buffer內容秀在window上。接下來你就可以編輯了。

重點:所謂buffer就是一塊記憶體,Emacs把放檔案內容放進去讓我們編輯。


這裡要解說一下那條灰色的Mode Line。
最左邊的“-”,無意義。
左邊數來第二欄,代表編碼系統(Coding System)。如果是“-”,大概代表“undecided”或是“us-ascii”,表示英文,如果是“B”,代表“chinese-big5(cp950)”,表示中文,這是中文版Windows預設的編碼,如果是“U”,表示unicode,可以把滑鼠移到上面,會出現一些資訊;通常我們都不用去管,Emacs都可以正確判斷與處理。
左邊數來第三欄,代表End-Of-Line。如果是“\ or DOS”表示CRLF;“/ or Mac”表示CR;“: or Unix”表示LF。如果忘記了,就把滑鼠停在上面,會顯示資訊給你看。通常我們也不用管這個。
左邊數來第四欄跟第五欄,第四欄表示buffer是否唯讀,第五欄表示buffer是否有被修改(跟檔案內容不一樣了),“--”表示buffer未修改,“**”表示buffer有修改,“%*”表示buffer雖是唯讀但有修改,“%%”表示其他狀態。
左邊數來第六欄,通常是“-”,滑鼠停在上面會顯示檔案路徑,如果路徑是在遠方機器上,會顯示“@”。

好吧,你是不是頭昏眼花了,其實上面這些,通常我們都不用管,而且你把滑鼠移上去就知道了,不需硬記。

然後是buffer名稱,通常跟檔案名稱一樣。但有時候你會看到*Message*、*scratch* 、*GNU Emacs*、*Help*等等,這些有星號的buffer,都是Emacs內部會用到的,不用管他也不用急著把他們關掉。譬如你在echo area會看到很多訊息,這些訊息也會寫入到*Message*內。

然後是位置資訊,可能是“All or Top or Bot or nn%”,看就知道了。
然後是游標在第幾行,Lxx。

然後是所謂的Major Mode一些附加資訊(如果有的話),所謂major mode就是根據你在編輯的文件種類的不同,設計的編輯模式,例如“Text”、“HTML”、“Fundamental”、“C”等等。

然後是一連串的“---”,把滑鼠移上去會發現可以對window調整大小、放到最大、或移除掉;自己試試看就清楚了。

問:怎麼儲存檔案、另存新檔?
答:請問File->Save或是File->Save As...。

問:開了很多檔,到底有多少buffers啊?怎麼切換?
答:到選單Buffers就可以看到全部的buffers,點選就會切換。

問:怎麼把frame分割成多個windows用來分別顯示不同的buffers?
答:File->Split Window,可以上下分割。至於要左右分割的話,Emacs沒有把這個命令放到選單內,所以,我們終於要輸入Emacs指令囉,

左右分割的指令是“C-x 3”,C代表Ctrl,C-x代表按住Ctrl不放的同時按下x,然後放開,再按3。

任何時候,如果發現輸入指令有錯,可按C-g取消,或是按兩三次的ESC。

問:怎麼把window移除?
答:在mode line上按滑鼠右鍵即可。雖然把window移除,但buffer還是存在的。

問:那怎麼把一個buffer關閉?
答:File->Close。

問:我打錯東西要按C-z取消,怎麼反而把Emacs縮到最小了?
答:想要做undo(一般軟體都以C-z表示),Emacs的指令是C-/。

問:怎麼C-c、C-x、C-v不是複製剪下貼上啊?
答:可以到Options->C-x/C-c/C-v Cut and Paste (CUA),打開這個模式即可。

問:怎麼搜尋?
答:C-s往下尋找,C-r往上尋找。

問:那怎麼把Emacs關掉?
答:按整個畫面右上角的叉叉,或是File->Quit,如果有未存檔的buffer,會詢問你。

問:那接下來?
答:接下來就靠你自己了,我不是Emacs高手,只是因想寫lisp程式需要用Emacs,所以把初步介紹寫下來,下面有一些參考文件,可以作為你的下一步。

聽說Emacs很難學是不是真的啊?不是,正確說法應該是:很詭異。

參考資料:
1. GNU Emacs Manual
2. GNU Emacs FAQ For MS Windows
3. Xah's Emacs Tutorial
3. 炎龍的筆記本
4. Emacs 初學者

2010/06/14

Joel Spolsky on Software文章選

不知道是從什麼時候開始讀Joel Spolsky(周思博、約耳)的文章,還記得一開始看的是中文翻譯『周思博趣談軟體』,後來開始看原文部落格Joel on Software這裡有另有各種語言的翻譯),幾乎每篇都不放過,對他的文章與意見,我從崇拜學習到有贊成有反對,惠我良多,可惜的是在三個月前,Joel宣布不再寫部落格了(不過好像會找其他管道作另一種形式的發表),心中升起一股淡淡的哀傷感;為記錄我的一些感想,選出以下的文章,並寫下我的意見與感想。



這裡有Joel的背景介紹,簡單講就是耶魯大學畢業,在Microsoft、Viacom Interactive Services與Juno Online Services工作過後,與夥伴在紐約創立Fog Creek Software至今,其產品包括FogBugz(專業管理與臭蟲追蹤)、Fog Creek Copilot(遠端控制電腦,可穿過各種防火牆與NAT)以及其他軟體。過去十年來Joel寫過超過1000篇的文章,討論軟體開發、專案管理、軟體與商業與電腦科學等等,Joel的網站聽說是每個寫程式的、搞軟體的定期都要拜訪的。


以下是我挑的選輯,以及我的感想與看法並配上一幅漫畫。另外有點要事先聲明,有些文章都好幾年前了,有些內容仍然擲地有聲,但有部分或許以現在的觀點看來已經過時或是老掉牙了,甚或你會覺得不正確了,希望你可以想像當年的時空背景,發掘其內涵。我依照我的想法把內容有關連的放在近一點的位置,所以不是照發表日期排列。



Five Worlds,2002.05.06:
斯斯有兩種,軟體不只兩種,這篇文章將軟體分類為五種,五這個數字不是絕對的,重要的是要搞清楚你是在哪個領域開發何種軟體,誰會是使用者,搞錯就好像穿西裝去運動場,格格不入。這裡要注意的是,Joel的領域是他文中所謂的shrinkwrap軟體,是要賣給很多人的那種,當看Joel的文章時,要把這點謹記心。


User Interface Design For Programmers(共九篇),2000.04.10:
這是給軟體工程師看的使用者介面設計的入門手冊,道理雖淺但不可不知。摘錄一段:
人的資質分佈是個鐘型曲線. 你的客戶可能有98%夠聰明到能使用電視機. 大約70%能使用Windows. 有15%能使用Linux. 只有1%能寫程式. 不過卻只有0.1%能用C++之類的語言寫程式. 而只有0.01%能攪懂Microsoft ATL程式設計 (而且他們都留鬍子戴眼鏡, 沒有例外.)


The Joel Test: 12 Steps to Better Code,2000.08.09:
想增進軟體開發的效率嗎?要怎麼評量一個軟體開發的環境呢?這十二項是個簡單又具關鍵性的指標。


Daily Builds Are Your Friend,2001.01.27:
所謂"build是指將原始程式碼經過一連串的程序轉成最後的產品,隨時保持整個軟體專案在可build可執行的狀態是很重要的,人越多就越難達到,如果壞了造成的損害也越大,開發的人就沒辦法把新增修改的部份放上去,也沒辦法抓到最新狀態的程式。


Painless Functional SpecificationsPart 1, Part 2, Part 3, Part 4),2000.10.02:
你覺得寫規格書是個惡夢嗎?不知道怎麼寫,寫了沒人看,不斷地要求修改,到底為什麼呢?


The Iceberg Secret, Revealed,2002.02.13:
不論你在什麼職位,你一定有"客戶",可能是上司、主管、同儕、買家,你寫的程式總會有人要用要看要測試要審核,這篇告訴你一個秘密,客戶不知道他們想要的是什麼,千萬別預期他們能夠告訴你;文中有更多的探討與因應對策。


Top Five (Wrong) Reasons You Don't Have Testers,2000.04.30:
凡實驗必有誤差,凡程式必有bug,就我所知,號稱自己寫的程式絕對沒有臭蟲的人好像只有Linus Torvalds(linux kernel的爸爸)而已,所以,測試吧!


A Hard Drill Makes an Easy Battle,2001.11.20:
Windows有這麼多版本怎麼辦?不要以為你用的是Win32 API就可以通吃,沒測過到時候就會出現一堆奇奇怪怪的問題,測試吧。雖然這是篇很早的文章,講的是在Windows上開發軟體,但看看今日的狀況,這麼多不同血統的瀏覽器與版本,可供借鏡。


Painless Software Schedules,2000.03.29,Evidence Based Scheduling,2007.10.26:
開發進度的追蹤,是件極度不可能的任務,最常見的狀態就是不斷的delay,有人說訂schedule的意義就是用來delay的。


Painless Bug Tracking,2000.11.08:
軟體工程師不只是一直寫程式寫程式,事實上,根據統計,花在debug的時間反而是最多的,所以花點時間想想該怎麼做臭蟲追蹤吧。


Making Wrong Code Look Wrong,2005.05.11:
寫程式是件困難的事情,要盡力把各種阻礙除去,降低寫錯的機率以及提高除錯的效率與可能性,譬如採取一套正確的命名法可以幫助我們看出寫錯的程式碼,文中也點出,如果同一行程式碼可能會有不同的行為(技術上叫做context-sensitive),譬如overloading,有些程式碼的行為需要參考更多其他程式碼才能得知,譬如exception,都應該令人擔心,使用上要非常注意,因為會大大提高修改與維護的困難度。


Getting Things Done When You're Only a Grunt,2001.12.25:
就算你只是個大組織中的小螺絲,還是有很多事情你可以做可以努力,以個人的力量來讓整個專案與團隊變得更好。


How to be a program manager,2009.03.09:
你從小工程師晉升到軟體專案的管理者嗎?你知道專案管理需要哪方面的知識與技巧嗎?看這篇就對了。


The Development Abstraction Layer,2006.04.11:
不是會寫程式就能夠成立一家軟體公司的,除了技術還需要什麼呢?


Fire And Motion,2002.01.06:
一個簡單的概念,但卻不可不知,要不然被人牽著鼻子走(不斷地追求新技術)卻不知向何方而去。


Three Wrong Ideas From Computer Science,2000.08.22:
盡信書不如無書,有些不知不覺中形成的映像,有些約定俗成看似大家都同意的概念,其實可能是錯的,譬如這裡有分散式計算的一些錯誤假設,這本書講軟體工程的謬論,這篇提出三個電腦科學看似正確卻有問題的觀念。


The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!),2003.10.08:
現代人不可不知Unicode、character set、encoding、code page、UTF8、UTF16、ASCII等等,這篇算是初階入門的文章,讓你有個簡單清楚的開始。


Platforms,2002.08.30:
有些人寫的軟體是"平台",其真正的目標對象應該是"寫程式的開發人員",而非一般的使用者,但有人(或公司)搞不清楚這點,以致於其平台無法成功。


The Law of Leaky Abstractions,2002.11.11:
整合開發工具、高階語言、低階語言、作業系統、軔體、CPU與memory、電子電路、量子力學、等等,一層一層堆砌起來的技術,經過一道又一道的抽象化手續,讓你產生錯覺,誤以為底下住著一隻精靈,有如魔術般地忠實完成你提出的需求,可是,萬一有一天,某一層有破洞,地底妖魔跑出來大亂天下,怎麼辦呢?


Lord Palmerston on Programming,2002.12.11:
很久很久以前(我指的是Peter Norton那個年代),你只要讀完一本書,大概就可以動手開發軟體了,現在,想的美喔,你要花上大把大把的時間在一拖拉庫的"物件"上打轉;有人說可以在一星期學會某某語言,但是,那又如何呢?


Can Your Programming Language Do This?,2006.08.01:
工欲善其事,必先利其器。有時候要回過頭重新檢視一下寫程式最重要的工具:程式語言,其優劣如何,是否是最適合目前工作的選擇。


How Microsoft Lost the API War,2004.06.13:
Win32 API一度是王者,造就了Windows平台上各式各樣的軟體可用,但漸漸地失去了風采,原因是什麼,因為網際網路浪潮是擋不住的嗎?難道Microsoft都沒有做任何努力?WinForm、.NET 1.0 1.1 2.0...、Avalon、Visual Basic .NET各種新的技術都無所用嗎?看看這篇吧。


Biculturalism,2003.12.14:
解釋windows一方的文化與unix一派的文化之間的不同與差異,既然用到"文化"這個字眼,沒有對兩方都有一定程度的了解是無法做出公平客觀的評價的。


The Perils of JavaSchools,2005.12.29:
談論美國電腦科學系所改採Java當做的教學語言所造成的傷害。文中論及,Java並不適合,不夠難,沒辦法在學生中區分出一流與二流的程式員;教OOP也不是,學校教的OOP只是記憶一堆術語,諸如inheritance、encapsulation、is-a vs has-a、polymorphism等等;不是說這些東西不該教或不用教,而是真正電腦科學該教的重點是proofs (recursion)、algorithms(recursion)、languages(lambda calculus)、operating systems (pointers)、compilers (lambda calculus),真正該建立的能力是同時能以多層的抽象化方式來思考問題,有興趣的看看MIT教授在二三十年前的教學錄影,或是這裡也有Stanford最近的上課錄影,看看他們對電腦科學一年級生教些什麼。


Strategy Letter II: Chicken and Egg Problems,2000.05.24:
先有雞還是先有蛋,這問題不妨無著邊際討論一番,但是,這問題萬一發生在你的產品上,那該怎麼辦?譬如你要賣手機平台,如果很多消費者買,那就會吸引很多開發者寫軟體,如果很多開發者寫軟體,那就會吸引很多消費者買,沒完沒了,變成雞蛋問題。


Strategy Letter VI,2007.09.18:
隨著CPU越來越快,memory越來越大,寫程式似乎不需要在意效能了,錯了,新的戰場是在瀏覽器上跑著JavaScript的AJAX程式,依然還是有限制條件,網路頻寬與執行效率,但是,歷史會一再重演,有人汲汲營營於效能,有人忽略這些會被時間解決的問題(或者說,會有其他人出來解決),盡力地寫出功能更多更好的應用軟體,你覺得以長期而言,誰會贏呢?


Why are the Microsoft Office file formats so complicated? (And some workarounds),2008.02.19:
以銅為鏡,可以正衣冠;以史為鏡,可以知興替。但世界變化的這麼快,技術演進的這麼迅速,連讓人喘口氣小憩一會兒的工夫都沒辦法了,哪來的時間讀歷史故事啊。雖說如此,但如果不了解一些技術的背後理念,不清楚前人作法之後的歷史因素,有些事情就很難理解。這篇敘述了Microsoft Office檔案格式看起來這麼古怪的原因。


Martian Headsets,2008.03.17:
闡述為什麼web發展到今日的局面,網站與瀏覽器之間多對多的關係,致使開發網站很困難,開發瀏覽器也很困難,原因就是沒有一個標準,啥?沒有標準?明明有W3C的HTML啊,錯了,看起來是,但其實沒有,原因詳見內文。



這只是我的選輯,事實上,還有很多好文章我沒有挑選進來,如果你覺得有遺珠之憾,請寫在留言板,謝謝。你可以到Joel Spolsky的網站去找其他文章,有以主題分類好了。