什麼是軟件設計(翻譯、轉載自Jack W. Reeves的論文《What Is Software Design?》)

      至今,我仍能記起當我頓悟並最終產生下面文章時所在的地方。那是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日

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章