岸上的船兒如同海上的燈塔,無(wú)法移動(dòng)。
—— 荷蘭諺語(yǔ)
Een schip op het strand is een baken in
zee.
[A ship on the beach is a lighthouse to the
sea.]
DUTCH
PROVERB
史前史中,沒有別的場(chǎng)景比巨獸們?cè)诮褂涂又写顾罀暝膱?chǎng)面更令人震撼。上帝見證著恐龍、猛犸象、劍齒虎在焦油中掙扎。它們掙扎得越猛烈,焦油糾纏得就越緊,沒有任何猛獸足夠強(qiáng)壯或具有足夠的技巧,能夠掙脫束縛,它們最后都沉到了坑底。
過去幾十年的大型系統(tǒng)開發(fā)就猶如這樣一個(gè)焦油坑,很多大型和強(qiáng)壯的動(dòng)物在其中劇烈地掙扎。他們中大多數(shù)開發(fā)出
了可運(yùn)行的系統(tǒng)——
不過只有極少數(shù)的項(xiàng)目滿足了目標(biāo)、進(jìn)度和預(yù)算的要求。各種團(tuán)隊(duì),大型的或小型的,龐雜的或精干的,一個(gè)接一個(gè)淹沒在了焦油坑中。表面上看起來(lái)好像沒有任何
一個(gè)單獨(dú)的問題會(huì)導(dǎo)致困難,每個(gè)問題都能獲得解決,但是當(dāng)它們相互糾纏和累積在一起的時(shí)候,團(tuán)隊(duì)的行動(dòng)就會(huì)變得越來(lái)越慢。對(duì)問題的麻煩程度,每個(gè)人似乎都
會(huì)感到驚訝,并且很難看清問題的本質(zhì)。不過,如果我們想解決問題,就必須試圖先去了解問題。
因此,首先讓我們來(lái)認(rèn)識(shí)一下系統(tǒng)開發(fā)這個(gè)職業(yè),以及充滿在這個(gè)職業(yè)中的樂趣和苦惱吧!
編程系統(tǒng)產(chǎn)品
報(bào)紙上經(jīng)常會(huì)出現(xiàn)這樣的新聞,講述兩個(gè)程序員如何在經(jīng)過改造的簡(jiǎn)陋車庫(kù)中,編出了超過大型團(tuán)隊(duì)工作量的重要程序。接著,每個(gè)編程人員準(zhǔn)備相信這樣的神話,因?yàn)樗雷约耗芤猿^產(chǎn)業(yè)化團(tuán)隊(duì)的1 000代碼行/年的生產(chǎn)率來(lái)開發(fā)任何程序。
為什么不是所有的產(chǎn)業(yè)化隊(duì)伍都會(huì)被這種專注的二人組合所替代?我們必須看一下產(chǎn)出的是什么。
在圖1-1的左上部分是程序(Program)。它本身是完整的,可以由作者在所開發(fā)的系統(tǒng)平臺(tái)上運(yùn)行。它通常是車庫(kù)中產(chǎn)出的產(chǎn)品,以及作為單個(gè)程序員生產(chǎn)率的評(píng)估標(biāo)準(zhǔn)。

