歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Unix知識 >> Unix資訊 >> Unix哲學相關資源匯總

Unix哲學相關資源匯總

日期:2017/3/6 11:37:24   编辑:Unix資訊

Unix哲學起源於Ken Thompson早期關於如何設計一個服務接口簡潔、小巧精干的操作系統的思考,隨著Unix文化在學習如何盡可能發掘Thompson設計思想的過程中不斷成長,同時一路上還從其它許多地方博采眾長。

Unix哲學說來不算是一種正規設計方法。它並不打算從計算機科學的理論高度來產生理論上完美的軟件。那些毫無動力、松松垮垮而且薪水微薄的程序員們,能在短短期限內,如同神靈附體般造出穩定而新穎的軟件——這只不過是經理人永遠的夢呓罷了。

Unix哲學(同其它工程領域的民間傳統一樣)是自下而上的,而不是自上而下的。Unix哲學注重實效,立足於豐富的經驗。你不會在正規方法學和標准中找到它,它更接近於隱性的半本能的知識,即Unix文化所傳播的專業經驗。它鼓勵那種分清輕重緩急的感覺,以及懷疑一切的態度,並鼓勵你以幽默達觀的態度對待這些。

Unix管道的發明人、Unix傳統的奠基人之一Doug McIlroy在[McIlroy78]中曾經說過:

(i)讓每個程序就做好一件事。如果有新任務,就重新開始,不要往原程序中加入新功能而搞得復雜。

(ii)假定每個程序的輸出都會成為另一個程序的輸入,哪怕那個程序還是未知的。輸出中不要有無關的信息干擾。避免使用嚴格的分欄格式和二進制格式輸入。不要堅持使用交互式輸入。

(ⅲ)盡可能早地將設計和編譯的軟件投入試用, 哪怕是操作系統也不例外,理想情況下, 應該是在幾星期內。對拙劣的代碼別猶豫,扔掉重寫。

(iv)優先使用工具而不是拙劣的幫助來減輕編程任務的負擔。工欲善其事,必先利其器。

後來他這樣總結道(引自《Unix的四分之一世紀》(A Quarter Century of Unix [Salus])):

Unix哲學是這樣的:一個程序只做一件事,並做好。程序要能協作。程序要能處理文本流,因為這是最通用的接口。

Rob Pike, 最偉大的C語言大師之一, 在《Notes on C Programming》中從另一個稍微不同的角度表述了Unix的哲學[Pike]:

原則1:你無法斷定程序會在什麼地方耗費運行時間。瓶頸經常出現在想不到的地方,所以別急於胡亂找個地方改代碼,除非你已經證實那兒就是瓶頸所在。

原則2:估量。在你沒對代碼進行估量,特別是沒找到最耗時的那部分之前,別去優化速度。

原則3:花哨的算法在n很小時通常很慢,而n通常很小。花哨算法的常數復雜度很大。除非你確定n總是很大,否則不要用花哨算法(即使n很大,也優先考慮原則2)。

原則4:花哨的算法比簡單算法更容易出bug、更難實現。盡量使用簡單的算法配合簡單的數據結構。

原則5:數據壓倒一切。如果已經選擇了正確的數據結構並且把一切都組織得井井有條,正確的算法也就不言自明。編程的核心是數據結構,而不是算法。

原則6:沒有原則6。

Ken Thompson——Unix最初版本的設計者和實現者,禅宗偈語般地對Pike的原則4作了強調:

拿不准就窮舉。

Unix哲學中更多的內容不是這些先哲們口頭表述出來的,而是由他們所作的一切和Unix本身所作出的榜樣體現出來的。從整體上來說,可以概括為以下幾點:

1. 模塊原則:使用簡潔的接口拼合簡單的部件。

2. 清晰原則:清晰勝於機巧。

3. 組合原則:設計時考慮拼接組合。

4. 分離原則:策略同機制分離,接口同引擎分離。

5. 簡潔原則:設計要簡潔,復雜度能低則低。

6. 吝啬原則:除非確無它法,不要編寫龐大的程序。

7. 透明性原則:設計要可見,以便審查和調試。

