歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Unix知識 >> 關於Unix >> UNIX哲學

UNIX哲學

日期:2017/2/28 11:21:19   编辑:關於Unix


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

Keep It Simple, Stupid!
==================================================
也許Unix 最持久的異議恰恰來自Unix 哲學的一個特性,這一條特性是X window 設計者首先明確提出的。X 致力於提供一套“機制,而不是策略”,以支持一套極端通用的圖形操作,從而把使用工具箱和界面的“觀感”(策略)推後到應用層。
Unix 其它系統級的服務也有類似的傾向:行為的最終邏輯被盡可能推後到使用端。Unix用戶可以在多種shell 中進行選擇。而Unix 應用程序通常會提供很多的行為選項和令人眼花缭亂的定制功能。
這種傾向也反映出Unix的遺風:原本是為技術人員設計的操作系統;同時也表明設計的信念:最終用戶永遠比操作系統設計人員更清楚他們究竟需要什麼。
然而這種選擇機制而不是策略的代價是:當用戶“可以”自己設置策略時,他們其實是“必須”自己設置策略。非技術型的終端用戶常常會被Unix 豐富的選項和接口風格搞得暈頭轉向,於是轉而選擇那些偽稱能夠給他們提供簡潔性的操作系統。
只 看眼前的話,Unix 的這種自由放縱主義風格會讓它失去很多非技術型用戶。但從長遠考慮,最終你會發覺這個“錯誤”換來至關重要的優勢:策略相對短壽,而機制才會長存。現今流 行的界面觀感常常會變成明日進化的死胡同(去問問那些使用已經過時的X 工具包的用戶,他們會有一肚子苦水倒給你!)。說來說去,只提供機制不提供方針的哲學能使Unix 長久保鮮;而那些被束縛在一套方針或界面風格內的操作系統,也許早就從人們的視線中消失了。
雖然成型於TOPS-10 的TCP/IP 標准(互聯網的基礎) 在理論上可以與Unix 分開, 但當應用在其它操作系統上時,一直都飽受兼容性差、不穩定、bug 太多等問題的困擾。實際上,理論和規格說明人人都可以獲取, 但是只有Unix 世界中你才見得到這些穩固可靠的現實成果。
從頭到腳的靈活性:
許 多操作系統自诩比起Unix 來有多麼的“現代”,用戶界面又是多麼的“友好”。 它們漂亮外表的背後,卻是以貌似精巧實則脆弱狹隘難用的編程接口,把用戶和開發者禁锢在單一的界面方針下。在這樣的操作系統中,完成設計者(指操作系統) 預見的任務很容易,但如果要完成設計者沒有預料到的任務,用戶不是無計可施就是痛苦不堪。
相反,Unix 具有非常徹底的靈活性。Unix 提供眾多的程序粘合手段,這意味著Unix基本工具箱的各種組件連縱開合後,將收到單個工具設計者無法想象的功效。
Unix 支持多種風格的程序界面(通常也因為給終端用戶增加了明顯的系統復雜度而被視為Unix 的一個缺點),從而增加了它的靈活性;只管簡單數據處理的程序而無需背上精巧圖形界面的擔子。
Unix 傳統將重點放在盡力使各個程序接口相對小巧、簡潔和正交——這也是另一個提高靈活性的方面。整個Unix 系統,容易的事還是那麼容易,困難的事呢,至少是有可能做到的。
Unix 哲學起源於Ken Thompson 早期關於如何設計一個服務接口簡潔、小巧精干的操作系統的思考,隨著Unix 文化在學習如何盡可能發掘Thompson 設計思想的過程中不斷成長,同時一路上還從其它許多地方博采眾長。
Unix 管道的發明人、Unix 傳統的奠基人之一Doug McIlroy 在[McIlroy78]中曾經說過:
(i)讓每個程序就做好一件事。如果有新任務,就重新開始,不要往原程序中加入
新功能而搞得復雜。
(ii)假定每個程序的輸出都會成為另一個程序的輸入,哪怕那個程序還是未知的。
輸出中不要有無關的信息干擾。避免使用嚴格的分欄格式和二進制格式輸入。不要堅持
使用交互式輸入。
(ii)盡可能早地將設計和編譯的軟件投入試用, 哪怕是操作系統也不例外,理想情
況下, 應該是在幾星期內。對拙劣的代碼別猶豫,扔掉重寫。
(iv)優先使用工具而不是拙劣的幫助來減輕編程任務的負擔。工欲善其事,必先
利其器。
Unix 哲學是這樣的:一個程序只做一件事,並做好。程序要能協作。程序要能處理文本流,因為這是最通用的接口。
Rob Pike, 最偉大的C 語言大師之一, 在《Notes on C Programming》中從另一個稍微不同的角度表述了Unix 的哲學[Pike]:
原則1: 你無法斷定程序會在什麼地方耗費運行時間。瓶頸經常出現在想不到的地方,所以別急於胡亂找個地方改代碼,除非你已經證實那兒就是瓶頸所在。
原則2:估量。在你沒對代碼進行估量,特別是沒找到最耗時的那部分之前,別去優化速度。
原則3: 花哨的算法在n 很小時通常很慢,而n 通常很小。花哨算法的常數復雜度很大。除非你確定n 總是很大,否則不要用花哨算法(即使n 很大,也優先考慮原則2)。
原則4:花哨的算法比簡單算法更容易出bug、更難實現。盡量使用簡單的算法配合簡單的數據結構。
原則5:數據壓倒一切。如果已經選擇了正確的數據結構並且把一切都組織得井井有條,正確的算法也就不言自明。編程的核心是數據結構,而不是算法6。
原則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 下,多數程序都盡可能采用簡單過濾器的形式,即將一個輸入的簡單文本流處理為一個簡單的文本流輸出。
拋開世俗眼光,Unix 程序員偏愛這種做法並不是因為他們仇視圖形用戶界面,而是因為如果程序不采用簡單的文本輸入輸出流,它們就極難銜接。
要想讓程序具有組合性,就要使程序彼此獨立。在文本流這一端的程序應該盡可能不要考慮文本流另一端的程序。將一端的程序替換為另一個截然不同的程序,而完全不驚擾另一端應該很容易做到。
GUI 可以是個好東西。有時竭盡所能也不可避免復雜的二進制數據格式。但是,在做一個GUI 前,最好還是應該想想可不可以把復雜的交互程序跟干粗活的算法程序分離開,每個部分單獨成為一塊,然後用一個簡單的命令流或者是應用協議將其組合在一起。
在 構思精巧的數據傳輸格式前,有必要實地考察一下,是否能利用簡單的文本數據格式;以一點點格式解析的代價,換得可以使用通用工具來構造或解讀數據流的好處 是值得的。當程序無法自然地使用序列化、協議形式的接口時,正確的Unix 設計至少是,把盡可能多的編程元素組織為一套定義良好的API。這樣,至少你可以通過鏈接調用應用程序,或者可以根據不同任務的需求粘合使用不同的接口。
將策略同機制剝離,就有可能在探索新策略的時候不足以打破機制。另外,我們也可以更容易為機制寫出較好的測試(因為策略太短命,不值得花太多精力在這上面)。
一個方法是將應用程序分成可以協作的前端和後端進程,通過套接字上層的專用應用協議進行通訊;前端實現策略,後端實現機制。比起僅用單個進程的整體實現方式來說,
這種雙端設計方式大大降低了整體復雜度,bug 有望減少,從而降低程序的壽命周期成本。
來 自多方面的壓力常常會讓程序變得復雜(由此代價更高,bug 更多),其中一種壓力就是來自技術上的虛榮心理。程序員們都很聰明,常常以能玩轉復雜東西和耍弄抽象概念的能力為傲,這一點也無可厚非。但正因如此,他們 常常會與同行們比試,看看誰能夠鼓搗出最錯綜復雜的美妙事物。正如我們經常所見,他們的設計能力大大超出他們的實現和排錯能力,結果便是代價高昂的廢品。
“錯綜復雜的美妙事物”聽來自相矛盾。Unix 程序員相互比的是誰能夠做到“簡潔而漂亮”並以此為榮,這一點雖然只是隱含在這些規則之中,但還是很值得公開提出來強調一下。
—Doug McIlroy
吝啬原則: 除非確無它法,不要編寫龐大的程序。
“大”有兩重含義:體積大,復雜程度高。程序大了,維護起來就困難。由於人們
對花費了大量精力才做出來的東西難以割捨,結果導致在龐大的程序中把投資浪費在注
定要失敗或者並非最佳的方案上.
大多數軟件禁不起磕碰,毛病很多,就是因為過於復雜,很難通盤考慮。如果不能夠正確理解一個程序的邏輯,就不能確信其是否正確,也就不能在出錯的時候修復它。
這也就帶來了讓程序健壯的方法,就是讓程序的內部邏輯更易於理解。要做到這一點主要有兩種方法:透明化和簡潔化。
軟件的透明性就是指一眼就能夠看出來是怎麼回事。如果人們不需要絞盡腦汁就能夠推斷出所有可能的情況,那麼這個程序就是簡潔的。程序越簡潔,越透明,也就越健壯.
數據要比編程邏輯更容易駕馭。所以接下來,如果要在復雜數據和復雜代碼中選擇一個,寧願選擇前者。更進一步:在設計中,你應該主動將代碼的復雜度轉移到數據之中去。
最易用的程序就是用戶需要學習新東西最少的程序——或者,換句話說,最易用的程序就是最切合用戶已有知識的程序。
因此,接口設計應該避免毫無來由的標新立異和自作聰明。如果你編制一個計算器程序,‘+’應該永遠表示加法。而設計接口的時候,盡量按照用戶最可能熟悉的同樣功能接口和相似應用程序來進行建模。
Unix 中最古老最持久的設計原則之一就是:若程序沒有什麼特別之處可講,就保持沉默。行為良好的程序應該默默工作,決不唠唠叨叨,礙手礙腳。沉默是金。
我認為簡潔是Unix 程序的核心風格。一旦程序的輸出成為另一個程序的輸入,就很容易把需要的數據挑出來。站在人的角度上來說――重要信息不應該混雜在冗長的程序內部行為信息中。如果顯示的信息都是重要的,那就不用找了。
—Ken Arnold
借助原型化找出哪些功能不必實現,有助於對性能進行優化;那些不用寫的代碼顯然無需優化。目前,最強大的優化工具恐怕就是delete 鍵了。
我最有成效的一天就是扔掉了1000 行代碼。
--Ken Thompson
Copyright © Linux教程網 All Rights Reserved