0%
第十一章 網路經濟學 11.4 與錯誤打交道

第十一章 網路經濟學

11.4 與錯誤打交道

另外一種非常重要的防錯方法是對複雜軟體進行模塊化。1982年發表在IEEE的《軟體工程交易》上的一個研究顯示,在其它條件完全相同的狀況下,代碼總行數相同的程序拆分為子程序之後,錯誤數量是如何減少的。一個1萬行的程序,如果是一整塊,它有317個錯誤,如果把它拆分為三個子程序,那麼總數還是1萬行的程序,錯誤數則略有減少,為265個。每拆分一次所減少的錯誤量,大致符合一個線性方程,所以模塊化雖然不能完全解決問題,但它卻是一種有效的手段。
零缺陷軟體的代價就是它的「過度設計」,超量建設,多少有點浮腫——永遠不會處在泰德和他的朋友所經常逗留的那種未知的邊緣。它是用執行效率來換取生產效率。
大型軟體程序可能是人類現在所能製造的最複雜的東西了。微軟的新操作系統有4百萬條代碼。當然,在7萬個Beta版本的測試點進行測試之後,比爾蓋茨肯定會說,現在這個軟體沒有漏洞了。
對於小程序來說,這個「零缺陷」的零就是0.000。但是對於那種超大型的程序來說,這個「零」指的就是小於等於0.001。這是指每千行代碼允許的錯誤值,而這隻是產品質量的一個大概標準。這些旨在編寫零缺陷軟體的方法,大量借鑒了日本工程師新鄉重夫的零缺陷生產的開創性工作。當然,計算機科學家們聲稱,「軟體不一樣」。軟體可以被完美複製,因此只需要保證最開始的那一份是「零缺陷」就好了。
新生物學的解決之道是用一個個可以正常工作的單元來搭建程序,並在這個過程中不斷地對其進行檢測和修正。不過,我們還會面臨這樣的問題:儘管各個單元是沒有漏洞的,但在搭建的過程中,仍然會發生意料之外的「突現行為」(即漏洞)。不過,你現在所要做的就是在更高一級的層面上進行測試(因為底層單元已經被證明是沒有問題的),因而是有希望做到「零缺陷」的——這比要同時應付突現問題和深埋問題的情況要好得多了。
泰德永遠都不可能跟日本的那種軟體作坊合得來。他說,「一個好的程序員可以對任何一個已知的、規律的軟體進行重寫,巧妙地減少代碼。但是,在創造性編程過程中,沒有任何已經被完全理解的東西。你不得不去編寫自己也並不明白的東西……嗯,是,你是可以寫出零缺陷的軟體,但它會有好幾千行超出所需的代碼。」
當各種公司取消實體進入某種巴洛式的賽博空間之後,它們就具有了某種類似於軟體的特點。無污染、無重量、快速、有用、可移動而且有趣。但同時也可能變得非常複雜,充滿了沒人能查明的煩人的小毛病。
前面提到,在IBM的代碼中有31處錯誤。而包含這些read•99csw.com錯誤的模塊充分說明了軟體的一個特性——錯誤總是扎堆出現的。我們可以利用這個特性來達到質量管理上的希格瑪精度。零缺陷運動的聖經《零缺陷軟體》寫道,「你發現的下一個錯誤,極有可能出現在你已經找出了11個錯誤的模塊里,而那些從未出過錯誤的模塊,則可能會一直保持不敗金身。」錯誤扎堆現象在軟體中是如此普遍,以至於被當作一條「魔鬼定律」:當你發現一個錯誤的時候,也就意味著還有另外一堆你沒看見的錯誤在什麼地方等著你。
《零經》中提到的補救方法是這樣的,「不要把錢花在錯誤百出的代碼上,拋棄它!重寫一段代碼的代價和修補一個錯誤百出的模塊的代價相差無多。如果軟體的某個單元的錯誤率超過了一定的閾限,就把它扔掉,另找一個開發人員來重寫代碼。如果你手上正在編寫的代碼顯示出某種容易出錯的傾向,就放棄它,因為在前期出現錯誤的話,也就意味著後面還將不斷地出錯。」
軟體可靠性大師C.K.曹曾經告誡業界人士,不要把軟體看成產品,要把它看成攜帶型工廠。你賣的,或者說,你給予客戶的是一個工廠(程序代碼),可以在客戶需要的時候為他製造出一個答案。你的難題是要製造一個能生產零缺陷答案的工廠。建造能夠生產出完美可靠器件的工廠的方法,也可以輕易地應用到創建能給出完美可靠答案的工廠上。
如果未來的公司和產品就跟現在的軟體一樣,那意味著什麼?會破碎的電視機?突然熄火的汽車?會爆炸的烤麵包機?
在網路式經濟中,研發新產品的費用主要源自生產流程的設計,而非產品設計。日本人擅長生產流程的設計和改進,而美國人擅長的是產品的設計和改進。日本人把軟體看作一個生產流程而不是產品。在漸露端倪的網路文化中,我們所生產的越來越多的東西——當然也是我們越來越多的財富——都與符號處理流程密切相關,這些流程所裝配的是代碼而非實物。
這些零缺陷的傳道者有一個概括網路式經濟的口號:「公司里的每個人都有一個客戶」。通常而言,這個所謂的客戶,就是你的工作夥伴,你要將工作依次轉交給他。而你必須首先把你的那個小循環(設計-編寫-測試)做好,才能把它交付給你的工作夥伴——就好像你在銷售商品一樣。
在軟體設計領域,現在最熱的前沿就是所謂「面向對象」的軟體。一個面向對象的程序(OOP)實際上就是一個相對去中心化的、模塊式的程序。對於一個OOP來說,它的一個「碎片」,就是一個獨立成立、保持自身完整性的單元;它可以和其它的OOP「碎片」整合在一起形成一個可分解的指令結構。「對象」限九*九*藏*書制了程序漏洞所能造成的損害。和那種傳統程序不同,OOP有效地對功能實行了隔離,把每一個功能都限制在一個可掌控的單元內,這樣一來,即使一個對象崩潰了,程序的其它部分也能夠繼續運轉,而對於傳統程序來說,一個地方出了問題,整個程序就會崩潰。程序員可以把這個壞掉的單元換掉,就好象我們可以給一個汽車換剎車片一樣。軟體的銷售商可以購買或者銷售各種事先編製好的「對象」庫給其它的軟體研發人員,後者則可以基於這些庫里的對象快速地組裝起大型軟體,而不用再像以前那樣重新一行一行地編寫新的代碼。而到了要為這種大型軟體升級的時候,你所要做的就是升級舊的對象或者加入新的對象。
進一步來說,當程序小到某個閾限以下之後,就可以達到完全沒有錯誤的狀態。IBM為它們的IMS系列所寫的代碼,就是以模塊化的方式編製的,其中有四分之三的模塊達到了完全沒有缺陷的狀態。具體來說,就是在425個模塊中,有300個是完全沒有錯誤的。而在剩下的125個有錯誤的模塊中,有超過一半的錯誤集中發生在僅僅31個模塊上。從這個意義上說,程序編製的模塊化,就是程序的「可靠化」。
那麼,我們是否可能製造出那種超級複雜而又沒有任何缺陷(或者,只有很少幾個缺陷)的東西來呢?網路式經濟到底是能幫助我們創造出一種沒有缺陷的複雜系統,還是只能為我們建立一個有漏洞的複雜系統?
通常,軟體的編製遵循三個中心化的關鍵步驟。首先設計一個全景圖,然後用代碼實現細節,最後,在接近項目尾聲時,將其作為交互的整體來進行測試。而在零缺陷質量的設計流程中,整個軟體編製過程不再是幾個大的關鍵步驟,而是被分散成上千個小步驟。軟體的設計、編寫和測試工作每天都在成百個小工作間里進行著,每個小工作間里都有一個人在忙碌著。
日本人在防錯領域的經典發明是一種稱為Poka-Yoke的防錯系統——它可以使事情對人們所犯的錯誤具有「免疫力」。在裝配線上設置一些巧妙而簡單的裝置就可以防止錯誤的發生。比如,在放螺栓的托盤上為每一個螺栓設定一個特別的孔位,這樣,如果托盤上有螺栓剩下,操作人員就知道自己漏裝了一個。在軟體生產中,有一種防錯設計是「拼寫錯誤檢查器」,它不允許程序員輸入任何拼寫錯誤的命令,甚至不允許他/她輸入任何非法(非邏輯)命令。軟體https://read•99csw.com研發人員們有越來越多可供選擇的非常精巧的「自動糾錯程序」軟體,用來檢查正在編寫中的程序,以防止典型錯誤的出現。
通用汽車公司在測試新車應對急彎的性能時,會讓這輛車在不同的時速下進行測試,譬如50、60、70英里。顯然,性能隨時速的變化是連續的。如果一輛汽車能夠在時速50、60、70英里的時候通過測試,無需測試我們就會知道,在各種中間速度——比如每小時55或者67英里——的時候,它也肯定能通過測試。
自然亦是如此:它通過犧牲簡潔性來換取可靠性。自然界中存在的神經元迴路,其非最優化程度始終令科學家們瞠目結舌。研究小龍蝦尾部神經細胞的科學家們揭示了這種迴路是多麼令人震驚地臃腫和醜陋。只要花點功夫,他們就能設計出一種緊湊得多的結構。不過,儘管小龍蝦的尾部迴路要比它真正需要的冗餘很多,但卻是不會出錯的。
不過,這是顯而易見的事情。真正的改進在於儘早發現產生錯誤的原因,並儘早清除產生錯誤的原因。如果一個工人總是插錯螺栓,那就設置一個防止插錯螺栓的系統。犯錯的是人,處理錯誤的則是系統。
它們不太容易受控制
加拿大計算機學家戴維·帕那斯曾經對里根的星球大戰計劃提出了8條批評意見。他的觀點基於超級複雜軟體內在的不穩定性,而星球大戰計劃恰恰就是這麼一種超級複雜的軟體。戴維·帕那斯的觀點中,最有趣的一個是指出存在兩種類型的複雜系統:連續的和非連續的。
泰德靠發明新的軟體語言謀生。他是面向對象程序語言的先行者,是Small Talk和Hyper Card的編寫者,現在正在為蘋果電腦研發一種「直接操作」(directmanipulation)式語言。當我問起蘋果的零缺陷軟體時,他一語帶過:「我認為是有可能在產品化的軟體中達到零缺陷的,譬如說你正在寫的又一款資料庫軟體。只要你真正明白自己在幹什麼,就可以做到沒有任何錯誤。」
當你把你的工作成果交付給你的客戶/工作夥伴的時候,他/她就會立刻對它進行檢測,並把其中的錯誤反饋給你,讓你進行修改,讓你知道你的這份工作完成的到底怎麼樣。從某種意義上來看,軟體的這種自下向上的發展過程與羅德尼·布魯克斯的那種包容結構本質上並無不同。每個小步驟都是一個小的代碼模塊,read.99csw.com能確保自身的正常運行,在此基礎上,人們疊加和測試更複雜的層級。
隨著軟體的複雜性迅速增加,在最後關頭對其進行詳細檢測是不可能的。因為它們是非連續的系統,所以總會隱藏著某些詭異的個例或是某種致命的響應——其被激活的幾率可能只有百萬分之一,無論是系統化的測試還是抽樣測試都無法發現它們。另外,儘管統計抽樣能夠告訴我們是否有出錯的可能,卻無法確定出錯的位置。
OOP中的「對象」,其實就像樂高(Lego)積木玩具中的那些小塊,但這些小塊可能還帶著非常微小的智能。一個對象可以類似於蘋果電腦顯示器上的一個文件夾圖標,只不過這個圖標知道自己是一個文件夾,而且可以對某個程序要求所有文件夾列出內容清單的請求作出響應。一個OOP也可以是一張稅表,或者某個僱員在公司的資料庫,或者某個電子郵件信息。對象知道自己能幹什麼不能幹什麼,同時也在和其它的對象橫向交流。
他們不用擔心這輛車以每小時55英里的速度行駛時會突然長出翅膀來或者翻個底朝天。它在這個速度上的性能,基本上就是它在50英里和60英里時性能的某種插值。一輛汽車就是一個連續的系統。
它們並非最優化的
還有那些頂尖級的研發工具可以對程序的邏輯進行分析和評價——它會說,「嘿!這一步根本沒意義!」,從而在邏輯錯誤一出現的時候就將其清除。有一本軟體業的交易雜誌最近列出了近百種檢錯和改錯工具,沽價待售。其中最精緻的一種還可以像那些優質的拼寫檢查軟體一樣,為程序員提供合乎邏輯的改錯選擇。
對於一個超級複雜的系統來說,測試者沒有任何把握說那些沒測試到的值就一定會和抽樣到的數據之間呈現一種連續關係。不過,儘管如此,現在還是出現了一個旨在達到「零缺陷」軟體設計的運動。不用多想,這個運動肯定又是發生在日本。
單靠這些小步驟並不能得到零缺陷的軟體。「零缺陷」的目標隱含著一個關鍵的概念區分。所謂缺陷,是指被交付出去的錯誤;而在交付之前被修正的錯誤,不能算是缺陷。按新鄉重夫的說法,「我們絕對不可能避免錯誤,但是我們可以避免錯誤成為缺陷」。因此,零缺陷設計的任務就是儘早發現錯誤,儘早改正錯誤。
它們很難被理解
面向對象的程序使軟體具備了中等程度的分散式智能。它和其它分散式的存在一樣,有一定的抗錯性,能夠(通過刪除對象)快速修復,並且通過有效單元的組裝來實現擴展。
計算機軟體、分散式網路以及絕大多數的活系統都是非連續的系統。在複雜的適應性系統中,你根本不可能依賴插值函數來判斷系統的行為。你的軟體可能已經平穩運行了好幾年,然後突然在九九藏書某些特定的值點(比如,每小時63.25英里),轟隆一聲系統爆炸,或者,突變為某種全新的東西。
儘管我很看好網路經濟,但是仍然有許多令人擔憂的地方,這些問題也同樣存在於其他的大型、去中心化的自為系統中。
網路式經濟的未來在於設計出可靠的流程,而不是可靠的產品。與此同時,這種經濟的本質意味著這種流程是不可能最優化的。在一個分散式的、半活性的世界中,我們的所有目標只能被「滿意化」,而且這種滿意也只能保持很短的一瞬。也許一天之後整個形勢就完全變化了,正所謂「亂鬨哄,你方唱罷我登場」。
斷點始終都存在著,而你已經測試到了所有的鄰近取值,卻沒有測試到這特別的一組環境值。事情發生后,你會一目了然為什麼這個故障會導致系統崩潰,甚至能明白地指出為什麼人們本該找出這個隱患。不過,這都是事後諸葛亮。在一個擁有海量可能性的系統中,根本不可能對所有的可能性進行測試。更糟糕的是,你還不能依靠抽樣的方式來對系統進行測試,因為它是非連續的系統。
不管各種公司自己會不會變得更像軟體,至少,它們所生產的越來越多的產品肯定會依賴於愈加複雜的軟體,所以說,創造沒有缺陷的複雜系統是絕對必要的。
我曾經問諾貝爾獎得主赫伯特·西蒙如何讓這個零缺陷哲學與他那個「滿意化」概念——不求最優,但求夠好——相包容。他笑著說,「哦,你可以去生產零缺陷的產品。但問題在於你是否能夠以一種有利可圖的方式來生產它?如果你關心的是利潤,那麼你就得對你的零缺陷概念進行滿意化處理。」哦,又是那個複雜性的妥協問題。
在模擬領域,驗證一個模擬的真偽,與測試一個大型複雜軟體是否有缺陷是同一類問題。