源程序就是設計 ---By Jack Reeves

http://www.bleading-edge.com/Publications/C++Journal/Cpjour2.htm
程序員

這是一篇偉大的論文,該文撰寫於1992年,做者在當時就能有這樣的反思,實在是很是了不得。 算法


至 今,我仍能記起當我頓悟並最終產生下面文章時所在的地方。那是1986年的夏天,我在加利福尼亞中國湖海軍武器中心擔任臨時顧問。在這期間,我有幸參加了 一個關於Ada的研討會。討論當中,有一位聽衆提出了一個具備表明性的問題,「軟件開發者是工程師嗎?」我不記得當時的回答,可是我卻記得當時並無真正 解答這個問題。因而,我就退出討論,開始思考我會怎樣回答這樣一個問題。如今,我沒法確定當時我爲何會記起幾乎10年前曾經在Datamation雜誌 上閱讀過的一篇論文,不過促使我記起的應該是後續討論中的某些東西。這篇論文闡述了工程師爲何必須是好的做家(我記得該論文談論就是這個問題——很久沒 有看了),可是我從該論文中獲得的關鍵一點是:做者認爲工程過程的最終結果是文檔。換句話說,工程師生產的是文檔,不是實物。其餘人根據這些文檔去製造實 物。因而,我就在困惑中提出了一個問題,「除了軟件項目正常產生的全部文檔之外,還有能夠被認爲是真正的工程文檔的東西嗎?」我給出的回答是,「是的,有 這樣的文檔存在,而且只有一份——源代碼。」 

把 源代碼看做是一份工程文檔——設計——徹底顛覆了我對本身所選擇的職業的見解。它改變了我看待一切事情的方式。此外,我對它思考的越多,我就越以爲它闡明 了軟件項目經常遇到的衆多問題。更確切地說,我以爲大多數人不理解這個不一樣的見解,或者有意拒絕它這樣一個事實,就足以說明不少問題。幾年後,我終於有機 會把個人觀點公開發表。C++ Journal中的一篇有關軟件設計的論文促使我給編輯寫了一封關於這個主題的信。通過幾封書信交換後,編輯Livleen Singh贊成把我關於這個主題的想法發表爲一篇論文。下面就是這篇文章。 

——Jack Reecves, December,22,2001 


什麼是軟件設計? 
Jack W.Reeves, 1992 

面 向對象技術,特別是C++,彷佛給軟件界帶來了不小的震動。出現了大量的論文和書籍去描述如何應用這項新技術。總的來講,那些關於面向對象技術是否只是一 個騙局的問題已經被那些關於如何付出最小的努力便可得到收益的問題所替代。面向對象技術出現已經有一段時間了,可是這種爆炸式的流行卻彷佛有點不尋常。人 們爲什麼會忽然關注它呢?對於這個問題,人們給出了各類各樣的解釋。事實上,極可能就沒有單一的緣由。也許,把多種因素的結合起來才能最終取得突破,而且這 項工做正在進展之中。儘管如此,在軟件革命的這個最新階段中,C++自己看起來彷佛成爲了一個主要因素。一樣,對於這個問題,極可能也存在不少種理由,不 過我想從一個稍微不一樣的視角給出一個答案:C++之因此變得流行,是由於它使軟件設計變得更容易的同時,也使編程變得更容易。 

雖 然這個解釋好像有點奇特,可是它倒是深思熟慮的結果。在這篇論文中,我就是想要關注一下編程和程序設計之間的關係。近10年來,我一直以爲整個軟件行業都 沒有覺察到作出一個軟件設計和什麼是真正的軟件設計之間的一個微妙的不一樣點。只要看到了這一點,我認爲咱們就能夠從C++增加的流行趨勢中,學到關於如何 才能成爲更好的軟件工程師的意義深遠的知識。這個知識就是,編程不是構建軟件,而是設計軟件。 