8. 健壯原則:健壯源於透明與簡潔。

9. 表示原則:把知識疊入數據以求邏輯質樸而健壯。

10. 通俗原則:接口設計避免標新立異。

11. 緘默原則:如果一個程序沒什麼好說的,就沉默。

12. 補救原則:出現異常時,馬上退出並給出足夠錯誤信息。

13. 經濟原則:寧花機器一分,不花程序員一秒。

14. 生成原則:避免手工hack,盡量編寫程序去生成程序。

15. 優化原則:雕琢前先要有原型,跑之前先學會走。

16. 多樣原則:決不相信所謂“不二法門”的斷言。

17. 擴展原則:設計著眼未來,未來總比預想來得快。

如果剛開始接觸Unix,這些原則值得好好體味一番。談軟件工程的文章常常會推薦大部分的這些原則,但是大多數其它操作系統缺乏恰當的工具和傳統將這些准則付諸實踐,所以,多數的程序員還不能自始至終地貫徹這些原則。蹩腳的工具、糟糕的設計、過度的勞作和臃腫的代碼對他們已經是家常便飯了;他們奇怪,Unix的玩家有什麼好煩的呢。

1.6.1 模塊原則:使用簡潔的接口拼合簡單的部件

正如Brian Kernighan曾經說過的:“計算機編程的本質就是控制復雜度”[Kernighan-Plauger]。排錯占用了大部分的開發時間,弄出一個拿得出手的可用系統,通常與其說出自才華橫溢的設計成果,還不如說是跌跌撞撞的結果。

匯編語言、編譯語言、流程圖、過程化編程、結構化編程、所謂的人工智能、第四代編程語言、面向對象、以及軟件開發的方法論,不計其數的解決之道被拋售者吹得神乎其神。但實際上這些都用處不大,原因恰恰在於它們“成功”地將程序的復雜度提升到了人腦幾乎不能處理的地步。就像Fred Brooks的一句名言[Brooks]:沒有萬能藥。

要編制復雜軟件而又不至於一敗塗地的唯一方法就是降低其整體復雜度——用清晰的接口把若干簡單的模塊組合成一個復雜軟件。如此一來,多數問題只會局限於某個局部,那麼就還有希望對局部進行改進而不至牽動全身。

1.6.2 清晰原則: 清晰勝於機巧

維護如此重要而成本如此高昂;在寫程序時,要想到你不是寫給執行代碼的計算機看的,而是給人——將來閱讀維護源碼的人,包括你自己——看的。

在Unix傳統中,這個建議不僅意味著代碼注釋。良好的Unix實踐同樣信奉在選擇

算法和實現時就應該考慮到將來的可擴展性。而為了取得程序一丁點的性能提升就大幅度增加技術的復雜性和晦澀性,這個買賣做不得——這不僅僅是因為復雜的代碼容易滋生bug,也因為它會使日後的閱讀和維護工作更加艱難。

相反,優雅而清晰的代碼不僅不容易崩潰——而且更易於讓後來的修改者立刻理解。這點非常重要,尤其是說不定若干年後回過頭來修改這些代碼的人可能恰恰就是你自己。

永遠不要去吃力地解讀一段晦澀的代碼三次。第一次也許僥幸成功,但如果發現必須重新解讀一遍——離第一次太久了,具體細節無從回想——那麼你該注釋代碼了,這樣第三次就相對不會那麼痛苦了。

—Henry Spencer

1.6.3 組合原則:設計時考慮拼接組合

如果程序彼此之間不能有效通信,那麼軟件就難免會陷入復雜度的泥淖。

在輸入輸出方面,Unix傳統極力提倡采用簡單、文本化、面向流、設備無關的格式。在經典的Unix下,多數程序都盡可能采用簡單過濾器的形式,即將一個輸入的簡單文本流處理為一個簡單的文本流輸出。

拋開世俗眼光,Unix程序員偏愛這種做法並不是因為他們仇視圖形用戶界面,而是因為如果程序不采用簡單的文本輸入輸出流,它們就極難銜接。

