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的網站去找其他文章,有以主題分類好了。

2010/06/13

回憶起一次出包經驗

很久很久以前,工作內容是在手機平台上寫程式,曾經出過一次包,當時六神無主,手足無措,因為執行到我的程式就當機,更慘的是一點概念都沒有,不知道哪裡錯了,一當機就驚醒我夢中人,嚇的我屁滾尿流失了魂,。

後來,光用看的看不出所以然,就把改過的跟原來正常的版本作比較,但也還是不知道錯在哪,於是出動硬體偵錯的工具,邊執行邊追,一行一行追,終於得知問題所在。

錯在compiler/linker身上。你相信嗎?

我有些global static的資料,應該要對齊(align)偶數的記憶體位址的,但卻沒有,所以存取時就會發生bus error

我的天啊,segmentation fault倒是很常見,指標沒弄好就會存取到不該存取的記憶體,可是bus error,講正確一點是unaligned access,有學過沒看過,真是讓我學到一課啊。

後來跟幾個同事討論,雖然知道這是個compiler/linker的bug,但我們也不能去修改這些工具,所以解決方法就是改用別的方法,避開這個問題。我又想,怎麼只有我出現這個問題,把所有程式碼都掃一遍,卻這麼剛好,只有我用的寫法剛剛好compiler/linker會產出錯誤的程式碼,真是夠了。

2010/06/12

回憶起一個很難抓的臭蟲

很久很久以前,那個時候沒有iPhone、沒有Android、iPod還很大一台的時候,記得當時我的工作是在手機平台上寫程式,已經算是半熟的新人了,對於整個系統有了初步的掌握,已經可以愉快地獨自工作,不用別人的幫忙了。後來進來了一個新人,本來他跟我不同小組,不太會有交集,但同為年資最少的菜鳥,有幾個禮拜的時間我們倆被叫去品保部門支援,起初我有點小小不高興,認為那是苦力工作,不過上級有令只好遵從,我叫咱們是悲情苦命小工程師,不過後來發現那是段很不錯很有用的經驗,至少去支援的時候認識幾個正妹,嘿嘿;總而言之,在如此的因緣際會之下,後來他常常找我去幫他除錯抓臭蟲(debug),因為實在太沒效率(聊天太大聲)、浪費人力(兩人解一題)而且又跨界管事(有應該帶他的人),沒多久就被我主管禁止,雖然大部分的問題都是因為他還不熟平台以及各種API,但還是有少數幾個很難解的bug,以下就是其中之一。

聽說"debug"這個詞的由來,是真的在電腦裡面找的一隻蟲(bug),哇!


他開始負責維護安全認證方面的程式碼,譬如SIM卡可以設定密碼,開機時要輸入,不然就只能打緊急電話(No SIM),而且打錯太多次,SIM還會被鎖起來。其實功能大體上都好了,不過還有bug,帶他的人就交給他解解看,說了這麼久,到底是什麼bug呢?

BUG:開機時輸入正確的SIM卡密碼,有時候正常開機,有時候卻整個重開機。

哇哩咧,老實說,以我多年闖蕩江湖上斬北海蛟龍下劈南山猛虎的輝煌戰績看來,這種bug最難解的啦!有時候出現,有時候不出現,羚羊掛角,無跡可尋,搞不清楚狀況,一整個完蛋。

SIM卡小小一片,讓你幾乎讓了它的存在。


還好小弟在下不才我是有練過的,劣者我用壞螢幕的速度可追讀書破萬卷的杜甫,打爛鍵盤的數量可比寫黑一池水的王羲之;我一試之下果然有鬼,手機時好時不好,腦中閃過幾個可能,然後再看看程式碼,心理已經有個底,於是乎我告訴他說:我抓到規則了,只要你開機,看到輸入密碼的畫面就用很快的速度輸入密碼按確定,那就有可能會重開機,可是如果你等個幾秒鐘,然後才輸入按確定,那就平平安安。哇賽,真是太佩服我自己了,然後就跟他說只能幫到這回座位了,留下他一臉狐疑直說怎麼可能會這樣,慢慢苦戰吧,呵呵。

金田一跟柯南到底誰比較強啊?我以我爺爺的名號發誓,真相只有一個!如果debug能夠跟他們倆解謎一樣厲害,那就好囉。


那到底原因是什麼呢?還好我有看過Scott Meyers的Effective C++: 55 Specific Ways to Improve Your Programs and Designs,知道裡面有這麼一條寫著:the relative order initialization of non-local static objects in different translation units is undefined,啥?

PS 在這本書第三版出現在Item 4,第二版出現在Item 47。

用書中的C++例子來說明:


class FileSystem { ... };

FileSystem theFileSystem;

在某個檔案定義了一個類別FileSystem,並且有一個global static的物件theFileSystem。

然後在另外的檔案:

class Directory {
public:
Directory();
...
};

Directory::Directory()
{
//會使用theFileSystem這個物件
}

Directory theDir;

同樣也有一個global static的物件theDir,而且這個物件的constructor需要用到另一個global static物件theFileSystem來做初始化的動作,問題是,你怎麼知道theFileSystem會在theDir之前就先準備好呢?

答案是:你不能,theFileSystem跟theDir,皆為non-local static物件,其執行各自的constructors的順序是沒有定義的。所以當theDir執行constructor時,如果theFileSystem還沒,那就當然會當機或重開機了。

所以我猜,當手機開機開到輸入密碼時,背景其實還在跑很多其他的東西,此時如果快速輸入密碼按確定,就有可能會去用到還沒有準備好的物件,造成重開機;但如果等一等,那就沒事。

哇,這真是太神奇了。

至於怎麼解決這樣的問題,那就請你看看書囉,好書,值得推薦,另外還有姊妹作More Effective C++: 35 New Ways to Improve Your Programs and Designs,學 C++不可錯過的著作喔。