編程,更多?更好?更快?
最近,讀到一個故事,是下面這樣的。
在一次陶藝課上,老師在***堂課時說,他會把班上同學們分成兩組。教室左邊這組,他們這門課的成績將會以最終完成的陶器作品數(shù)量來評定,而右邊那組,則會以最終完成的陶器品質(zhì)來評定。
進一步說明,其評定過程是這樣的:這門課的***一天,老師會帶來一桿天平稱,用來稱量 “數(shù)量” 組的成果。如果 50 磅及以上,得 A,40 磅及以上得 B,30 磅得 C,如此類推。而 “品質(zhì)” 組只需要提交一件(僅一件)他們組認為最 “***” 的作品即可,如果老師也認為很不錯,就可以得 A。
時間很快過去,到了該交作業(yè)的日子。一個很有趣的現(xiàn)象出現(xiàn)了,“數(shù)量” 組如預期一般拿出了很多作品,但質(zhì)量***的作品卻也全部是由 “數(shù)量” 組制作出來的。按 “數(shù)量” 組的評定標準,他們似乎應該忙于粗制濫造大量的陶器,但他們每做出一個垃圾作品,都會吸取上一次制作的錯誤經(jīng)驗教訓,再做下一個作品時得到改進。而 “品質(zhì)” 組一開始就追求***的作品,他們花費了大量的時間從理論上論證如何才能做出一個***的作品,而到了***拿出來的東西,似乎只是一堆建立在宏大理論上的陶土。
更多
當我讀完這個故事,陷入了沉思,感到編程和制作陶藝是如此類似。《黑客與畫家》書里講,編程和畫畫近乎異曲同工,其實很多這種類似工匠型的技藝都有其相似之處。
很多人小時候都畫過畫,是的,我小時候也愛畫畫。看見一幅圖,拿上一只筆就可以開始臨摹。后來有了美術(shù)課,開始寫生,看見了,就能畫出來。但現(xiàn)在我卻不再畫畫了,為什么?因為,現(xiàn)在我再回頭看曾經(jīng)畫過的畫,簡直就是一坨 “狗屎”。后來,長大了,成年了,讀完書、考上大學,工作后,再想拿起筆去畫時,發(fā)現(xiàn)還不如小時候畫的,所以我不再畫了。
為什么那時候(小時候)明明畫得不好,卻可以不停得去畫。也許這個問題有很多答案,但我想其中之一必然是:那時候,我們并沒有給自己施加任何的限制,沒有追求***的作品,沒有追求畫畫的意義,而僅僅是在探索與學習。一幅接一幅的畫,僅僅是這一次比上一次有所進步,我們就會開心的大呼小叫。
某一天,我們長大了。我們知道了,畫畫是一種技藝,甚至是一種藝術(shù)。我們見過了真正可以稱之為藝術(shù)的畫作,我們也知道了如何才算是正確的畫畫,所有這些讓我們感到,曾經(jīng)的那支畫筆已經(jīng)重到讓我們不敢再輕易去拿起。
那些成名畫家的作品,如果按時間順序來排列展示,我們會發(fā)現(xiàn)每幅畫所用的技巧,都是建立在上一幅作品學到的東西之上。如果某幅作品特別出眾,你往往能在更早期的作品中找到類似的版本。
而編程這門技藝,也完全是一個類似的過程。我很慶幸我在初學編程時,就像我小時候剛拿起畫筆,我只是在不斷通過編程訓練來解答一個又一個書本上得來的困惑。后來,則是不斷寫程序來解決一個又一個工作中的問題。那時,看到書上探討各種優(yōu)雅的代碼之道,編程的藝術(shù)哲學,我卻完全不知道如何通往這座編程的 “圣杯”,看著自己寫出的蹩腳代碼,然后繼續(xù)不斷重復去制作下一個丑陋的 “陶器”。
而過去十多年的編程經(jīng)驗印證了開頭的故事,在通往「更好」的路上,必然要經(jīng)過「更多」這條路。
更好
編程路上,如果一開始就像 “品質(zhì)” 組的同學那樣去追求***,也許我們就會被定義 “***” 的品質(zhì)所絆住。
編程的問題是,一開始我們并不知道什么是編程的正確方法,無論我們在開始動手編程時看過多少有關(guān)的編程理論、方法、哲學與藝術(shù)的書。這樣反而讓我們沒有什么約束,只管去盯住你要用編程解決的問題,把問題解決,把任務完成。
曾經(jīng),還在學校學習編程時,有一個期中課程設(shè)計。我很快完成了一個這個課程設(shè)計中的編程作業(yè),而另一位同學,剛剛看完了那本經(jīng)典的設(shè)計模式書。他嘗試在用書里學到的新概念來設(shè)計這個編程作業(yè),并且先又用 UML 畫了一大堆交互和類圖,去推導設(shè)計的***與優(yōu)雅。然后興致勃勃的向我(因為我剛好坐在他旁邊)講解他的***設(shè)計,然后我若有所悟,覺得里面確實有值得我改進的地方,準備吸收一些我能聽明白的東西,重構(gòu)一遍已經(jīng)寫好的作業(yè)程序。
后來,這位同學在動手實現(xiàn)他的***設(shè)計時,發(fā)現(xiàn)程序越寫越復雜,交作業(yè)的時間已經(jīng)不夠了,只好借用我的不***的***版代碼改改湊合交了。而我這在***版代碼基礎(chǔ)上,又按領(lǐng)悟到的正確思路重構(gòu)了一次,交了作業(yè)。而巧的是我的***版代碼,又流傳到了另外幾個同學手上,幾乎也就改個名字就當成作業(yè)交了。但是,我們那門課的老師有一個專門識別類似作業(yè)程序代碼的程序,檢查出了相似度極高的那幾個同學的作業(yè),都是我的***版代碼,結(jié)果所有人都被打回重做了一遍,而我暗自慶幸,還好我又重構(gòu)一次。
編程,其實一開始哪有什么***,只有更好。之后,工作了,我做了大量的不大不小的項目,然后發(fā)現(xiàn)這些項目都有很多類似之處。每次,即使項目上線后,我也必然重構(gòu)項目代碼,提取其中的可復用代碼,然后在下一個項目中使用。循環(huán)往復,一直干了七、八年。我想,很多程序員都有類似的經(jīng)歷,而把這件事干得最有名且***的是江南白衣的 SrpingSide(一個以 Spring Framework 為核心的,Pragmatic 風格的 JavaEE 應用參考示例,是 JavaEE 世界中的主流技術(shù)選型,***實踐的總結(jié)與演示。) 開源項目。
在這個過程中,我漸漸成型了屬于自己的編程價值觀:沒有***的解決方案,任何方案總是有這樣或那樣一些因子可以優(yōu)化。一些方案可能面臨的權(quán)衡取舍會少些,而另一些方案則會更糾結(jié)一些。但所有的方案,我都做了取舍。
好不是***,好是一個過程。
更快
當做了足夠多,并且到了足夠好的時候,自然能做到更快。
影視作品里,總是用一種敲擊鍵盤的快來表達黑客高手編程的快。但實際編程***的瓶頸在頭腦,而非手指。如前,程序員反復提取、重構(gòu)與優(yōu)化的代碼,***就成了自己專屬的工具箱和腳手架。遇到類似的問題、場景,要么直接就能復用,要么稍微改改也能使用,這樣才能做到快。
所以,為什么會有不要重復發(fā)明輪子的說法,我們要把寶貴的思考力用在更新的問題上,而非已經(jīng)解決的問題上。為什么需要盡早并經(jīng)常性的重構(gòu)代碼,扔(重構(gòu)刪除)掉一些代碼,就是扔掉負擔,然后走的更輕松,留下(重構(gòu)復用)另一些代碼,讓未來走得更快。
有時,好幾年后,我還會看幾年前的代碼。剛開始幾年,我老是罵自己太蠢,怎么當年寫這么蠢的代碼。再過了一些年,偶爾我會驚喜的暗贊當年還是有聰明的時候,對于一些當時就思考理解得很費力的地方居然留下了注釋,還有故意寫了一些看起來很 “蠢” 但是很容易閱讀和理解的代碼,而不是寫一些 “聰明”(不聰明的普通人不太看得懂)的代碼。當時的這些 “蠢” 反而讓后來去改進、修復和重構(gòu)時能更快。
【本文是51CTO專欄作者胡峰的原創(chuàng)文章,轉(zhuǎn)載請聯(lián)系作者本人獲取授權(quán)】