Unix中,文本流之於工具,就如同在面向對象環境中的消息之於對象。文本流界面的簡潔性加強了工具的封裝性。而許多精致的進程間通訊方法,比如遠程過程調用,都存在牽扯過多各程序間內部狀態的傾向。

要想讓程序具有組合性,就要使程序彼此獨立。在文本流這一端的程序應該盡可能不要考慮文本流另一端的程序。將一端的程序替換為另一個截然不同的程序,而完全不驚擾另一端應該很容易做到。

GUI可以是個好東西。有時竭盡所能也不可避免復雜的二進制數據格式。但是,在做一個GUI前,最好還是應該想想可不可以把復雜的交互程序跟干粗活的算法程序分離開,每個部分單獨成為一塊,然後用一個簡單的命令流或者是應用協議將其組合在一起。

在構思精巧的數據傳輸格式前,有必要實地考察一下,是否能利用簡單的文本數據格式;以一點點格式解析的代價,換得可以使用通用工具來構造或解讀數據流的好處是值得的。

當程序無法自然地使用序列化、協議形式的接口時,正確的Unix設計至少是,把盡可能多的編程元素組織為一套定義良好的API。這樣,至少你可以通過鏈接調用應用程序,或者可以根據不同任務的需求粘合使用不同的接口。

(我們將在第7章詳細討論這些問題。)

1.6.4 分離原則: 策略同機制分離,接口同引擎分離

在Unix之失的討論中,我們談到過X系統的設計者在設計中的基本抉擇是實行“機制,而不是策略”這種做法——使X成為一個通用圖形引擎,而將用戶界面風格留給工具包或者系統的其它層次來決定。這一點得以證明是正確的,因為策略和機制是按照不同的時間尺度變化的,策略的變化要遠遠快於機制。GUI工具包的觀感時尚來去匆匆,而光柵操作和組合卻是永恆的。

所以,把策略同機制揉成一團有兩個負面影響:一來會使策略變得死板,難以適應用戶需求的改變,二來也意味著任何策略的改變都極有可能動搖機制。

相反,將兩者剝離,就有可能在探索新策略的時候不足以打破機制。另外,我們也可以更容易為機制寫出較好的測試(因為策略太短命,不值得花太多精力在這上面)。

這條設計准則在GUI環境之外也被廣泛應用。總而言之,這條准則告訴我們應該設法將接口和引擎剝離開來。

實現這種剝離的一個方法是,比如,將應用按照一個庫來編寫,這個庫包含許多由內嵌腳本語言驅動的C服務程序,而至於整個應用的控制流程則用腳本來撰寫而不是用C語言。這種模式的經典例子就是Emacs編輯器,它使用內嵌的腳本語言Lisp解釋器來控制用C編寫的編輯原語操作。我們會在第11章討論這種設計風格。

另一個方法是將應用程序分成可以協作的前端和後端進程,通過套接字上層的專用應用協議進行通訊;我們會在第5章和第7章討論這種設計。前端實現策略,後端實現

機制。比起僅用單個進程的整體實現方式來說,這種雙端設計方式大大降低了整體復雜度,bug有望減少,從而降低程序的壽命周期成本。

1.6.5 簡潔原則:設計要簡潔,復雜度能低則低

來自多方面的壓力常常會讓程序變得復雜(由此代價更高,bug更多),其中一種壓力就是來自技術上的虛榮心理。程序員們都很聰明,常常以能玩轉復雜東西和耍弄抽象概念的能力為傲,這一點也無可厚非。但正因如此,他們常常會與同行們比試,看看誰能夠鼓搗出最錯綜復雜的美妙事物。正如我們經常所見,他們的設計能力大大超出他們的實現和排錯能力,結果便是代價高昂的廢品。

“錯綜復雜的美妙事物”聽來自相矛盾。Unix程序員相互比的是誰能夠做到“簡潔而漂亮”並以此為榮,這一點雖然只是隱含在這些規則之中,但還是很值得公開提出來強調一下。

—Doug McIlroy

