Posted on 2007-04-24 19:51
鋒出磨礪 閱讀(257)
評論(0) 編輯 收藏
http://blog.csdn.net/g9yuayon/archive/2007/04/22/1574518.aspx推薦,不管對與錯,作者能夠敢于思考就令人敬佩。思考,思考,再思考。
有時無知是福。俺看到一點新鮮的科普也能覺得造化神奇。剛才讀Gerald Jay Sussman(SICP作者)的文章,Building Robust Systems – an essay,竟然心如小鹿亂撞,手心濕潤,仿佛第一次握住初戀情人溫柔的手。
這篇文章主旨明了:構造復雜的健壯系統非常困難。我們的軟件能夠有效完成某件具體任務,卻不能適應業務領域的變化。一點細微的需求或部署的改動都能讓我們的系統變得脆弱。反觀生物進化的歷史,無數生物在頻繁變更的嚴酷大自然里繁衍生息。也許我們能從中學到讓系統隨環境變更而自動演化的秘密。當然,不是所有的軟件都身段僵硬。35年前問世的Emacs至今是最高效的編輯器之一(不怕惹眾怒地說一句,流行的EditPlus和UltraEdit除了學習曲線,還是不能和Emacs比),實屬居家旅行殺人越貨之必備利器。20年前問世的TeX ,1989年就停止更新代碼,但這并不能阻擋它橫掃科技出版業,變成科技出版物排版的事實標準,基本上干掉了科技出版業里的排版員這項本來很有前途的工作。不過,這些都是特例。我們需要了解的是構造復雜系統的通用方法。不然skynet和matrix怎么能夠問世囁?
Sussman在文章里討論了生物在殘酷進化里得來的五坨特性。這些特性對諳熟生物的老大們也許不是新鮮事,卻能讓我這個靠三思科普生物的半文盲腎上腺素急劇釋放:
- 冗余(redundancy)和簡并(degenerate,不知道這個翻譯對不對)
強健的生物系統都有大量冗余。比如腎和肝。割掉一個腎,我們仍然能活蹦亂跳。把肝的三分之一供奉給乙肝病毒,我們被歧視乙肝攜帶者的公司氣死的幾率也大多得肝癌掛掉的幾率。
生物系統也高度簡并:同一功能可以由不同的部分來完成。比如我們的能量既能從糖獲得,也能從脂肪獲得,還能從蛋白質里獲得(這個造成我們為節食和消耗熱量絞盡腦汁,實屬進化跟不上變化的特例,另當別論)。而這三者的代謝過程都不一樣。甚至我們的遺傳代碼也是簡并的。我們有20來種氨基酸,但核苷酸構成的密碼子組合卻有64種。這樣才能讓點突變不至于影響某個密碼區的蛋白質,使得突變能積累起來,同時不會導致明顯的表現型后果。不然領導某天生出一特聰明的小孩兒(變異了),但就是長得像頭羊,我們非得抓狂不可。簡并成于進化,也成就進化。環境改變了,大不了某個部分廢掉,但生命繼續(系統依然滿足規格)。而廢掉的功能為變異(或修補)騰出空間。整個系統沒有被驚擾。
現在的軟件系統往往包含冗余,但很少刻意加入簡并。作者順便對Python拍磚:Python的口號是TIOWWTDI(There is only one way to do it),明顯是零簡并系統。
- 探索行為
探索行為也是生物系統健壯的基石。生物需要的合適功能通過“生成-測試”的機制獲得。系統某部分生成功能,而另外相對獨立的部分測試功能,決定接受還是拒絕測試結果。比如說支持細胞上的微管陣列決定細胞的形狀。微管們總是不斷被生成和摧毀。那些有幸碰到細胞膜里穩定子的微管們得以存活。最終結果就是細胞的形狀又穩定子的位置決定。所以細胞形狀的生成和維護機制同確定細胞最終形狀的機制分開(操作系統設計里policy和mechanism分開有點類似)。
探索過程中測試者不必知道行為提供者。行為提供者也不必知道測試機制。這樣的結果是變異和適應非常靈活,因為測試者和行為提供者可以自由發展。反正合者生,不合者死。負面作用就是這種選擇代價高昂。自然選擇的每一秒都伴隨著無數生命的消亡。
- 隔離和定位
我們身體的每一坨細胞都源于單一的受精卵。所有細胞的遺傳信息(才1GM內存?。┒家粯?。但是,我們有各種專門細胞,比如皮膚細胞,神經細胞,肌肉細胞等。這些細胞再進一步組織成組織,器官,和器官系統。這一切之所以可能,是因為細胞們能根據環境特異化。也就是說,細胞的行為并沒有被編入細胞間的信號傳遞,而是由基因組決定。不同的信號組合可以激活或關閉細胞的某項功能。不同的細胞組合起來,進一步實現更為復雜的功能。
優秀的軟件系統有類似的特點。它們高度模塊化。不同的模塊在不同的環境里執行對應的功能,進行不同的組合。
- 防御,修補,和再生
生物大都能防御異物的攻擊,修補缺損的部分,再生死亡的肌體。現在的軟件開始包括防御功能,比如安全特性。不過,很少有強大的修補和再生功能,雖然號稱自己能自我調控的系統不少。前兩年IBM鬧騰得歡的autonomous computing最近好像也讓位給牛皮轟轟的SOA。Erlang的容錯系統倒非常誘人:它的基礎設施讓系統比較輕松地偵測出問題的進程,然后在不影響系統運行的前提下重啟該進程。
- 組合
復雜系統都是又小模塊組合而成。這點我們并不陌生。我們構建的系統模塊依賴事先寫好的規范。比如接口的規范,比如接口調用的順序。這種規范現行的辦法隨著系統復雜程度的增高變得越來越難。相反,人類的基因組信息不過區區1G,還不夠容納一個普通操作系統的規范,卻足以決定我們的構造和行為。我們的“系統接口”必須能夠自我配置,適應環境。代價是系統的初始化時間太長,9月懷胎不過是剛開始。
文章也討論了具備這些通用特性的健壯系統需要哪些基礎功能:
- 通用的部件
健壯的系統總是由一系列通用部件構成。每類部件都有廣泛的應用范圍。每個部件能接受范圍寬廣的輸入,但能輸出范圍狹窄的結果。這好比久經考驗的電子原件。他們能在充斥了噪音信號的環境里正確工作,輸出可以預測的信號。
- 可以擴展的泛型操作符。比如同樣是加號,+, 既可以處理整數相加,也能處理實數相加,也能處理矩陣相見。更重要的是,還能讓用戶擴展該操作符的語義,引入新的功能。這樣不僅能讓新程序容易編寫,而且能舊的程序自然增加功能,應對新的環境。這點其實很多語言都有所支持,尤其是現下流行的動態語言。比如說在Lisp環境下開發,我們可以開發一個簡單的版本,讓程序運行起來。然后我們就在這個運行的程序里不斷調試,修改,和加入新的功能,直到這個系統健全。這里有演示錄像。
- 生成和測試
我們的系統應該讓我們能夠寫出返回多項選擇的函數,然后同步測試這些結果,挑選出合適的結果。如果結果不好,系統自動回溯。這樣做的危險是回溯可能導致指數級的運行時間。不過這也是進化不可避免的代價。其實生成-測試的理念早已用到編程當中。比如Prolog的自動回溯。和眾多動態語言支持的模式匹配--比如Erlang, 比如Scala,比如Ocaml。
- 通過約束得到的普適過程
這個大概是說通過一系列的約束條件,我們可以構建出對應的約束網絡。通過這個網絡,我們能生成適應這些約束條件的過程或函數。這樣生成的函數能滿足廣泛的應用環境。
- 工程中的簡并
作者提出了兩種方法。一是利用AI中常用的技巧:目標導向(goal-directed)的方法。這個本質上是說我們不規定系統怎么做一件事,而是告訴系統要達到什么目標。Prolog簡直是解決這類問題的天生殺手。當然,現代的函數編程語言也是解決這類問題的利器。二是對同一問題實現多種獨立解法,然后讓系統挑選合適的方法。
文章還討論了支持系統健壯和進化的方法:
- 組合子
簡單說,我們應該通過搭配組合相對獨立的部件來構建系統。函數語言對這種編程方式尤其擅長。特別是支持transparent referential integrity和lazy evaluation的函數語言,比如Haskell:我們搭建出基本的模塊。Haskell系統提供一大堆強大的黏合工具,讓我們把這些模塊輕松地組裝起來。不過文章也強調,關鍵還是模塊的質量。函數編程只是有效的手段。
- Continuation
這個特性在Ruby, Python,Scheme, Smalltak等現代動態語言里都有。Continuation是非常強大的編程手段。一個Continuation對象被創建時能保留當時系統的有關狀態,并在其他任意時間被調用。這讓程序員獲得對時間的直接控制。我們可以暫停某段計算,并在一段時間后繼續那段暫停的計算。牛人Avi就利用Smalltak對Continuation的完善支持寫出了絕對讓人驚嘆的Seaside Web編程框架。不信邪的老大們可以去體驗以下用Seaside搭建的應用,dabbledb。
- 回溯和并發
沒有回溯,我們就不能自動檢驗多項選擇,排除不合適的結果。沒有并發,我們不能同時檢驗多個結果,計算的代價太高。這些好像不新鮮。
- 任意聯系
標注元數據便是一個例子。我們不能也不可能預測系統運行時數據間的所有關聯。所以構建可以任意擴展的數據關聯系統就非常重要了。這好像也不新鮮。比如說至少20年前人們就認識到Metaobject Protocol的重要性,有興趣的老大可以去讀這本經典的書?,F在Java支持的Annotation也可以算一個例子。
- 動態配置的接口
這個比較新鮮,屬于正在研究的難題?,F在的方法是讓一個群體內的計算實體(agent)通過不斷地交流信息來建立大家理解的規則。俺沒有看明白。
總之,這篇文章屬于高來高去的主題演講性質的文章,但它對生物系統以及生物系統與計算系統的聯系的描述著實讓我大開眼界。也許文章結尾是最好的總結:正經的工程不過幾千年歷史。我們構造健壯系統的手段還遠未成熟。我們還沒有從漫漫幾十億年生物進化中吸取經驗….