幾 年前,我參見了一個討論會,其中討論到軟件開發是不是一門工程學科的問題。雖然我不記得了討論結果,可是我卻記得它是如何促使我認識到:軟件業已經作出了 一些錯誤的和硬件工程的比較,而忽視了一些絕對正確的對比。其實,我認爲咱們不是軟件工程師,由於咱們沒有認識到什麼纔是真正的軟件設計。如今,我對這一 點更是確信無疑。 

任 何工程活動的最終目標都是某些類型的文檔。當設計工做完成時,設計文檔就被轉交給製造團隊。該團隊是一個和設計團隊徹底不一樣的羣體,而且其技能也和設計團 隊徹底不一樣。若是設計文檔正確地描繪了一個完整的設計,那麼製造團隊就能夠着手構建產品。事實上,他們能夠着手構建該產品的許多實物,徹底無需設計者的任 何進一步的介入。在按照個人理解方式審查了軟件開發的生命週期後,我得出一個結論:實際上知足工程設計標準的唯一軟件文檔,就是源代碼清單。 

對 於這個觀點,人們進行了不少的爭論,不管是同意的仍是反對的都足以寫成無數的論文。本文假定最終的源代碼就是真正的軟件設計,而後仔細研究了該假定帶來的 一些結果。我可能沒法證實這個觀點是正確的,可是我但願證實:它確實解釋了軟件行業中一些已經觀察到的事實,包括C++的流行。 

在 把代碼看做是軟件設計所帶來的結果中,有一個結果徹底蓋過了全部其餘的結果。它很是重要而且很是明顯,也正由於如此,對於大多數軟件機構來講,它徹底是一 個盲點。這個結果就是:軟件的構建是廉價的。它根本就不具備昂貴的資格;它很是的廉價,幾乎就是免費的。若是源代碼是軟件設計,那麼實際的軟件構建就是由 編譯器和鏈接器完成的。咱們經常把編譯和鏈接一個完整的軟件系統的過程稱爲「進行一次構建」。在軟件構建設備上所進行的主要投資是不多的——實際須要的只 有一臺計算機、一個編輯器、一個編譯器以及一個鏈接器。一旦具備了一個構建環境,那麼實際的軟件構建只需花費少量的時間。編譯50 000行的C++程序也許會花費很長的時間,可是構建一個具備和50 000行C++程序一樣設計複雜性的硬件系統要花費多長的時間呢? 

把 源代碼看做是軟件設計的另一個結果是,軟件設計相對易於創做,至少在機械意義上如此。一般,編寫(也就是設計)一個具備表明性的軟件模塊(50至100 行代碼)只需花費幾天的時間(對它進行徹底的調試是另一個議題,稍後會對它進行更多的討論)。我很想問一下,是否還有任何其餘的學科能夠在如此短的時間 內,產生出和軟件具備一樣複雜性的設計來,不過,首先咱們必需要弄清出如何來度量和比較複雜性。然而,有一點是明顯的,那就是軟件設計能夠 極爲迅速地變得很是龐大。 

假 設軟件設計相對易於創做,而且在本質上構建起來也沒有什麼代價,一個不使人吃驚的發現是,軟件設計每每是難以置信的龐大和複雜。這看起來彷佛很明顯,可是 問題的重要性卻經常被忽視。學校中的項目一般具備數千行的代碼。具備10 000行代碼(設計)的軟件產品被它們的設計者丟棄的狀況也是有的。咱們早就再也不關注於簡單的軟件。典型的商業軟件的設計都是由數十萬行代碼組成的。許多 軟件設計達到了上百萬行代碼。另外,軟件設計幾乎老是在不斷地演化。雖然當前的設計可能只有幾千行代碼,可是在產品的生命期中,實際上可能要編寫許多倍的 代碼。 