更為常見的是(至少在商業軟件領域裡),過度的復雜性往往來自於項目的要求,而這些要求常常基於當月的推銷熱點,而不是基於顧客的需求和軟件實際能夠提供的功能。許多優秀的設計被市場推銷所需要的大堆大堆“特性清單”扼殺——實際上,這些特性功能幾乎從未用過。然後,惡性循環開始了:比別人花哨的方法就是把自己變得更花哨。很快,龐大臃腫變成了業界標准,每個人都在使用臃腫不堪、bug極多的軟件,連軟件開發人員也不敢敝帚自珍。

無論以上哪種方式,最後每個人都是失敗者。

要避免這些陷阱,唯一的方法就是鼓勵另一種軟件文化,以簡潔為美,人人對龐大復雜的東西群起而攻之——這是一個非常看重簡單解決方案的工程傳統,總是設法將程序系統分解為幾個能夠協作的小部分,並本能地抵制任何用過多噱頭來粉飾程序的企圖。

這就有點Unix文化的意味了。

1.6.6 吝啬原則: 除非確無它法,不要編寫龐大的程序

“大”有兩重含義:體積大,復雜程度高。程序大了,維護起來就困難。由於人們對花費了大量精力才做出來的東西難以割捨,結果導致在龐大的程序中把投資浪費在注定要失敗或者並非最佳的方案上。

(我們會在第13章就軟件的最佳大小進行更多的詳細討論。)

1.6.7 透明性原則:設計要可見,以便審查和調試

因為調試通常會占用四分之三甚至更多的開發時間,所以一開始就多做點工作以減少日後調試的工作量會很劃算。一個特別有效的減少調試工作量的方法就是設計時充分考慮透明性和顯見性。

軟件系統的透明性是指你一眼就能夠看出軟件是在做什麼以及怎樣做的。顯見性指程序帶有監視和顯示內部狀態的功能,這樣程序不僅能夠運行良好,而且還可以看得出它以何種方式運行。

設計時如果充分考慮到這些要求會給整個項目全過程都帶來好處。至少,調試選項的設置應該盡量不要在事後,而應該在設計之初便考慮進去。這是考慮到程序不但應該能夠展示其正確性,也應該能夠把原開發者解決問題的思維模型告訴後來者。

程序如果要展示其正確性,應該使用足夠簡單的輸入輸出格式,這樣才能保證很容易地檢驗有效輸入和正確輸出之間的關系是否正確。

出於充分考慮透明性和顯見性的目的,還應該提倡接口簡潔,以方便其它程序對其進行操作——尤其是測試監視工具和調試腳本。

1.6.8 健壯原則: 健壯源於透明與簡潔

軟件的健壯性指軟件不僅能在正常情況下運行良好,而且在超出設計者設想的意外條件下也能夠運行良好。

大多數軟件禁不起磕碰,毛病很多,就是因為過於復雜,很難通盤考慮。如果不能夠正確理解一個程序的邏輯,就不能確信其是否正確,也就不能在出錯的時候修復它。

這也就帶來了讓程序健壯的方法,就是讓程序的內部邏輯更易於理解。要做到這一點主要有兩種方法:透明化和簡潔化。

就健壯性而言,設計時要考慮到能承受極端大量的輸入,這一點也很重要。這時牢記組合原則會很有益處;經不起其它一些程序產生的輸入(例如,原始的Unix C編譯器據說需要一些小小的升級才能處理好Yacc的輸出)。當然,這其中涉及的一些形式對人類來說往往看起來沒什麼實際用處。比如,接受空的列表/字符串等等,即使在人們很少或者根本就不提供空字符串的地方也得如此,這可以避免在用機器生成輸入時需要對這種情況進行特殊處理。

—Henry Spencer

在有異常輸入的情況下,保證軟件健壯性的一個相當重要的策略就是避免在代碼中出現特例。bug通常隱藏在處理特例的代碼以及處理不同特殊情況的交互操作部分的代碼中。

上面我們曾說過,軟件的透明性就是指一眼就能夠看出來是怎麼回事。如果“怎麼回事”不算復雜,即人們不需要絞盡腦汁就能夠推斷出所有可能的情況,那麼這個程序就是簡潔的。程序越簡潔,越透明,也就越健壯.

模塊性(代碼簡樸,接口簡潔)是組織程序以達到更簡潔目的的一個方法。另外也有其它的方法可以得到簡潔。接下來就是另一個。

