摘要:Knuth在他的多卷書《電腦編程藝術》中向我們展示了電腦編程的技巧和藝術性,並在其圖靈獎演說中論述了電腦編程和藝術的關係。這篇文章受Knuth著作的啟發,進一步闡述為什麼電腦編程應該是一門藝術並通過代碼展示藝術的主要表現形式。
圖片來源:accidentally in code
1. 引言
"(program(computers) == *art) ? so : what"
“只有大約5%的程式員能夠在編寫代碼時創造出藝術。其他95%一定是為了取得成功的科學家,不是藝術家。”
談及“藝術”,人們自然會聯想到“美”、“技藝”、“靈感”等詞,但很少會把它和“電腦編程”這聽起來似乎無趣的詞聯絡在一起。而Donald Knuth,《電腦編程的藝術》多卷書的作者,通過他的著作,成功地展現了電腦編程的藝術。隨後他又在圖靈獎演說[1]中對電腦編程的藝術做了科學地論述和詮釋。他不是第一個這麼做的人,但無疑他是最成功的一個。Guido van Rossum,Python的設計者,如是說:
“我同意Knuth對‘藝術’一詞的定義(或使用)。對於我來說,它和創造性聯絡十分緊密,而這對於我的工作非常重要。如果(電腦編程)其中沒有藝術,它將沒有任何樂趣,而我也不會在30年之後仍然從事它。”
編寫優美的程式需要靈感和高超的技巧,就像詩人寫詩,畫家作畫,建築師構築,充滿了樂趣、挑戰和美。優雅的程式會像詩歌一樣耐人尋味,像名畫那樣大開眼界,像教堂一樣堂皇華麗。所以,電腦編程也同樣是一門藝術,程式員就是創造這種藝術的藝術家。
2. 編程之美
什麼樣的程式才是美的程式?這個問題似乎沒有完整的答案。一個很酷的Demo或一個很炫的視頻遊戲都能讓我們讚嘆不已。Doom和Half Life可以說把3D技術推向了極至,這種程式總能給人一種視覺上的美,就像畫家手中的美麗油畫,只是程式員們的畫布在電腦螢幕上,畫筆是鍵盤。Linux也是一種美,一種開放的美,從Unix那裡繼承來的優雅的設計,強大的可移植性,豐富的工具,這讓它看起來像優秀建築師們設計的一座富麗堂皇的教堂。這些美是顯而易見的。還有一種美,隱藏在程式背後,流動於原始碼之中。什麼又是美的代碼呢?可能它們一看上去就很美。這裡有一個驚人的宏定義的C代碼集合[2]:允許程式建立常量,使它們看上去像是螢幕上的圖形!程式的自描述能力大大加強!
#define X )*2+1
#define _ )*2
#define s ((((((((((((((((0
static unsigned short stopwatch[] =
{
s _ _ _ _ _ X X X X X _ _ _ X X _ ,
s _ _ _ X X X X X X X X X _ X X X ,
s _ _ X X X _ _ _ _ _ X X X _ X X ,
s _ X X _ _ _ _ _ _ _ _ _ X X _ _ ,
s _ X X _ _ _ _ _ _ _ _ _ X X _ _ ,
s X X _ _ _ _ _ _ _ _ _ _ _ X X _ ,
s X X _ _ _ _ _ _ _ _ _ _ _ X X _ ,
s X X _ X X X X X _ _ _ _ _ X X _ ,
s X X _ _ _ _ _ X _ _ _ _ _ X X _ ,
s X X _ _ _ _ _ X _ _ _ _ _ X X _ ,
s _ X X _ _ _ _ X _ _ _ _ X X _ _ ,
s _ X X _ _ _ _ X _ _ _ _ X X _ _ ,
s _ _ X X X _ _ _ _ _ X X X _ _ _ ,
s _ _ _ X X X X X X X X X _ _ _ _ ,
s _ _ _ _ _ X X X X X _ _ _ _ _ _ ,
s _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
};
這種只能在Usenet或混亂C代碼競賽中才能見到的代碼雖然沒有多少實際用處,但它的確能讓我們感受到代碼 —— 一堆有規則的符號 —— 也能創造出視覺上的美。也可能是程式使用的技巧 —— 演算法很美,就像漢諾塔程式,快速排序程式,自然而然地使用遞迴讓它們看起來很緊湊,易讀,這當然也是一種美,是只有程式員才能體會到的美。還有一種美,深藏在代碼之後,是程式的設計思想之美,一種需要領悟的美。Unix帶給我們的不僅是它的強大功能,還有它那深邃的設計哲學[3]:
“小巧就是美的。”(Small is beautiful.)
“讓每個程式都擅長做一件事。”(Make each program do one thing well. )
“一切都是檔案。”(Everything is a file.)
“沉默是金。”(Silence is golden.)
“讓作業系統核心小而輕巧。”(Make operating system kernels small and lightweight.)
這些思想在Unix設計中不失為黃金法則。這種美將穿越時空,千古流傳,讓Unix不僅僅是一個優秀的作業系統,而成為一門電腦領域的哲學。
人們都喜歡美的東西,程式員們更是珍視美的程式,我們把那些創造美好程式的人尊稱為“駭客”。 Paul Graham認為駭客和畫家很相似[4]:
駭客和畫家的共同之處是,他們都是創造者。和作曲家,建築師,作家一樣,駭客和畫家嘗試去做的也是創造好的東西。他們本身並不做研究,但是如果在創造好東西的過程中發現了一些新的技術,那就更好了。
好的畫家是藝術家,那麼好的程式員——駭客——也是藝術家。這也就不難理解為什麼很多Unix核心駭客都留著藝術家式的絡腮鬍了。
3. 編程之巧
靈巧的程式像含蓄的詩歌,需要仔細領悟,用心去體會,茅塞頓開後方能回味無窮。真乃“會當臨絕頂,一覽眾山小”!同樣是求pi,但是只有簡單的四行C代碼卻能列印出pi的前800位的程式定會讓我們大開眼界[5]:
int a=10000,b,c=2800,d,e,f[2801],g;
main(){
for(;b-c;)f[b++]=a/5;
for(;d=0,g=c*2;c-=14,printf("%.4d",e+d/a),e=d%a)
for(b=c;d+=f[b]*a,f[b]=d%--g,d/=g--,--b;d*=b);
}
駭客們不會墨守陳規,他們不斷地創新,尋找更巧的方法來解決同樣的問題。曾經流行編寫這樣一種程式,它能夠列印它自己的全部代碼。程式員們努力尋找最短的這種程式。這雖然沒多大實際用處,但是充滿了挑戰性,駭客們把這當作樂趣。看看下面的程式[6]是多麼怪異。
char *f="char *f= %c%s%c;main(){printf(f,34,f,34,10);} %c";
main(){printf(f,34,f,34,10);}
電腦編程迷人的很大一部分在於它需要高超的技巧,也正是這些技巧才使我們看到了美,從中得到了樂趣。而且,我發現,當限制增加時,技巧將會更高,樂趣也會隨之增加。來寫這樣一段程式,讓它在螢幕上列印1~1000之間的數字。這對於一個新手來說也是小菜一碟,一個for 迴圈就搞定。好,我們加一個限制,不許使用任何迴圈。這時你得動一番腦筋了,不過你還是會想到用遞迴可以完成。不錯,我們再加一個限制,也不許用遞迴。這可能把你難住了,你可能會認為不可能有這樣的程式,那看看下面的程式吧:
#include <stdio.h>
#define A(x) x;x;x;x;x;x;x;x;x;x;
int main (void)
{
int n = 1;
A(A(A(printf ("%d ", n++))));
return 0;
}
既沒有用迴圈,也沒有用遞迴,而是使用了宏!我們常常驚訝於世界各地著名的Warez組織推出的64k的3D動畫,那麼小的程式,往往有難以想象的效果。它們把64k的限制和彙編的威力運用到了極限,這種技術讓人歎為觀止。64k似乎並沒有限制住其藝術性,反而起了促進作用。並且,當你對系統有足夠的瞭解時,樂趣將會更多。因為你可以提示和系統開玩笑了,欺騙它,作弄它,甚至攻擊它。看下面的程式:
void main() {
int x;
x = 0;
x = 1;
printf("%dn",x);
}
想一想,如何才能讓程式跳過“x=1;”這一句而在螢幕上列印0?如果你對系統堆棧瞭解的話,你可能會給出類似下面的程式[7]:
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
int *ret;
ret = buffer1 + 12;
(*ret) += 8;
}
void main() {
int x;
x = 0;
function(1,2,3);
x = 1;
printf("%dn",x);
}
它利用了調用函數時堆棧的變化,改變函數的返回地址,跳過了“x=1;”這一句而直接執行下面的printf!它成功的欺騙了系統!如果把返回地址改成你預先放置的一段代碼的首地址,那麼你將會劫持系統,讓它運行你的那段代碼。如果那段代碼足夠巧,你將能獲得系統的完全控制權!這也是緩衝區溢位的基本原理。我想,這種技巧將會讓你興奮不已,絲毫不亞於陶醉在自己詩裡的詩人。我們已經看到:巧妙產生美,並與之形成藝術的雛形。
4. 編程之樂
電腦給人的樂趣在於,如果你有什麼好的想法,你可以馬上實驗去得到結果。當然,你可能不會立刻得到正確答案,而必須坐下來,盯著電腦螢幕,苦思冥想求解問題的有效方法,通過不斷的嘗試去驗證你的結果。可以通過找到正確的方法,使問題突然消失,也可以換一個角度,突然靈光閃現:原來是這樣!
編程是對創造力的訓練,好的程式員不會循規蹈矩,不會使用平庸的方法去解決問題,而是根據自己的見解去尋找更簡單的方法,因為他們能看到隱藏在問題背後的實質。然後他們會寫出全新而漂亮的程式去驗證他們的方法。“不過還是很難說清楚,閉門苦思冥想地要找到解決某個問題的漂亮答案,為什麼竟會有如此巨大的魅力。但是,你要是曾經有過找到更好方法的經曆,你就會明白,這簡直是無以倫比的感覺。”[8]這種感覺能讓我們快樂得像一個孩子,樂不知疲。
這種“無以倫比”的感覺,流動在程式員體內,讓程式員們為之癡迷,瘋狂。而癡迷的程式員從他藝術性的創造中得到了難以言傳的樂趣,並讓為之上癮。 Linux之父在他的傳記[8]中這樣談及他所體會的編程的樂趣:
編程給人帶來最初的興奮很好解釋:那就是通過編程你可以支配一台電腦,你叫電腦做什麼,它就做什麼,永遠準確無誤,而且毫無怨言。這本身就很有意思。
它比下棋之類的遊戲更有樂趣得多,因為它可以由你自己來制定遊戲規則。而你制定什麼樣的規則,也就會匯出與此規則相符合的結果。
在電腦世界中,你就是創世者,你對所發生的一切擁有最終的控制。如果你功力深厚,你可以是上帝——在一個較小的層面上。
無疑,樂在其中,外行人永遠體會不到,畢竟“子非魚安知魚之樂”。無窮無盡的樂趣讓程式員們模糊地體會到了作為藝術家的快樂,並且開始享受他們的工作。
5. 結論
Rob Pike曾悲觀地歎息:“那種藝術消失了。”[9]但是,我想當他看到諸如《組合語言的藝術》和《Unix編程藝術》之類的書時,他也會高興。這種藝術並沒有消失,而且還會流傳下去。我們不應該因“為藝術而藝術”而感到不好意思。正如Knuth所言[1]:
“我們已經看到,電腦編程是一門藝術,因為它把積累的知識應用於世界,因為它需要技巧和靈巧,尤其是因為它創造出了美的目標。模糊地意識到自己是一個藝術家的程式員將會享受他所做的工作,而且將會把它做得更好。”
或許,我們應該為了“藝術”的聖杯,舉起我們的雙刃劍打鬥一番。但是,比起劍來,我更喜歡犁頭,我本人。
6. 致謝
特別感謝王亞剛老師,他能不厭其煩地閱讀此文並給我提出寶貴的意見,沒有他的指點我不可能完成這篇論文。
參考文獻
[1]DonaldE. Knuth, Programming As An Art, ACM Turing Award lecture,1974.
[2]Peter van der Liden, Expert C Programming,Prentice Hall, 1994.
[3]Mike Gancarz, Linux and the UnixPhilosophy, Digital Press, 2003.
[4]Paul Graham, Hackersand Painters, O'Reilly, 2004.
[5]International Obfuscated CCode Contest, http://www.ioccc.org.
[6]Eric S. Raymond, JargonFile, http://catb.org/jargon/html/index.html.
[7]Aleph One,Smashing The Stack For Fun And Profit,http://insecure.org/stf/smashstack.html.
[8]Linus Torvalds andDavid Diamond, Just for fun, Harper Business, 2001.
[9]RobPike, SystemsSoftware Research Is Irrelevant,http://herpolhode.com/rob/utah2000.pdf, 2000.
http://kb.cnblogs.com/page/132089/