盡 管確實存在一些硬件設計,它們看起來彷佛和軟件設計同樣複雜,可是請注意兩個有關現代硬件的事實。第一,複雜的硬件工程成果未必老是沒有錯誤的,在這一點 上,它不存在像軟件那樣讓咱們相信的評判標準。多數的微處理器在發售時都具備一些邏輯錯誤:橋樑坍塌,大壩破裂,飛機失事以及數以千計的汽車和其餘消費品 被召回——全部的這些咱們都記憶猶新,全部的這些都是設計錯誤的結果。第二,複雜的硬件設計具備與之對應的複雜、昂貴的構建階段。結果,製造這種系統所需 的能力限制了真正可以生產複雜硬件設計公司的數目。對於軟件來講,沒有這種限制。目前,已經有數以百計的軟件機構和數以千計的很是複雜的軟件系統存在,並 且數量以及複雜性天天都在增加。這意味着軟件行業不可能經過仿效硬件開發者找到針對自身問題的解決辦法。假若必定要說出有什麼相同之處的話,那就是,當 CAD和CAM能夠作到幫助硬件設計者建立愈來愈複雜的設計時,硬件工程纔會變得和軟件開發愈來愈像。 

設 計軟件是一種管理複雜性的活動。複雜性存在於軟件設計自己之中,存在於公司的軟件機構之中,也存在於整個軟件行業之中。軟件設計和系統設計很是類似。它可 以跨越多種技術而且經常涉及多個學科分支。軟件的規格說明每每不固定、常常快速變化,這種變化經常在正進行軟件設計時發生。一樣,軟件開發團隊也每每不固 定,經常在設計過程的中間發生變化。在許多方面,軟件都要比硬件更像複雜的社會或者有機系統。全部這些都使得軟件設計成爲了一個困難的而且易出錯的過程。 雖然全部這些都不是創造性的想法,可是在軟件工程革命開始將近30年後的今天,和其餘工程行業相比,軟件開發看起來仍然像是一種未受過訓練 (undisciplined)的技藝。 

一 般的見解認爲,當真正的工程師完成了一個設計,無論該設計有多麼複雜,他們都很是確信該設計是能夠工做的。他們也很是確信該設計可使用公認的技術建造出 來。爲了作到這一點,硬件工程師花費了大量的時間去驗證和改進他們的設計。例如,請考慮一個橋樑設計。在這樣一個設計實際建造以前,工程師會進行結構分析 ——他們創建計算機模型並進行仿真,他們創建比例模型並在風洞中或者用其餘一些方法進行測試。簡而言之,在建造前,設計者會使用他們可以想到的一切方法來 證明設計是正確的。對於一架新型客機的設計來講,狀況甚至更加嚴重;必需要構建出和原物同尺寸的原型,而且必需要進行飛行測試來驗證設計中的種種預計。 

對 於大多數人來講,軟件中明顯不存在和硬件設計一樣嚴格的工程。然而,若是咱們把源代碼看作是設計,那麼就會發現軟件工程師實際上對他們的設計作了大量的驗 證和改進。軟件工程師不把這稱爲工程,而稱它爲測試和調試。大多數人不把測試和調試看做是真正的「工程」——在軟件行業中確定沒有被看做是。形成這種見解 的緣由,更多的是由於軟件行業拒絕把代碼看做設計,而不是任何實際的工程差異。事實上,試驗模型、原型以及電路試驗板已經成爲其餘工程學科公認的組成部 分。軟件設計者之因此不具備或者沒有使用更多的正規方法來驗證他們的設計,是由於軟件構建週期的簡單經濟規律。 

第 一個啓示:僅僅構建設計並測試它比作任何其餘事情要廉價一些,也簡單一些。咱們不關心作了多少次構建——這些構建在時間方面的代價幾乎爲零,而且若是咱們 丟棄了構建,那麼它所使用的資源徹底能夠從新利用。請注意,測試並不是僅僅是讓當前的設計正確,它也是改進設計的過程的一部分。複雜系統的硬件工程師經常建 立模型(或者,至少他們把設計用計算機圖形直觀地表現出來)。這就使得他們得到了對於設計的一種「感受」,而僅僅去檢查設計是不可能得到這種感受的。對於 軟件來講,構建這樣一個模型既不可能也無必要。咱們僅僅構建產品自己。即便正規的軟件驗證能夠和編譯器同樣自動進行,咱們仍是會去進行構建/測試循環。因 此,正規的驗證對於軟件行業來講歷來沒有太多的實際意義。 