1.6.9 表示原則: 把知識疊入數據以求邏輯質樸而健壯

即使最簡單的程序邏輯讓人類來驗證也很困難,但是就算是很復雜的數據,對人類來說,還是相對容易地就能夠推導和建模的。不信可以試試比較一下,是五十個節點的指針樹,還是五十行代碼的流程圖更清楚明了;或者,比較一下究竟用一個數組初始化器來表示轉換表,還是用switch語句更清楚明了呢?可以看出,不同的方式在透明性和清晰性方面具有非常顯著的差別。參見Rob Pike的原則5。

數據要比編程邏輯更容易駕馭。所以接下來,如果要在復雜數據和復雜代碼中選擇一個,寧願選擇前者。更進一步:在設計中,你應該主動將代碼的復雜度轉移到數據之中去。

此種考量並非Unix社區的原創,但是許多Unix代碼都顯示受其影響。特別是C語言對指針使用控制的功能,促進了在內核以上各個編碼層面上對動態修改引用結構。在

結構中用非常簡單的指針操作就能夠完成的任務,在其它語言中,往往不得不用更復雜的過程才能完成。

(我們將在第9章再討論這些技術。)

1.6.10 通俗原則:接口設計避免標新立異

(也就是眾所周知的“最少驚奇原則”。)

最易用的程序就是用戶需要學習新東西最少的程序——或者,換句話說,最易用的程序就是最切合用戶已有知識的程序。

因此,接口設計應該避免毫無來由的標新立異和自作聰明。如果你編制一個計算器程序,‘+’應該永遠表示加法。而設計接口的時候,盡量按照用戶最可能熟悉的同樣功能接口和相似應用程序來進行建模。

關注目標受眾。他們也許是最終用戶,也許是其他程序員,也許是系統管理員。對於這些不同的人群,最少驚奇的意義也不同。

關注傳統慣例。Unix世界形成了一套系統的慣例,比如配置和運行控制文件的格式,命令行開關等等。這些慣例的存在有個極好的理由:緩和學習曲線。應該學會並使用這些慣例。

(我們將在第5章和第10章討論這些傳統慣例。)

最小立異原則的另一面是避免表象相似而實際卻略有不同。這會極端危險,因為表象相似往往導致人們產生錯誤的假定。所以最好讓不同事物有明顯區別,而不要看起來幾乎一模一樣。

—Henry Spencer

1.6.11 緘默原則:如果一個程序沒什麼好說的,就保持沉默

Unix中最古老最持久的設計原則之一就是:若程序沒有什麼特別之處可講,就保持沉默。行為良好的程序應該默默工作,決不唠唠叨叨,礙手礙腳。沉默是金。

“沉默是金”這個原則的起始是源於Unix誕生時還沒有視頻顯示器。在1969年的緩慢的打印終端,每一行多余的輸出都會嚴重消耗用戶的寶貴時間。現在,這種情況已不復存在,一切從簡的這個優良傳統流傳至今。

我認為簡潔是Unix程序的核心風格。一旦程序的輸出成為另一個程序的輸入,就很容易把需要的數據挑出來。站在人的角度上來說――重要信息不應該混雜在冗長的程序內部行為信息中。如果顯示的信息都是重要的,那就不用找了。

—Ken Arnold

設計良好的程序將用戶的注意力視為有限的寶貴資源,只有在必要時才要求使用。

(我們將在第11章末尾進一步討論緘默原則及其理由。)

1.6.12 補救原則: 出現異常時,馬上退出並給出足量錯誤信息

軟件在發生錯誤的時候也應該與在正常操作的情況下一樣,有透明的邏輯。最理想的情況當然是軟件能夠適應和應付非正常操作;而如果補救措施明明沒有成功,卻悄無聲息地埋下崩潰的隱患,直到很久以後才顯現出來,這就是最壞的一種情況。

因此,軟件要盡可能從容地應付各種錯誤輸入和自身的運行錯誤。但是,如果做不到這一點,就讓程序盡可能以一種容易診斷錯誤的方式終止。