圖1-1 編程系統(tǒng)產(chǎn)品的演進(jìn)
有兩種途徑可以使程序轉(zhuǎn)變成更有用的,但是成本更高的產(chǎn)物,這兩種途徑表現(xiàn)為圖中的邊界。
水平邊界以下,程序轉(zhuǎn)變成編程產(chǎn)品(Programming
Product)。這是可以被任何人運(yùn)行、測(cè)試、修復(fù)和擴(kuò)展的程序。它可以在多種操作系統(tǒng)平臺(tái)上運(yùn)行,供多套數(shù)據(jù)使用。要成為通用的編程產(chǎn)品,程序必須按
照普遍認(rèn)可的風(fēng)格來(lái)編寫,特別是輸入的范圍和形式必須廣泛地適用于所有可以合理使用的基本算法。接著,對(duì)程序進(jìn)行徹底測(cè)試,確保它的穩(wěn)定性和可靠性,使其
值得信賴。這就意味著必須準(zhǔn)備、運(yùn)行和記錄詳盡的測(cè)試用例庫(kù),用來(lái)檢查輸入的邊界和范圍。此外,要將程序提升為程序產(chǎn)品,還需要有完備的文檔,每個(gè)人都可
以加以使用、修復(fù)和擴(kuò)展。經(jīng)驗(yàn)數(shù)據(jù)表明,相同功能的編程產(chǎn)品的成本,至少是經(jīng)過測(cè)試程序的3倍。
回到圖中,垂直邊界的右邊,程序轉(zhuǎn)變成編程系統(tǒng)(Programming
System)中的一個(gè)構(gòu)件單元。它是在功能上能相互協(xié)作、具有規(guī)范的格式、可以進(jìn)行交互的程序集合,并可以用來(lái)組裝和搭建整個(gè)系統(tǒng)。要成為編程系統(tǒng)構(gòu)
件,程序必須按照一定的要求編制,使輸入和輸出在語(yǔ)法和語(yǔ)義上與精確定義的接口一致。同時(shí)程序還要符合預(yù)先定義的資源限制——
內(nèi)存空間、輸入輸出設(shè)備、計(jì)算機(jī)時(shí)間。最后,程序必須同其他系統(tǒng)構(gòu)件單元一道,以任何能想像到的組合進(jìn)行測(cè)試。由于測(cè)試用例會(huì)隨著組合不斷增加,所以測(cè)試
的范圍必須廣泛。因?yàn)橐恍┮庀氩坏降慕换?huì)產(chǎn)生許多不易察覺的bug,測(cè)試工作將會(huì)非常耗時(shí),因此相同功能的編程系統(tǒng)構(gòu)件的成本至少是獨(dú)立程序的3倍。如
果系統(tǒng)有大量的組成單元,成本還會(huì)更高。
圖1-1的右下部分代表編程系統(tǒng)產(chǎn)品(Programming Systems Product)。與以上的所有的簡(jiǎn)單的程序都不同的是,它的成本高達(dá)9倍。然而,只有它才是真正有用的產(chǎn)品,是大多數(shù)系統(tǒng)開發(fā)的目標(biāo)。
職業(yè)的樂趣
編程為什么有趣?作為回報(bào),它的從業(yè)者期望得到什么樣的快樂?
首先,這種快樂是一種創(chuàng)建事物的純粹快樂。如同小孩在玩泥巴時(shí)感到快樂一樣,成年人喜歡創(chuàng)建事物,特別是自己進(jìn)行設(shè)計(jì)。我想這種快樂是上帝創(chuàng)造世界的折射,一種呈現(xiàn)在每片獨(dú)特、嶄新的樹葉和雪花上的喜悅。
其次,這種快樂來(lái)自于開發(fā)對(duì)他人有用的東西。內(nèi)心深處,我們期望我們的勞動(dòng)成果能夠被他人使用,并能對(duì)他們有所幫助。從這一角度而言,這同小孩用粘土為“爸爸的辦公室”捏制鉛筆盒沒有任何本質(zhì)的區(qū)別。
第三,快樂來(lái)自于整個(gè)過程體現(xiàn)出的一股強(qiáng)大的魅力——
將相互嚙合的零部件組裝在一起,看到它們以精妙的方式運(yùn)行著,并收到了預(yù)先所希望的效果。比起彈球游戲機(jī)或自動(dòng)電唱機(jī)所具有的迷人魅力,程序化的計(jì)算機(jī)毫不遜色。
第四,這種快樂是持續(xù)學(xué)習(xí)的快樂,它來(lái)自于這項(xiàng)工作的非重復(fù)特性。人們所面臨的問題總有這樣那樣的不同,因而解決問題的人可以從中學(xué)習(xí)新的事物:有時(shí)是實(shí)踐上的,有時(shí)是理論上的,或者兼而有之。
最后,這種快樂還來(lái)自于在易于駕馭的介質(zhì)上工作。程序員,就像詩(shī)人一樣,幾乎是僅僅工作在單純的思考中。程序
員憑空地運(yùn)用自己的想像,來(lái)建造自己的“城堡”。很少有創(chuàng)造介質(zhì)如此靈活,如此易于精煉和重建,如此容易實(shí)現(xiàn)概念上的設(shè)想(不過我們將會(huì)看到,容易駕馭的
特性也有它自己的問題)。
然而程序畢竟同詩(shī)歌不同:它是實(shí)實(shí)在在的東西;它可以移動(dòng)和運(yùn)行,能獨(dú)立產(chǎn)生可見的輸出;它能打印結(jié)果,繪制圖形,發(fā)出聲音,移動(dòng)支架。神話和傳說(shuō)中的魔術(shù)在我們的時(shí)代已變成了現(xiàn)實(shí)。在鍵盤上鍵入正確的咒語(yǔ),屏幕會(huì)活動(dòng)、變幻,顯示出前所未有的也不可能存在的事物。
編程的快樂在于它不僅滿足了我們內(nèi)心深處進(jìn)行創(chuàng)造的渴望,而且還喚醒了每個(gè)人內(nèi)心的情感。
職業(yè)的苦惱
然而這個(gè)過程并不全都是快樂。我們只有事先了解一些編程固有的苦惱,這樣,當(dāng)它們真的出現(xiàn)時(shí),才能更加坦然地面對(duì)。
首先,苦惱來(lái)自追求完美。因?yàn)橛?jì)算機(jī)是以這樣的方式來(lái)變戲法的:如果咒語(yǔ)中的一個(gè)字符、一個(gè)停頓,沒有與正確
的形式一致,魔術(shù)就不會(huì)出現(xiàn)(現(xiàn)實(shí)中,很少的人類活動(dòng)要求完美,所以人類對(duì)它本來(lái)就不習(xí)慣)。實(shí)際上,我認(rèn)為,學(xué)習(xí)編程最困難的部分,是將做事的方式向追
求完美的方向調(diào)整[1]。
其次,苦惱來(lái)自由他人來(lái)設(shè)定目標(biāo)、供給資源和提供信息。編程人員很少能控制工作環(huán)境和工作目標(biāo)。用管理的術(shù)語(yǔ)
來(lái)說(shuō),個(gè)人的權(quán)威和他所承擔(dān)的責(zé)任是不相配的。不過,似乎在所有的領(lǐng)域中,對(duì)要完成的工作,很少能提供與責(zé)任相一致的正式權(quán)威。而現(xiàn)實(shí)情況中,實(shí)際(相對(duì)
于形式)的權(quán)威來(lái)自于每次任務(wù)的完成。
對(duì)于系統(tǒng)編程人員而言,對(duì)其他人的依賴是一件非常痛苦的事情。他依靠其他人的程序,而往往這些程序設(shè)計(jì)得并不
合理、實(shí)現(xiàn)拙劣、發(fā)布不完整(沒有源代碼或測(cè)試用例)、或者文檔記錄得很糟。所以,系統(tǒng)編程人員不得不花費(fèi)時(shí)間去研究和修改,而它們?cè)诶硐肭闆r下本應(yīng)該是
可靠完整的。
下一個(gè)苦惱—— 概念性設(shè)計(jì)是有趣的,但尋找瑣碎的bug卻只是一項(xiàng)重復(fù)性的活動(dòng)。伴隨著創(chuàng)造性活動(dòng)的,往往是枯燥沉悶的時(shí)間和艱苦的勞動(dòng)。程序編制工作也不例外。
另外,人們發(fā)現(xiàn)調(diào)試和查錯(cuò)往往是線性收斂的,或者更糟糕的是,具有二次方的復(fù)雜度。結(jié)果,測(cè)試一拖再拖,尋找最后一個(gè)錯(cuò)誤比第一個(gè)錯(cuò)誤將花費(fèi)更多的時(shí)間。
最后一個(gè)苦惱,有時(shí)也是一種無(wú)奈——
當(dāng)投入了大量辛苦的勞動(dòng),產(chǎn)品在即將完成或者終于完成的時(shí)候,卻已顯得陳舊過時(shí)。可能是同事和競(jìng)爭(zhēng)對(duì)手已在追逐新的、更好的構(gòu)思;也許替代方案不僅僅是在構(gòu)思,而且已經(jīng)在安排了。
現(xiàn)實(shí)情況比上面所說(shuō)的通常要好一些。當(dāng)產(chǎn)品開發(fā)完成時(shí),更優(yōu)秀的新產(chǎn)品通常還不能投入使用,而僅僅是為大家談?wù)摱选A硗猓瑯有枰獢?shù)月的開發(fā)時(shí)間。事實(shí)上,只有實(shí)際需要時(shí),才會(huì)用到最新的設(shè)想,因?yàn)樗鶎?shí)現(xiàn)的系統(tǒng)已經(jīng)能滿足要求,并體現(xiàn)了回報(bào)。
誠(chéng)然,產(chǎn)品開發(fā)所基于的技術(shù)在不斷地進(jìn)步。一旦設(shè)計(jì)被凍結(jié),在概念上就已經(jīng)開始陳舊了。不過,實(shí)際產(chǎn)品需要一
步一步按階段實(shí)現(xiàn)。實(shí)現(xiàn)落后與否的判斷應(yīng)根據(jù)其他已有的系統(tǒng),而不是未實(shí)現(xiàn)的概念。因此,我們所面臨的挑戰(zhàn)和任務(wù)是在實(shí)際的進(jìn)度和有效的資源范圍內(nèi),尋找
解決實(shí)際問題的切實(shí)可行方案。
這,就是編程,一個(gè)許多人痛苦掙扎的焦油坑以及一種樂趣和苦惱共存的創(chuàng)造性活動(dòng)。對(duì)于許多人而言,其中的快樂遠(yuǎn)遠(yuǎn)大于苦惱。本書的以下章節(jié)將試圖搭建一些橋梁,為通過這樣的焦油坑提供一些指導(dǎo)。