這 就是現今軟件開發過程的現實。數量不斷增加的人和機構正在建立着更加複雜的軟件設計。這些設計會被先用某些編程語言編寫出來,而後經過構建/測試循環進行 驗證和改進。過程易於出錯,而且不是特別的嚴格。至關多的軟件開發人員並不想相信這就是過程的運做方式,也正由於這一點,使問題變得更加複雜。 

當 前大多數的軟件過程都試圖把軟件設計的不一樣階段分離到不一樣的類別中。必需要在頂層的設計完成而且凍結後,才能開始編碼。測試和調試只對清除建造錯誤是必要 的。程序員處在中間位置,他們是軟件行業的建造工人。許多人認爲,若是咱們可讓程序員再也不進行「隨意的編碼(hacking)」而且按照交給他們的設計 去進行構建(還要在過程當中,犯更少的錯誤),那麼軟件開發就能夠變得成熟,從而成爲一門真正的工程學科。可是,只要過程忽視了工程和經濟學事實,這就不可 能發生。 

例 如,任何一個現代行業都沒法忍受在其製造過程當中出現超過100%的返工率。若是一個建造工人經常不能在第一次就構建正確,那麼不久他就會失業。可是在軟件 業中,即便最小的一塊代碼,在測試和調試期間,也極可能會被修正或者徹底重寫。在一個創造性的過程當中(好比:設計),咱們承認這種改進不是製造過程的一部 分。沒有人會指望工程師第一次就建立出完美的設計。即便她作到了,仍然必須讓它經受改進過程,目的就是爲了證實它是完美的。 

即 使咱們從日本的管理方法中沒有學到任何東西,咱們也應該知道因爲在過程當中犯錯誤而去責備工人是無益於提升生產率的。咱們不該該不斷地強迫軟件開發去符合不 正確的過程模型,相反,咱們須要去改進過程,使之有助於而不是阻礙產生更好的軟件。這就是「軟件工程」的石蕊測試。工程是關於你如何實施過程的,而不是關 因而否須要一個CAD系統來產生最終的設計文檔。 

關 於軟件開發有一個壓倒性的問題,那就是一切都是設計過程的一部分。編碼是設計,測試和調試是設計的一部分,而且咱們一般認爲的設計仍然是設計的一部分。雖 然軟件構建起來很廉價,可是設計起來倒是難以置信的昂貴。軟件很是的複雜,具備衆多不一樣方面的設計內容以及它們所致使的設計考慮。問題在於,全部不一樣方面 的內容是相互關連的(就像硬件工程中的同樣)。咱們但願頂層設計者能夠忽視模塊算法設計的細節。一樣,咱們但願程序員在設計模塊內部算法時沒必要考慮頂層設 計問題。糟糕的是,一個設計層面中的問題侵入到了其餘層面之中。對於整個軟件系統的成功來講,爲一個特定模塊選擇算法可能和任何一個更高層次的設計問題同 樣重要。在軟件設計的不一樣方面內容中,不存在重要性的等級。最低層模塊中的一個不正確設計可能和最高層中的錯誤同樣致命。軟件設計必須在全部的方面都是完 整和正確的,不然,構建於該設計基礎之上的全部軟件都會是錯誤的。 

爲 了管理複雜性,軟件被分層設計。當程序員在考慮一個模塊的詳細設計時,可能還有數以百計的其餘模塊以及數以千計的細節,他不可能同時顧及。例如,在軟件設 計中,有一些重要方面的內容不是徹底屬於數據結構和算法的範疇。在理想狀況下,程序員不該該在設計代碼時還得去考慮設計的這些其餘方面的內容。 