同時也請注意Postel的規定[8]:“寬容地收,謹慎地發”。Postel談的是網絡服務程序,但是其含義可以廣為適用。就算輸入的數據很不規范,一個設計良好的程序也會盡量領會其中的意義,以盡量與別的程序協作;然後,要麼響亮地倒塌,要麼為工作鏈下一環的程序輸出一個嚴謹干淨正確的數據。

然而,也請注意這條警告:

最初HTML文檔推薦“寬容地接受數據”,結果因為每一種浏覽器都只接受規范中一個不同的超集,使我們一直倍感無奈。要寬容的應該是規范而不是它們的解釋工具。

—Doug McIlroy

McIlroy 要求我們在設計時要考慮寬容性,而不是用過分縱容的實現來補救標准的不足。否則,正如他所指出的一樣,一不留神你會死得很難看。

1.6.13 經濟原則: 寧花機器一分,不花程序員一秒

在Unix早期的小型機時代,這一條觀點還是相當激進的(那時機器要比現在慢得多也貴得多)。如今,隨著技術的發展,開發公司和大多數用戶(那些需要對核爆炸進行建模或處理三維電影動畫的除外)都能夠得到廉價的機器,所以這一准則的合理性就顯然不用多說啦!

但不知何故,實踐似乎還沒完全跟上現實的步伐。如果我們在整個軟件開發中很嚴格的遵循這條原則的話,大多數的應用場合都應該使用高一級的語言,如Perl、Tcl、Python、Java、Lisp,甚至shell——這些語言可以將程序員從自行管理內存的負擔中解放出來(參見[Ravenbrook])。

這種做法在Unix世界中已經開始施行,盡管Unix之外的大多數軟件商仍堅持采用舊Unix學派的C(或C++)編碼方法。本書會在後面詳細討論這個策略及其利弊權衡。

另一個可以顯著節約程序員時間的方法是:教會機器如何做更多低層次的編程工作,這就引出了……

1.6.14 生成原則: 避免手工hack,盡量編寫程序去生成程序

眾所周知,人類很不善於干辛苦的細節工作。因此,程序中的任何手工hacking都是滋生錯誤和延誤的溫床。程序規格越簡單越抽象,設計者就越容易做對。由程序生成代碼幾乎(在各個層次)總是比手寫代碼廉價並且更值得信賴。

我們都知道確實如此(畢竟這就是為什麼會有編譯器、解釋器的原因),但我們卻常常不去考慮其潛在的含義。對於代碼生成器來說,需要手寫的重復而麻木的高級語言代碼,與機器碼一樣是可以批量生產的。當代碼生成器能夠提升抽象度時——即當生成器的說明性語句要比生成碼簡單時,使用代碼生成器會很合算,而生成代碼後就根本無需再費力地去手工處理了。

在Unix傳統中,人們大量使用代碼生成器使易於出錯的細節工作自動化。Parser/Lexer生成器就是其中的經典例子,而makefile生成器和GUI界面式的構建器(interface builder)則是新一代的例子。

(我們會在第9章討論這些技術。)

1.6.15 優化原則: 雕琢前先得有原型,跑之前先學會走

原型設計最基本的原則最初來自於Kernighan 和 Plauger 所說的“90%的功能現在能實現,比100%的功能永遠實現不了強”。做好原型設計可以幫助你避免為蠅頭小利而投入過多的時間。

由於略微不同的一些原因,Donald Knuth(程序設計領域中屈指可數的經典著作之一《計算機程序設計藝術》的作者)廣為傳播普及了這樣的觀點:“過早優化是萬惡之源”[9]。他是對的。

還不知道瓶頸所在就匆忙進行優化,這可能是唯一一個比亂加功能更損害設計的錯誤。從畸形的代碼到雜亂無章的數據布局,犧牲透明性和簡潔性而片面追求速度、內存或者磁盤使用的後果隨處可見。滋生無數bug,耗費以百萬計的人時——這點芝麻大的好處,遠不能抵消後續排錯所付出的代價。

經常令人不安的是,過早的局部優化實際上會妨礙全局優化(從而降低整體性能)。在整體設計中可以帶來更多效益的修改常常會受到一個過早局部優化的干擾,結果,出來的產品既性能低劣又代碼過於復雜。

