來自Unix/Linux的編程啓示錄

  最近有消息稱華爲在中國區開始集中清理34歲以上員工,對此華爲總裁任正非作出迴應:“網上傳有員工34歲要退休,不知誰來給他們支付退休金?我們公司沒有退休金,公司是替在職的員工買了社保、醫保、意外傷害保險等。你的退休得合乎國家政策。你即使離職了,也得自己去繳費,否則就中斷了,國家不承認,你以後就沒有養老金了。”

  作者簡介

  大家早上好,新的一週開始了!

  本篇是 江湖人稱小白哥 的第二篇投稿,分享了他從Unix/Linux中獲得的編程感悟,希望能夠幫助到大家。

  江湖人稱小白哥 的博客地址:

  http://blog.csdn.net/dd864140130

  前言

  寫本文的最初靈感源於16年11月份我將工作環境切換到Mac OS上,其中一些使用”差異”讓我開始對 Unix/Linux 中設計產生了濃厚的興趣.雖然從13年開始使用redhat,再到後來一直使用的 ubuntu,但卻從來關注過這些,特此記錄.

  在整個探究過程中,那些經典的著作再次讓我獲益匪淺:C和指針,C專家編程,深入理解計算機系統(原書第3版),Linux/Unix設計思想,Linux Shell腳本攻略.前兩本書購於13年,斷斷續續的讀了許久,這一次重讀令人豁然開朗,其中許多不解之處在深入理解計算機系統一書得到答案,而後兩本則是年前有幸讀到.其中 Linux/Unix 設計思想不談技術細節,卻揭示了 Linux/Unix 隱含的指導思想,最後一本則是從 Shell 出發,以實踐的角度教你如何利用 Shell(Bash) 在 Linux/Unix 平臺上構建有效的解決方案,實乃入門進階必備啊.

  從女媧造人說起

  俗說天地開闢,未有人民,女媧摶黃土作人.劇務,力不暇供,乃引繩於泥中,舉以爲人.故富貴者,黃土人;貧賤人,引繩人也…

  神一樣的程序員

  “女媧造人”可謂人人皆知,女媧是神,而程序員是能力上最接近女媧的存在.如果說女媧創造的是真實的世界,那麼程序員是創造數字的世界,我們所寫下的每行代碼,所構建每個程序,都在讓這個數字世界變得豐富多彩.

  沒有哪個職業可以像程序員:賦予代碼以生命,創造數字世界中的花花草草!儘管我們擁有近乎神的能力,本身卻也受着NIH綜合徵的困擾.

  程序員之殤

  NIH綜合徵是什麼?

  Not invented here (NIH) is a stance adopted by social, corporate, or institutional cultures that avoid using or buying already existing products, research, standards, or knowledge because of their external origins and costs.

  我們經常爲NIH所困:在求解解決方案時,經常自認爲可以做得更好或者在看到別人的解決方案會提出各種質疑.這大都是我們缺乏對當時問題解決者所面臨限制的認識所造成:可能迫於時間或者預算的限制,也可能受限於當時物理資源的限制.

  穿着衣服的猴子

  NIH綜合徵的特點就是人們會爲了證明自己能夠提供更加卓越的解決方案而放棄其他開發人員已經完成的工作.這種狂妄自大的行徑說明此人並無興趣去維護他人竭盡全力提供的最佳成果,也不想以此爲基礎去挑戰新的高度.NIH綜合徵本質上是動物天性—”嘿,我更好”的體現,就像所有的公猴都會向母猴證明”我更好”一樣.

  放棄已有工作成果而另起爐竈的做法無形之間浪費了大量時間.有一些技術人員在入職新公司後,往往有想推倒一切重來的慾望.我曾經有位朋友連續跳槽很多家公司,每次入職之前都信心滿滿,不就後就黯然離開.朋友能力很不錯,但每次入職後總是急於通過推倒重來來證明自己的能力.

  更糟的是,新的解決方案往往只是做了一些改進,和之前並無本質區別,再加上現代的應用往往動輒十幾萬行,遠超出每個人所能注意的極限,這也會讓程序員產生疏漏,從而使得這個問題變得更糟糕.

  當然,少數情況下,新的解決方案更好,這只是因爲技術人員早已瞭解做過的工作,從而針對問題可以提出更高的解決方案.站在現在的角度看歷史,還看不出對錯的話,除非你對歷史一無所知.

  爲什麼Linux會成功

  Linux 爲什麼會成功有很多的的因素,除卻當時環境因素外,其成功之處在於開源的世界讓每個人都能得到 Linux源碼,從而使得經驗可以被借鑑.事實上,在原有軟件基礎上進行擴展是Unix的核心概念之一.當然,在Linux出現之前,借鑑他人編寫的軟件已成爲相當普遍的做法,這也是GUN宣言中的GPL下所闡釋的思想.

  來自Unix/Linux的編程啓示錄

  現在我們來看看 Unix/Linux 中那些隱藏的編程哲學,需要說明的是 Unix/Linux 中的編程哲學非常通俗易懂,他們大多是你已知的,更多的時候是我們不曾注意到.

  無論你現在負責的系統多麼複雜,這總有可以幫助你的地方.(要說複雜,還有什麼比 Unix/Linux 更爲複雜的應用?)

  原則一:小既是美

  我猜當你看到”小既是美”一詞時會首先想到一句諺語”麻雀雖小,五臟俱全”.那就用麻雀做引子來說說爲什麼小即是美.

  大凡生物,無論形體如何,愈小愈穩定.麻雀相對人而言,出現腦殘鳥的機率要小的多,而單細胞生物相對多細胞生物產生顯著變異體的概率也要小的多…在軟件工程中,同樣如此.Unix中的程序大凡遵循這條準則,小帶來的顯著優點如下:

  易於編寫

  易於理解

  易於維護

  消耗更少的系統資源

  容易與其他工具組合

  儘管我知道你已經對其有過了解,我還是例行的囉嗦一下.

  每個程序員心中都有編寫一個萬能軟件的想法,渴望像上帝一樣創世,能夠名垂青史,但這實在是太難了.越是複雜的問題越令人畏縮不前,想想在上學期間,你是更樂於立刻開始做一道題還是一套題呢?不出意外,我們大都喜歡從一道題開始.編寫小程序同樣如此:我們能夠儘快的動手去做,並且針對某個點找出更合理的解決方案.另外,由於大腦的結構,我們無法同時關注超過四個以上的點,而複雜的程序需要被關注的點卻遠大於四個,這就意味着我們可能會犯更多的錯誤.

  小程序帶來的另一個好處就是容易理解,一個100行的程序比一個1000行的程序要容易理解的多(複雜度相同的情況下).

  當程序足夠小的時候它就是函數,還有什麼比函數更靈活地自由組合呢?當然大多數小程序不能夠小到只有一個函數,但儘可能的減小程序大小仍然很重要,unix/linux中的命令便是最佳的示例:cp用來拷貝,rm用來刪除,組合起來就可以實現移動,簡直棒呆了.

  我想,沒人會認爲麻雀每天攝入的能量會比人多吧?換到程序當中就是越小的程序消耗的系統資源會更少,大多數情況下如此.

  原則二:讓每個程序只做好一件事情

  程序員也許只想編寫一個簡單的應用程序,但是隨着他的創新精神佔據上風,促使他在會在這裏添加一個功能,在那裏添加一個選項,很快你就發現本來你只想要一個文本編輯器,但是他卻給你一個IDE,最終他給你的往往不是驚喜而是大雜燴.這個問題不但在程序員身上體現出來,同樣也會出現在產品經理上:想要一個計算器對麼,我這裏有個超級計算機可以給你用?現在你只能面對這這麼一個龐然大物了

  該思想和”小即是美”相輔相成,”專注一件事”的應用最終會產生一個較小的程序,而小程序往往只有單一的功能,單一功能的程序往往也會很小.另外,每個程序只做一件事情也意味着我們可以集中精力去解決當前任務,全新全意做好本職工作.

  原則三:建立原型

  原型的建立是學習的過程:在該過程中可以知道哪些想法可行,哪些不可行.每一個正確設計的背後都有數百個錯誤的設計方案,通過建立原型,我們可以在早期剔除掉不良的設計方案,以此來降低風險.換句話說,越早的建立原型,離你的軟件發佈的時間越近.

  你的軟件發佈了嗎?

  從開始接觸軟件工程開始起,我們的前輩就告訴我們:”軟件永遠不會有開發完的時候,記住,是永遠!”.

  “怎麼會完不成呢,我只要不做了不就行了麼?”,現在想想,這比讓一個沉迷在購物中的女人停下腳步更難(如果錢是無盡的話).編寫軟件亦如此,你永遠都會想要加入的更多的功能.想加入的更多功能的可能不是你,或者是你的產品經理,當然你的boss也會摻一腳.

  我一直在向周圍的朋友傳遞這麼一種觀點”世界上唯有不變的事物那就是變“,對於軟件工程同樣如此.既然變化無可避免,那軟件是怎麼完成的?儘管我們做事都希望看到最後的結局,但是對於軟件而言並非如此.可以說,沒有做完的軟件,只有發佈的軟件.

  我曾犯過類似的錯誤.16年我在負責一款移動端產品的開發,希望在一個月內上線第一個版本.由於個人疏忽,當我着手原型工作時離發佈時間只有20天的時間了,在這期間發現原有的一些方案無法奏效,我不得不臨時更改一些既有的設計.最終導致第一個版本正式發佈的時間超出15天.我也曾因此被認爲是個糟糕的工程師.在團隊沒有任何移動應用產品開發的經驗下,及早的開始建立原型或許不會導致如此後果.在離開這家公司之後,我仍倍感慚愧.

  原則四:捨棄高效率而取可移植性

  偏向高效率往往會導致代碼不可移植,而選擇可移植性往往會讓軟件的的性能不那麼盡如人意.每當有爲了追求高效率而放棄移植性的想法的時候,請在心中默唸以下兩句話:

  1. 速度欠佳的缺點會被明天的機器克服

  2. 好程序不會消失,而被移植到新平臺.

  關於優化的兩點建議

  在unix環境中,可移植性的含義通常意味着人們要轉而採用shell腳本來編寫軟件.拋開平臺不談,關於優化,我有以下兩點建議:

  不要立刻優化:如無必要,無須優化.換句話說,不要想當然的優化,尤其是在用戶無感覺的情況下.

  關注微優化:影響性能的往往只有幾處,在需要優化的時候只要解決這幾處就好,切莫以優化的名義重構全部.

  原則五:使用純文本來存儲數據

  文本不一定是性能最好的格式,但卻是最通用的.另外,文本文件易於閱讀和編輯:在任何平臺上我們可以輕鬆的閱讀文本數據,或使用標準文本編輯器對其進行編輯.

  你可能會考慮到使用純文本文件拖慢了系統的處理速度,並會找出一系列的證據來證明處理字符串的性能更低.我們承認文本文件確實拖累了系統的性能,但是記住明天系統的機器的性能必將有大幅度的提高.

  原則六:利用軟件的槓桿效應

  給你一個槓桿,在不考慮槓桿質量的前提下,你真的可以撬動地球.一個人精力只有這麼多,如果想要取得非凡的成就,你就必須放大自己對這個世界的影響力,這就需要你找到其中的”槓桿點”,也就是關鍵點.

  君子性非異也,善假於物也

  軟件中的槓桿效應就是要善於利用他人已有成果,具體點就是學會利用他人寫的代碼.在早期,我希望每一行代碼都是從自己手中出來,並以爲爲傲,並認爲這就是所謂的優秀的程序員.多年之後,我才明白成爲一個優秀程序員的關鍵卻和手敲每行代碼並無必要聯繫.

  善於利用他人的代碼會給程序員自身增加砝碼.這可能和很多人的認知相違背.查看別人工作並誇口說自己做的更好,不代表你能力更強;推導現有的方案在重來,那只是模仿不是創造.想要解決掉你手中的任務,編寫更多軟件的最好方法就是善於借用別人的成果.和大多程序員一樣,我曾認爲親自編寫代碼能帶來”就業保障”,並將這種做法視爲核心競爭力.但實際工作中卻是相反,在實現功能的前提下,企業往往認爲花費時間更少的程序員更具有高效的生產了,你可能對此感到委屈和不解.這裏,我想要說的是:認識企業對你的認識和你對自己認識之間的差異是非常重要的.

  如果有可能,請儘量讓你的工作自動化.通過加強自動化工作來利用軟件的槓桿效應能產生巨大的生產力,並且能夠更充分的利用好時間.如果你是個linux開發者,shell腳本便是你在尋找的槓桿點.

  化作春泥更護花

  從另外一個角度來說,允許他人使用你的代碼來發揮槓桿作用.大部分工程師喜歡私藏自己的源代碼,並視爲獨一無二,舉世珍寶,彷彿自己的”核武器”.他們認爲公開自己的源代碼,自己就失去地位,會被公司所拋棄.

  哪些你以爲是”核武器”的代碼真的就有如此威力麼?要記住:任何一個有着合理思維的正常人都可以編寫出像樣的代碼.更何況,一個有耐心的程序員完全可以將程序反匯編出來,通過一步一的分析,最終發現其中的蛛絲馬跡.

  Linux的開發人員認爲執意保留源碼的控制權並無太大必要.現在你發現,儘管你擁有全部的源碼,但卻仍然不能創造出比Linux更成功的操作系統.我想這足打消你心中哪點憂慮了.

  重新認識自豪感

  現在重新認識所謂的自豪感.很多程序員將寫出優秀的代碼,使用先進的技術視爲自豪感,但我們最終的產出是用來服務用戶的,如果用戶不能滿意,那麼我們所謂的自豪感不過是”孤芳自賞”.

  原則七:使用shell腳本來提高槓杆效應和可移植性

  談起腳本語言,很多工程師覺得腳本太弱了,只能用來編寫簡單的應用無法工程化,並且不少程序員更樂於哪些看起來宏大的 Java 或者 net 應用,甚至有些程序員認爲腳本語言算不上一門語言.現實給了我們一巴掌:我們從來沒有想象過 JavaScript 會有如此發展,以 node 爲代表的新型開發平臺,讓整個 JavaScript 語言變得非常有活力.

  那麼我們是否也小覷了 shell 這種簡單的腳本語言呢?有很長一段時間我不能正確的認識 shell 是什麼,甚至覺得”嗨,這東西好像對我沒什麼用,它能用來幹什麼”.讓我改變想法的恰好是15年的工作經歷.

  和其他腳本語言(如:Python,JavaScript)一樣,shell腳本 同樣由一個或者多個語句組成,通過調用本地程序,解釋程序和其他腳本來執行任務.shell腳本 將每條指令加載到內存執行.大部分情況下,這些指令是由無數的 unix/linux 開發者事先編寫完成,我們要做的就是用 shell 來間接的利用這些高效,安全的代碼.

  比如在 shell 中使用 wget 命令來下載文件時,我們實際書寫的不過幾行語句,背後支撐我們的確有數萬行的代碼,如果讓你來用 java 寫一個下載器會需要多少工程量呢,又需要耗費多少時間?現在有些程序員會反駁我:我用 python 寫起來也很快,代碼也不多?那問題來了,python 的運行環境可不是先天就存在 unix/linux 中的,但是大部分 unix/linux 卻都是支持 shell 的.如果編寫的腳本程序要運行在不同的系統中或者運行在許多設備中,shell 無疑具有更好的移植性,不是麼?

  如你所想,及時運行

  腳本語言有一個先天的優勢就是他們是解釋型的語言,運行前不需要事先編譯.先來看看以C語言爲代表的編譯型語言,要構建一個程序的基本流程如下:

  思考->編輯代碼->編譯->測試

  而在shell當中,整個過程更短:

  思考->編輯->測試

  相比 C語言,shell 不存在編譯過程,這帶來的優勢就是:無論 shell 的應用規模多大多複雜,只要你想你就可以運行它觀察它,而無需像 C語言 一樣等待編譯過程結束後再運行.

  shell真的慢嗎?

  一些程序員對 shell 執行效率過於擔憂,認爲其效率太低,這就導致了他們爲了更高的效率企圖採用 C語言 來重寫腳本.shell腳本 的執行效率相對較慢,一旦 C程序 被裝載到內存中運行, 純C程序 與那些從腳本中調用 C程序 相比,並沒有太大的性能優勢.

  另外,由於 Unix/Linux 中大部分的命令做過相關的優化,反而會比由你編寫的 純C程序 更快.這也引出我想說的另外一點:爲了追求更高的性能而更換語言這一做法有待商榷.如果真是爲了追求性能,那麼改變通過改良實現方法更有效,比如有序數列中查找指定數字採用二分查找比傳統的遍歷查找的時間複雜度更低,而不是將原來實現遍歷查找的java代碼改成C代碼實現.

  原則八:避免強制性的用戶界面

  我最早接觸計算機系統是 Windows 2000,應該是在上小學期間,儘管我不知道這個大個”計算器”能夠做什麼,但是卻可以在沒人教的情況下琢磨去做,並學會玩編輯文字,利用文本編輯器和共享來相互交流,當然,少不了的紙牌和掃雷.

  window和unix/linux理念差異

  用戶界面能夠讓任何一個小白在不需要專業知識的前提邁出操作的第一步.window系列 產品和 unix/linux系列 產品的不同之一在於對於他們對用戶的看法上:window 下的設計者認爲用戶是畏懼和計算機打交道的,因而提供足夠的用戶界面來消除用戶的恐懼心理,而unix的設計理念則不同,它認爲一個接觸 unix/linux 的用戶已經具備了基本的計算機素養,併力求更全面的掌握它,從這個角度而言,unix/linux 是選擇用戶的,而 window 是服務用戶的.

  這也是早期 window 比 unix/linux 更爲大衆所接受的關鍵因素之一.但隨着 unix/linux 的逐漸發展以及大衆計算機素養的提升,越來越多的人開始接受 unix/linux 產品,並熱衷與此.

  像搭積木一樣編程

  對於程序員而言,我們希望編程應該像搭積木一樣,通過不同的組合來實現多樣的產品,未來的產品也應該是如此:一些程序員負責開發基礎的小模塊,另外一些程序員則負責將這些小模塊對接成客戶所需要的產品.對 Unix/Linux 開發者而言的確如此,我們可以利用系統中提供的衆多非界面性小程序來組合成我們所需要的.但是對於提供用戶界面的小程序而言我們卻很難做到這點:用戶界面渴望與用戶溝通而非另一個程序,而模擬人在用戶界面上的溝通並非易事,你需要花費更多的精力放在非核心需求上.

  即使我們能夠模擬,從操作效率來看也不容樂觀.畢竟用戶界面相對命令程序而言本身意味着更多的資源消耗,我想沒人願意在服務器上裝一個KDE吧?這就是 window 下同樣擁有衆多的小程序但卻很難將其組合成新產品的原因之一,換言之我們很難利用前人已產生的成果來發揮槓桿作用.

  嗨,我們需要再加個按鈕

  程序員和產品之間總有一個矛盾點,來看看下面這個對話.

  PM:”這裏加個按鈕”

  RD:”又沒有人用,不加不行麼?”

  PM:”聽我的,加上吧!加了按鈕之後就會有人點擊…”

  RD:”好吧…”

  PM:”你看這個地方空白好大,能再加一個按鈕麼?”

  RD:”我….”

  好吧,這是個笑話,我並非想挑起程序員和產品之間的戰爭.如果你在設計/開發一個界面化的產品,你經常會不由自主的爲他加上更多的按鈕,企圖讓他提供更豐富的功能:你總覺得有人會需要它.最終導致項目更加複雜,但用戶滿意度卻未見提升.

  有這麼一件事到現在對我影響甚大.我想把Kindle中的筆記導出到印象筆記,這件事情本來很簡單,只需要導出指定的文本文件,解析後導入到印象筆記就可以.來看看當時我想了什麼:我應該做一個界面,可以方便的我操作,別人也可能需要一個保存筆記成html格式的功能,所以我要添加個轉換按鈕,當然,保存,導出按鈕也不能忘了,等等…要不要編輯功能?…

  這非常好笑,不是麼?由於我第一時間想到了圖形界面,接下來不由自主地想在界面上添加更多的功能,更重要的是我明明是自己使用的,卻站在別人的角度上去給自己提了需求?

  如果最終呈現出的是圖形化的產品,會發生很有意思的事情.來想一下,我希望它能在每天十二點自動完成導出任務?難道我要再寫一個程序來模擬點擊操作麼?既然這樣,爲什麼不能讓兩個程序有能夠直接交流的能力麼?(感謝unix/linux中的管道機制)

  現在來看到底發生了什麼?當我們想提供界面的時候,就假設是人在操作.這個隱形的假設最終讓這個程序失去了自由,好比送給孩子一個用膠水粘合積木而成的城堡而非一盒積木.

  原則九:讓每個程序都成爲過濾器

  程序是什麼?早期認爲 程序=算法+數據.但從功能的角度來說,程序即 過濾器.

  先不要着急罵我或者反駁我.你不覺得在你編寫的每個程序中,無論是複雜還是簡單,都是以某種形式接受數據,併產生一些數據作爲輸出麼?這些要輸出的數據不就是取決於程序中的算法麼?有一些人爲過濾器就該是過濾掉不符合期望的東西,而非轉換,比如存在一個程序用於過濾掉集合中元素值爲0的元素,這對於大部分人而言是最直觀的有關過濾的理解.但要記住過濾器同樣也包含轉換的概念.

  對於計算器而言,我們輸入錯誤會產生錯誤提示,而決定產生什麼樣錯誤信息的算法就是錯誤狀態輸入的過濾器.可以說算法是人根據需求定義的規則,即算法由人定義.那數據又是怎麼來的?一個沒有數據輸入/輸出的程序就像一個不會進食和排泄的人,這種程序沒有存在的價值,現實世界也不存在這種人.

  原則十:並行思考

  計算機界有個經典的笑話:如果一個女人要花是十個月生下一個嬰兒,是否意味着能讓十個女人在一個月內生出一個嬰兒呢?笑話中透出的含義非常明顯:自然特性導致某些任務必須被串行,任何試圖讓其並行運行的舉動都無法加快它的進程.

  在數字計算機的整個歷史中,有兩個需求不斷的驅動我們:一是我們想計算機做的更多,令一個是我們想要計算機運行的更快.而併發則是實現這兩個需求有效途徑.對程序設計而言,並行思考意味着我們應該儘可能利用CPU運算性能,這也要求我們要對任務進行細緻有效的分解,尋找其串行路徑和並行路徑.

  現代操作系統通過提供進程,線程及I/O多路複用作爲並行思考的實現手段,這裏我們對這三者做個簡單的說明:

  進程:每個邏輯控制流都是一個進程,由內核來調度和維護.因爲進程有獨立的虛擬地址空間,想要和其他控制流通信必須依靠顯示的進程間通信,即我們所說的IPC機制

  I/O多路複用:應用程序在一個進程的上下文中顯式地調度他們自己的邏輯流.邏輯流被模型化爲狀態機,數據到達文件描述符之後,主程序顯式地從一個狀態轉換爲另一個狀態.因爲程序都是以一個單獨的進程,所以所有的流都共享同一個地址空間.基本的思路就是使用select函數要求內核掛起進程,只有一個或多個I/O事件發生後,纔將控制權返回給應用程序

  線程:線程應該是我們最爲熟知的.它本質是運行在一個單一進程上下文中的邏輯流,由內核進行調度.

  現代程序設計語言大都提供對這三種開發方式的支持,比如 C,Node,Python 中常用多進程/線程技術,java中的多線程及NIO技術等等.除此之外,協程也是一種不錯的技術方案,比如 Lua,Python 中也提供了對協程的支持.關於這幾種實現併發編程的技術方案,我將在隨後的文章中去解析.

  最後補充一點,無論機器速度快慢,我們都可以將多個機器串聯在一起,從而得到一個運行速度更快的集羣,這就是現代服務器技術核心之一:大凡高性能的服務器應用背後都有集羣的身影,而這些集羣大都依託於高性能,廉價的 Unix/Linux 平臺.

  原則十一:各部分之和大於整體

  水泥、沙子、石子和水個各自的硬度不高,但是混合起來去能得到高硬度的混凝土.這個現實展示了一個很普通的道理就是對不同特性的物質進行組合往往能產出令人意外的結果,這種不遵循數學上”1+1=2”的規律卻和化合反應非常類似.

  放在軟件工程中同樣如此:通過組合小程序來構建集成性的應用程序.這就和我在上文中提到像搭積木一樣編程.深究下來,無論是搭積木還是編程,其中共性就是組合的思想.從原子到分子,從樹木到高樓大廈,從函數到程序,看似不相關的東西經組合產生出意想不到的結果,在某種意義上,組合的思想是我們人類大腦最重要的能力之一.

  原則十二:尋找90%的解決方案

  “金無足赤,人無完人”這朗朗上口的話放在軟件領域卻代表一個不爭的事實:沒有一個軟件能百分百的滿足用戶.說的更直白點,你的軟件在用戶看來總缺少點什麼,無論你做出什麼努力,這也從另一個角度說明”只有已發佈的軟件而沒有完成的軟件”.

  中國郵政 vs 順豐

  既然沒有完美的軟件,那對於軟件開發者而言,有一個非常艱難的決定:”我們該向用戶提供什麼”.這是個非常有意思的問題,其答案取決你所開發軟件的性質以及面向的用戶羣體.

  說到這,就不得不談起中國郵政和順豐速遞.在中國的每個地方,你都可以用中國郵政來收發快遞,而順豐卻只見於經濟發展不錯的地區.很多人像我一樣曾抱怨過郵政的效率太低,接下來感嘆一句要是有順豐該多好.現在我們客觀的來談談同爲快遞這兩者本質差異:郵政作爲一家國企,在政府的要求下,郵政必須服務所有的人,必須提供100%的解決方案,而順豐作爲一家獨立的商業公司,卻可以選擇性服務,通過專注於高利潤且容易做到的90%.最終的結果就是我們普遍覺得順豐具有更高的效率.

  這其中的關鍵在於我們需要故意忽略哪些代價昂貴,費時費力或難以解決的問題.從商業的角度來說,這是一種”低投入,高回報”的解決方案.現在我們可以來談談軟件開發了.無論你是個人開發者還是商業軟件公司負責人,都應該考慮這個問題”向用戶提供什麼才最有價值”,然後去解決這其中的90%.這可能令很多人不適,但現在互聯公司最不應該做的就是企圖提供向郵政一樣的100%的服務.提供90%的方案除了能獲得更高的效益之外,還可以幫助聚集你的用戶羣體,這也是15年創業期間最大的感觸之一.

  原則十三:層次化思考

  層次化思想是什麼?說起來很抽象,不如直接的問自己一個問題”金字塔是如何建成的?”如果你的回答是一層一層建成的,那麼你可以直接略過本章節了.

  層次化思考並並非新名詞,對大部分程序員而言,”分層”是所有解決方案的指導思想,這裏的分層便是層次化思考的結果.與層次化思考相關的一種分析方法是 AHP(Analytic hierarchy process),即層次分析法.(關於AHP更多的信息就不多講了),它是思考和構造複雜系統的一個基本方法,按照該方法設計出的系統具有明顯的層次體系.

  現實世界充斥着層次化結構,小到細胞結構大到宇宙,從小團隊到跨國公司,其都呈現出層次化結構,對計算機軟件而言亦如此.在層次體系中,下層構件爲上層構件提供服務支撐,上層和下層之間的關係就像是方法的”調用-返回”.採用層次化設計的應用就像金字塔,先有底層構件,然後在之上構建高層構件,相對低層構件而言,高層構件更容易理解.

  可以說,一個系統無論最初採用什麼樣的組織方式,最終都會走向分層體系.

  我經常說的一句話是:無分層不架構,通俗點就是沒有分層的應用是沒有架構可言的.分層結構在計算機世界中無處不在,來看幾個最典型的例子:

  ISO/OSI七層網絡模型

  WEB應用分層結構

  Unix/Linux系統分層結構

  Android 系統分層結構

  MVC & MVP

  除了上述幾個典型示例外,兩種典型的開發方式 MVC 和 MVP 也都是典型的分層結構:

  無論是 MVC 還是 MVP,亦或是 MVVM,還是將來出現的什麼 M*P,只要記住所有的開發方式本質都是層次思考的結果,最終呈現分層體系,這就是所謂的萬變不離其中.如果將分層體系和小程序結合起來,我們可以得到一個更爲通用的程序結構設計圖:

  總結

  也許你會像我當初一樣納悶這麼優秀的操作系統就靠這些看起來無比簡單理念引導?事實確是如此,這有點像我們所說的”大道至簡”,複雜的東西簡單做,也是我們解決問題的最重要的一步.

  關於Unix/Linux中的編程哲學,我想以上十三條已經足夠.其中最有啓發的應屬”小既是美”,這也是我決定以後不寫長文的原因.

  更多

  每天學習累了,看些搞笑的段子放鬆一下吧。關注最具娛樂精神的公衆號,每天都有好心情。

  如果你有好的技術文章想和大家分享,歡迎向我的公衆號投稿,投稿具體細節請在公衆號主頁點擊“投稿”菜單查看。

  大連正規×××醫院 http://yyk.39.net/hospital/f9a8f_comments.html

  大連渤海醫院電話是多少 http://yyk.39.net/hospital/f9a8f_registers.html

  大連×××醫院 http://yiyuan.120ask.com/dlnk/


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