但 是,設計並非以這種方式工做的,而且緣由也開始變得明朗。軟件設計只有在其被編寫和測試後纔算完成。測試是設計驗證和改進過程的基礎部分。高層結構的設 計不是完整的軟件設計;它只是細節設計的一個結構框架。在嚴格地驗證高層設計方面,咱們的能力是很是有限的。詳細設計最終會對高層設計形成的影響至少和其 他的因素同樣多(或者應該容許這種影響)。對設計的各個方面進行改進,是一個應該貫穿整個設計週期的過程。若是設計的任何一個方面內容被凍結在改進過程之 外,那麼對於最終設計將會是糟糕的或者甚至沒法工做這一點,就不會以爲奇怪了。 

如 果高層的軟件設計能夠成爲一個更加嚴格的工程過程,那該有多好呀,可是軟件系統的真實狀況不是嚴格的。軟件很是的複雜,它依賴於太多的其餘東西。或許,某 些硬件沒有按照設計者認爲的那樣工做,或者一個庫例程具備一個文檔中沒有說明的限制。每個軟件項目早晚都會遇到這些種類的問題。這些種類的問題會在測試 期間被發現(若是咱們的測試工做作得好的話),之因此如此是由於沒有辦法在早期就發現它們。當它們被發現時,就迫使對設計進行更改。若是咱們幸運,那麼對 設計的更改是局部的。時常,更改會波及到整個軟件設計中的一些重要部分(莫非定律)。當受到影響的設計的一部分因爲某種緣由不能更改時,那麼爲了可以適應 影響,設計的其餘部分就必須得遭到破壞。這一般致使的結果就是管理者所認爲的「隨意編碼」,可是這就是軟件開發的現實。 

例 如,在我最近工做的一個項目中,發現了模塊A的內部結構和另外一個模塊B之間的一個時序依賴關係。糟糕的是,模塊A的內部結構隱藏在一個抽象體的後面,而該 抽象體不容許以任何方法把對模塊B的調用合入到它的正確調用序列中。當問題被發現時,固然已經錯過了更改A的抽象體的時機。正如所料,所發生的就是把一個 日益增加的複雜的「修正」集應用到A的內部設計上。在咱們尚未安裝完版本1時,就廣泛感受到設計正在衰退。每個新的修正極可能都會破壞一些老的修正。 這是一個正規的軟件開發項目。最後,我和個人同事決定對設計進行更改,可是爲了獲得管理層的贊成,咱們不得不自願無償加班。 

在 任何通常規模的軟件項目中,確定會出現像這樣的問題,儘管人們使用了各類方法來防止它的出現,可是仍然會忽視一些重要的細節。這就是工藝和工程之間的區 別。若是經驗能夠把咱們引向正確的方向,這就是工藝。若是經驗只會把咱們帶入未知的領域,而後咱們必須使用一開始所使用的方法並經過一個受控的改進過程把 它變得更好,這就是工程。 

我 們來看一下只是做爲其中很小一點的內容,全部的程序員都知道,在編碼以後而不是以前編寫軟件設計文檔會產生更加準確的文檔。如今,緣由是顯而易見的。用代 碼來表現的最終設計是唯一一個在構建/測試循環期間被改進的東西。在這個循環期間,初始設計保持不變的可能性和模塊的數量以及項目中程序員的數量成反比。 它很快就會變得毫無價值。 

在 軟件工程中,咱們很是須要在各個層次都優秀的設計。咱們特別須要優秀的頂層設計。初期的設計越好,詳細設計就會越容易。設計者應該使用任何能夠提供幫助的 東西。結構圖表、Booch 圖、狀態表、PDL等等——若是它可以提供幫助,就去使用它。可是,咱們必須記住,這些工具和符號都不是軟件設計。最後,咱們必須建立真正的軟件設計,並 且是使用某種編程語言完成的。所以,當咱們得出設計時,咱們不該該懼怕對它們進行編碼。在必要時,咱們必須應該樂於去改進它們。 