在Unix世界裡,有一個非常明確的悠久傳統(例證之一是Rob Pike以上的評論, 另一個是Ken Thompson關於窮舉法的格言):先制作原型,再精雕細琢。優化之前先確保能用。或者:先能走,再學跑。“極限編程”宗師Kent Beck從另一種不同的文化將這一點有效地擴展為:先求運行,再求正確,最後求快。

所有這些話的實質其實是一個意思:先給你的設計做個未優化的、運行緩慢、很耗內存但是正確的實現,然後進行系統地調整,尋找那些可以通過犧牲最小的局部簡潔性而獲得較大性能提升的地方。

制作原型對於系統設計和優化同樣重要——比起閱讀一個冗長的規格說明,判斷一個原型究竟是不是符合設想要容易得多。我記得Bellcore有一位開發經理,他在人們還沒有談論“快速原型化”和“敏捷開發”前好幾年就反對所謂的“需求”文化。他從不提交冗長的規格說明,而是把一些shell腳本和awk代碼結合在一起,使其基本能夠完成所需要的任務,然後告訴客戶派幾個職員來使用這些原型,問他們是否喜歡。如果喜歡,他就會說“在多少多少個月之後,花多少多少的錢就可以獲得一個商業版本”。他的估計往往很精確,但由於當時的文化,他還是輸給了那些相信需求分析應該主導一切的同行。

—Mike Lesk

借助原型化找出哪些功能不必實現,有助於對性能進行優化;那些不用寫的代碼顯然無需優化。目前,最強大的優化工具恐怕就是delete鍵了。

我最有成效的一天就是扔掉了1000行代碼。

—Ken Thompson

(我們將在第12章對相關內容進行深一步討論。)

1.6.16 多樣原則:決不相信所謂“不二法門”的斷言

即使最出色的軟件也常常會受限於設計者的想象力。沒有人能聰明到把所有東西都最優化,也不可能預想到軟件所有可能的用途。設計一個僵化、封閉、不願與外界溝通的軟件,簡直就是一種病態的傲慢。

因此, 對於軟件設計和實現來說,Unix傳統有一點很好,即從不相信任何所謂的“不二法門”。Unix奉行的是廣泛采用多種語言、開放的可擴展系統和用戶定制機制。

1.6.17 擴展原則: 設計著眼未來,未來總比預想快

如果說相信別人所宣稱的“不二法門”是不明智的話,那麼堅信自己的設計是“不二法門”簡直就是愚蠢了。決不要認為自己找到了最終答案。因此,要為數據格式和代

碼留下擴展的空間,否則,就會發現自己常常被原先的不明智選擇捆住了手腳,因為你無法既要改變它們又要維持對原來的兼容性。

設計協議或是文件格式時,應使其具有充分的自描述性以便可以擴展。一直,總是,要麼包含進一個版本號,要麼采用獨立、自描述的語句,按照可以隨時插入新的、換掉舊的而不會搞亂格式讀取代碼的方法組織格式。Unix經驗告訴我們:稍微增加一點讓數據部署具有自描述性的開銷,就可以在無需破壞整體的情況下進行擴展,你的付出也就得到了成千倍的回報。

設計代碼時,要有很好的組織,讓將來的開發者增加新功能時無需拆毀或重建整個架構。當然這個原則並不是說你能隨意增加根本用不上的功能,而是建議在編寫代碼時要考慮到將來的需要,使以後增加功能比較容易。程序接合部要靈活, 在代碼中加入“如果你需要……”的注釋。有義務給之後使用和維護自己編寫的代碼的人做點好事。

也許將來就是你自己來維護代碼,而在最近項目的壓力之下你很可能把這些代碼都遺忘了一半。所以,設計為將來著眼,節省的有可能就是自己的精力。

所有的Unix哲學濃縮為一條鐵律,那就是各地編程大師們奉為圭臬的“KISS”原則:

KISS原則

原文:http://www.linuxsong.org/2010/09/unix-philosophy/

Copyright © Linux教程網 All Rights Reserved