至 今,尚未任何設計符號能夠同時適用於頂層設計和詳細設計。設計最終會表現爲以某種編程語言編寫的代碼。這意味着在詳細設計能夠開始前,頂層設計符號必須 被轉換成目標編程語言。這個轉換步驟耗費時間而且會引入錯誤。程序員經常是對需求進行回顧而且從新進行頂層設計,而後根據它們的實際去進行編碼,而不是從 一個可能沒有和所選擇的編程語言徹底映射的符號進行轉換。這一樣也是軟件開發的部分現實狀況。 

也 許,若是讓設計者本人來編寫初始代碼,而不是後來讓其餘人去轉換語言無關的設計,就會更好一些。咱們所須要的是一個適用於各個層次設計的統一符號。換句話 說,咱們須要一種編程語言,它一樣也適用於捕獲高層的設計概念。C++正好能夠知足這個要求。C++是一門適用於真實項目的編程語言,同時它也是一個很是 具備表達力的軟件設計語言。C++容許咱們直接表達關於設計組件的高層信息。這樣,就能夠更容易地進行設計,而且之後能夠更容易地改進設計。因爲它具備更 強大的類型檢查機制,因此也有助於檢測到設計中的錯誤。這就產生了一個更加健壯的設計,實際上也是一個更好的工程化設計。 

最 後,軟件設計必需要用某種編程語言表現出來,而後經過一個構建/測試循環對其進行驗證和改進。除此以外的任何其餘主張都徹底沒有用。請考慮一下都有哪些軟 件開發工具和技術得以流行。結構化編程在它的時代被認爲是創造性的技術。Pascal使之變得流行,從而本身也變得流行。面向對象設計是新的流行技術,而 C++是它的核心。如今,請考慮一下那些沒有成效的東西。CASE工具,流行嗎?是的;通用嗎?不是。結構圖表怎麼樣?狀況也同樣。一樣地,還有 Warner-Orr圖、Booch圖、對象圖以及你能想起的一切。每個都有本身的強項,以及唯一的一個根本弱點——它不是真正的軟件設計。事實上,唯 一一個能夠被廣泛承認的軟件設計符號是PDL,而它看起來像什麼呢? 

這代表,在軟件業的共同潛意識中本能地知道,編程技術,特別是實際開發所使用的編程語言的改進和軟件行業中任何其餘東西相比,具備壓倒性的重要性。這還代表,程序員關心的是設計。當出現更加具備表達力的編程語言時,軟件開發者就會使用它們。 

同 樣,請考慮一下軟件開發過程是如何變化的。從前,咱們使用瀑布式過程。如今,咱們談論的是螺旋式開發和快速原型。雖然這種技術經常被認爲能夠「消除風險」 以及「縮短產品的交付時間」,可是它們事實上也只是爲了在軟件的生命週期中更早地開始編碼。這是好事。這使得構建/測試循環能夠更早地開始對設計進行驗證 和改進。這一樣也意味着,頂層軟件設計者頗有可能也會去進行詳細設計。 

正 如上面所代表的,工程更多的是關於如何去實施過程的,而不是關於最終產品看起來的像什麼。處在軟件行業中的咱們,已經接近工程師的標準,可是咱們須要一些 認知上的改變。編程和構建/測試循環是工程軟件過程的中心。咱們須要以像這樣的方式去管理它們。構建/測試循環的經濟規律,再加上軟件系統幾乎能夠表現任 何東西的事實,就使得咱們徹底不可能找出一種通用的方法來驗證軟件設計。咱們能夠改善這個過程,可是咱們不能脫離它。 

最 後一點:任何工程設計項目的目標是一些文檔產品。顯然,實際設計的文檔是最重要的,可是它們並不是唯一要產生的文檔。最終,會指望某些人來使用軟件。一樣, 系統極可能也須要後續的修改和加強。這意味着,和硬件項目同樣,輔助文檔對於軟件項目具備一樣的重要性。雖然暫時忽略了用戶手冊、安裝指南以及其餘一些和 設計過程沒有直接聯繫的文檔,可是仍然有兩個重要的需求須要使用輔助設計文檔來解決。 

輔 助文檔的第一個用途是從問題空間中捕獲重要的信息,這些信息是不能直接在設計中使用的。軟件設計須要創造一些軟件概念來對問題空間中的概念進行建模。這個 過程須要咱們得出一個對問題空間中概念的理解。一般,這個理解中會包含一些最後不會被直接建模到軟件空間中的信息,可是這些信息卻仍然有助於設計者肯定什 麼是本質概念以及如何最好地對它們建模。這些信息應該被記錄在某處,以防之後要去更改模型。 

對 輔助文檔的第二個重要須要是對設計的某些方面的內容進行記錄,而這些方面的內容是難以直接從設計自己中提取的。它們既能夠是高層方面的內容,也能夠是低層 方面內容。對於這些方面內容中的許多來講,圖形是最好的描述方式。這就使得它們難以做爲註釋包含在代碼中。這並非說要用圖形化的軟件設計符號代替編程語 言。這和用一些文本描述來對硬件科目的圖形化設計文檔進行補充沒有什麼區別。 

決 不要忘記,是源代碼決定了實際設計的真實樣子,而不是輔助文檔。在理想狀況下,可使用軟件工具對源代碼進行後期處理併產生出輔助文檔。對於這一點,咱們 可能指望太高了。次一點的狀況是,程序員(或者技術方面的編寫者)可使用一些工具從源代碼中提取出一些特定的信息,而後能夠把這些信息以其餘一些方式文 檔化。毫無疑問,手工對這種文檔保持更新是困難的。這是另一個支持須要更具表達力的編程語言的理由。一樣,這也是一個支持使這種輔助文檔保持最小而且盡 可能在項目晚期才使之變成正式的理由。一樣,咱們可使用一些好的工具;否則的話,咱們就得求助於鉛筆、紙以及黑板。 

總結以下: 
  實際的軟件運行於計算機之中。它是存儲在某種磁介質中的0和1的序列。它不是使用C++語言(或者其餘任何編程語言)編寫的程序。 
  程序清單是表明軟件設計的文檔。實際上把軟件設計構建出來的是編譯器和鏈接器。 
  構建實際軟件設計的廉價程度是使人難以置信的,而且它始終隨着計算機速度的加快而變得更加廉價。 
  設計實際軟件的昂貴程度是使人難以置信的,之因此如此,是由於軟件的複雜性是使人難以置信的,而且軟件項目的幾乎全部步驟都是設計過程的一部分。 
  編程是一種設計活動——好的軟件設計過程承認這一點,而且在編碼顯得有意義時,就會絕不猶豫的去編碼。 
  編碼要比咱們所認爲的更頻繁地顯現出它的意義。一般,在代碼中表現設計的過程會揭示出一些疏漏以及額外的設計須要。這發生的越早,設計就會越好。 
  由於軟件構建起來很是廉價,因此正規的工程驗證方法在實際的軟件開發中沒有多大用處。僅僅建造設計並測試它要比試圖去證實它更簡單、更廉價。 
  測試和調試是設計活動——對於軟件來講,它們就至關於其餘工程學科中的設計驗證和改進過程。好的軟件設計過程承認這一點,而且不會試圖去減小這些步驟。 
  還有一些其餘的設計活動——稱它們爲高層設計、模塊設計、結構設計、構架設計或者諸如此類的東西。好的軟件設計過程承認這一點,而且慎重地包含這些步驟。 
  全部的設計活動都是相互影響的。好的軟件設計過程承認這一點,而且當不一樣的設計步驟顯示出有必要時,它會容許設計改變,有時甚至是根本上的改變, 
  許多不一樣的軟件設計符號多是有用的——它們能夠做爲輔助文檔以及工具來幫助簡化設計過程。它們不是軟件設計。 
  軟件開發仍然仍是一門工藝,而不是一個工程學科。主要是由於缺少驗證和改善設計的關鍵過程當中所需的嚴格性。 
  最後,軟件開發的真正進步依賴於編程技術的進步,而這又意味着編程語言的進步。C++就是這樣的一個進步。它已經取得了爆炸式的流行,由於它是一門直接支持更好的軟件設計的主流編程語言。 
  C++在正確的方向上邁出了一步,可是還須要更大的進步。 

後 記 

當 我回顧幾乎10年前所寫的東西時,有幾點讓我印象深入。第一點(也是和本書最有關的)是,現今,我甚至比那時更加確信我試圖去闡述的要點在本質上的正確 性。隨後的一些年中,許多流行的軟件開發方法加強了其中的許多觀點,這支持了個人信念。最明顯的(或許也是最不重要的)是面向對象編程語言的流行。如今, 除了C++外,出現了許多其餘的面向對象編程語言。另外,還有一些面向對象設計符號,好比:UML。我關於面嚮對象語言之因此獲得流行是由於它們容許在代 碼中直接表現出更具表達力的設計的論點,如今看來有點過期了。 

重構的概念——從新組織代碼基礎,使之更加健壯和可重用——一樣也和個人關於設計的全部方面的內容都應該是靈活的而且在驗證設計時容許改變的論點類似。重構只是提供了一個過程以及一組如何去改善已經被證明具備缺陷的設計的準則。 

最後,文中有一個敏捷開發的總的概念。雖然極限編程是這些新方法中最知名的一個,可是它們都具備一個共同點:它們都認可源代碼是軟件開發工做中的最重要的產品。 

另 一方面,有一些觀點——其中的一些我在論文中略微談到過——在隨後的一些年中,對我來講變得更加劇要。第一個是構架,或者頂層設計的重要性。在論文中,我 認爲構架只是設計的一部份內容,而且在構建/測試循環對設計進行驗證的過程當中,構架須要保持可變。這在本質上是正確的,可是回想起來,我認爲個人想法有點 不成熟。雖然構建/測試循環可能揭示出構架中的問題,可是更多的問題是經常因爲改變需求而表現出來的。 通常來講,設計軟件是困難的,而且新的編程語言,好比:Java或者C++,以及圖形化的符號,好比:UML,對於不知道如何有效地使用它的人來講,都沒 有多大的幫助。此外,一旦一個項目基於一個構架構建了大量的代碼,那麼對該構架進行基礎性的更改,經常至關於丟棄掉該項目並從新開始一個,這就意味着該項 目沒有出現過。即便項目和機構在根本上接受了重構的概念,可是他們一般仍然不肯意去作一些看起來就像是徹底重寫的事情。這意味着第一次就把它做對(或者至 少是接近對)是重要的,而且項目變得越大,就越要如此。幸運的是,軟件設計模式有助於解決這方面問題。 

還 有其餘一些方面的內容,我認爲須要更多地強調一下,其中之一就是輔助文檔,尤爲是構架方面的文檔。雖然源代碼就是設計,可是試圖從源代碼中得出構架,可能 是一個使人畏懼的體驗。在論文中,我但願可以出現一些軟件工具來幫助軟件開發者自動地維護來自源代碼的輔助文檔。我幾乎已經放棄了這個但願。一個好的面向 對象構架一般可使用幾幅圖以及少量的十幾頁文本描述出來。不過,這些圖(和文本)必須集中於設計中的關鍵類和關係。糟糕的是,對於軟件設計工具可能會變 得足夠聰明,以致於能夠從源代碼的大量細節中提取出這些重要方面的內容這一點,我沒有看到任何真正的但願。這意味着還得必須由人來編寫和維護這種文檔。我 仍然認爲,在源代碼完成後,或者至少是在編寫源代碼的同時去編文檔,要比在編寫源代碼以前去編寫文檔更好一些。 

最後,我在論文的最後談到了C++是編程——而且所以是軟件設計——藝術的一個進步,可是還須要更大的進步。就算我徹底沒有看到語言中出現任何真正的編程進步來挑戰C++的流行,那麼在今天,我會認爲這一點甚至要比我首次編寫它時更加正確。 

——Jack Reeves, 2002年1月1日         
編程

相關文章
相關標籤/搜索