讀《Unix編程藝術(shù)》小結(jié)

前言

Unix是開源運動歷史上最著名的代表之一汗贫,而如今前端是開源運動中最活躍的一支隊伍,我相信它們兩者之間一定有共通之處。讀懂此書,可以讓我們以后看待軟件開發(fā)時角度變得不那么狹隘阳掐。

內(nèi)容

前面三章精要的概括了Unix的哲學思想、歷史發(fā)展冷蚂、以及和其他操作系統(tǒng)的對比缭保。

第一章:哲學

第一章開門見山, 鞭辟入里地詮釋了Unix的靈魂所在:一門技術(shù)的編程藝術(shù)和設(shè)計哲學帝雇。

為什么它的生命力如此長久涮俄?作者列舉了兩個原因:一是伴生的C語言的龐大影響力,二是帶目錄節(jié)點的樹形文件名字空間和用于通信的管道機制尸闸。

支持者認為Unix有什么優(yōu)點呢?主要如下:

  1. 開源軟件孕锄,同僚復審
  2. 跨平臺可移植性和開放標準
  3. 與Internet的融合
  4. 開源社區(qū)
  5. 簡潔靈活
  6. 讓編程變得有趣
  7. 設(shè)計思想經(jīng)典吮廉,廣泛被借鑒

這些優(yōu)點同樣值得前端項目借鑒,大家想想jquery畸肆、vue宦芦、react、angular等是不是或多或少地符合以上幾點轴脐?

當然Unix也不全是優(yōu)點调卑,它在商業(yè)上的不成功和追隨者的過于狂熱成了反對者的詬病之處。

另外在設(shè)計理念上大咱,由機制而不是策略主導設(shè)計恬涧,認為最終用戶比設(shè)計人員更清楚自己想要什么也導致了一些問題。不過碴巾,時間證明溯捆,這才是保持生命力長久的秘訣。

至于具體優(yōu)點有哪些厦瓢,簡直是羅列不過來提揍,四個大前提,五個原則煮仇,十七點小的概況劳跃。不過總的來說就是開發(fā)人員需要分清輕重緩急、懷疑一切浙垫,并以幽默樂觀的態(tài)度面對一切刨仑。一言蔽之:Keep It Simple强重,Stupid。

本章的最后描述了這些設(shè)計哲學是如何應用在Unix中的贸人,我們前端同樣也可以應用间景,比如著名的前后端分離思想,協(xié)議文本化(http/json)等艺智。

  • 依賴轉(zhuǎn)置
  • 數(shù)據(jù)流文本化
  • 數(shù)據(jù)庫和應用協(xié)議文本化
  • 前后端分離
  • 盡可能先寫原型
  • 恰當混用編程語言
  • 寬收嚴發(fā)
  • 不需要丟的信息絕對不丟
  • 小就是美
  • 追求軟件設(shè)計的卓越化

第二章:歷史

Unix的發(fā)展倘要,作者使用了三重境界來描述,和王國維的“昨夜西風凋碧樹十拣。獨上高樓封拧,望盡天涯路。衣帶漸寬終不悔夭问,為伊消得人憔悴泽西。眾里尋他千百度,驀然回首缰趋,那人卻在捧杉,燈火闌珊處∶匮”三重境界頗為相似味抖,值得深思。

簡單評價一下Unix的歷史 :起于兼容分時系統(tǒng)灰粮,以簡單好用走遍江湖仔涩,廣納各高校貢獻,雖失勢于商業(yè)粘舟,終借Linux重獲新生熔脂,涅槃騰飛。

那推動Unix發(fā)展的英雄們都是誰呢柑肴?自然是hacker們霞揉,他們是計算機世界的江湖和俠客,雖然在社會和高校中各成一派嘉抒,不過在經(jīng)歷過互聯(lián)網(wǎng)大融合(Unix和TCP/IP零聚、ARPANET融合)和自由軟件運動后Unix文化已經(jīng)上升到一種意識形態(tài)的層面,協(xié)同開發(fā)也成為一種趨勢些侍,分權(quán)隶症、公開、同僚復審的特點在其中體現(xiàn)的淋漓盡致岗宣,最終導致了開源運動的興起蚂会。

老派Unix陣營在商業(yè)上是吃過虧的,而開源運動以一種更親和市場耗式、更少對抗性的方式把軟件介紹給外部世界胁住,從而也彌補了商業(yè)上的不足趁猴。

可以這樣說,軟件離開源越近越繁榮彪见,保持靈活性儡司,別和低價而靈活的方案較勁,就可以得到長久而旺盛的發(fā)展余指。

第三章:對比

這一章作者對比了Unix和其他操作系統(tǒng)的設(shè)計和編程習俗捕犬,雖然其中舉的很多例子已經(jīng)隨風而逝了,但是其核心理念的對比還是非常具有參考價值的酵镜。

首先碉碉,作者對操作系統(tǒng)的風格元素進行了對比, 因為它反映了操作系統(tǒng)設(shè)計者的意圖淮韭,體現(xiàn)了成本和編程環(huán)境的限制對設(shè)計的均衡影響垢粮,更重要的是這種文化會隨機漂移,影響其他軟件靠粪。

具體又從下面幾個角度進行詳細說明:

  1. 統(tǒng)一性理念

Unix一切皆文件以及管道概念蜡吧。

  1. 多任務能力

即多進程并發(fā)能力,Unix有搶占式多任務能力庇配。
其他操作系統(tǒng)有協(xié)作式多任務能力斩跌。

  1. 協(xié)作進程

Unix具有低價的進程生成成本、簡便的IPC捞慌、以及能組合各種管道過濾器小工具,這就避免了多線程的坑柬批,使系統(tǒng)的各個部分容易合作啸澡。

  1. 內(nèi)部邊界

以程序員最清楚一切作為準繩,從而采取多用戶控制權(quán)限,在系統(tǒng)內(nèi)部設(shè)置三層內(nèi)部邊界:內(nèi)存管理、多用戶權(quán)限組氮帐、涉及安全的可信代碼塊嗅虏。

  1. 文件屬性和記錄結(jié)構(gòu)

Unix沒有,因為覺得記錄結(jié)構(gòu)是一種雞肋的存在上沐。文件屬性可以幫助理解文件皮服,但在面向字節(jié)流工具和管道的世界中會有語義問題。

  1. 二進制文件格式

Unix采用文本格式,而二進制的兼容性和靈活性不好参咙。

7.首選界面風格

Unix采用CLI風格,而其他操作系統(tǒng)有GUI風格,雖然GUI或者CLI沒做好都有問題,但CLI更易于程序員得到自己想要的東西龄广。

  1. 目標受眾

Unix為技術(shù)用戶而設(shè)計,其他操作系統(tǒng)有為服務端、客戶端蕴侧、最終用戶择同、單機、聯(lián)網(wǎng)等受眾設(shè)計的净宵。

  1. 開發(fā)的門檻

開發(fā)門檻是由開發(fā)工具的金錢成本敲才、成為熟練開發(fā)者的時間成本裹纳、甚至文化門檻組成,Unix支持輕松編程、玩家文化和精英編程文化紧武。

  1. 具體操作系統(tǒng)比較
  • VMS大全腫剃氧,商業(yè)領(lǐng)域尚可容忍
  • MacOS的統(tǒng)一性理念是Mac界面方針,邊界脆弱阻星,MacOS X融合Unix特點
  • OS/2單用戶系統(tǒng)朋鞍,不靈活
  • Windows辣雞但勝在商業(yè)
  • BeOS深入線程化疮绷、專攻大量數(shù)據(jù)處理涌萤,死在商業(yè)
  • MVS死板,用于大型機
  • VM/CMS是Unix祖先捍歪,在大型機領(lǐng)域如魚得水
  • Linux繼承Unix思想矾踱,更進一步連接世界和人

最后作者總結(jié)恨狈,種瓜得瓜,種豆得豆呛讲,一個好的操作系統(tǒng)必須可移植禾怠、支持網(wǎng)絡(luò)、把握客戶端的力量贝搁。從這里我突發(fā)奇想吗氏,會不會操作系統(tǒng)的未來就是瀏覽器呢?

設(shè)計思想

從第四章到第十三章都是展開描述Unix各個設(shè)計思想的精髓雷逆,配有大量的例子弦讽,雖然這些例子大部分已經(jīng)湮沒在歷史的長河里,不過對當今的軟件開發(fā)仍然具有重要借鑒意義膀哲。

第四章:模塊性(保持清晰往产,保持簡潔)

隨著代碼的復雜度日益增加,我們需要使用子程序某宪、庫仿村、進程等來劃分代碼。比如可以用定義清晰的接口把若干簡單模塊組合起來兴喂,這樣把程序劃分開來蔼囊,并且讓它們易于協(xié)作,這是良好的設(shè)計方式衣迷。好的軟件滿足模塊化畏鼓、正交性、緊湊性三個特點蘑险。

而模塊化最突出的特點就是封裝滴肿。模塊間通過一組嚴密、定義良好的程序調(diào)用和數(shù)據(jù)結(jié)構(gòu)來進行通信佃迄。

有幾點需要注意:

  1. API是實現(xiàn)和設(shè)計間的滯塞點
  2. 簡潔清晰的API表明設(shè)計是良好的
  3. 模塊不宜過多也不宜多少

模塊化另一處特點是緊湊性和正交性泼差,一個軟件贵少,設(shè)計和人類使用習慣相符就是緊湊的,任何操作沒有副作用就是正交的堆缘。

但緊湊意味著精煉滔灶,實際上的軟件基本上是半緊湊型的,因為如果編程者需要記憶的條目數(shù)大于七說明API不是緊湊型的吼肥。比如C和Python是半緊湊的录平、C++是反緊湊的,造成這種現(xiàn)象的原因是有時候為了性能和適應范圍等要犧牲緊湊性缀皱。

正交性代碼在源頭上減少了bug的可能性斗这,更容易文檔化和復用,重構(gòu)根本的目標就是提高正交性啤斗。

實踐當中如何體現(xiàn)緊湊型和正交性呢表箭?作者告訴我們需要遵循SPOT原則、圍繞強單一中心钮莲、時刻考慮分離的價值免钻。

SPOT原則即真理的單點性,比如通過重構(gòu)去除重復代碼保留真理:

  1. 去除重復數(shù)據(jù)->讓代碼生成程序
  2. 去除重復代碼知識點->讓代碼生成部分文檔
  3. 去除重復頭文件和接口聲明->讓代碼生成頭文件和接口聲明
  4. 讓數(shù)據(jù)結(jié)構(gòu)“無垃圾崔拥,無混淆”

強單一中心即圍繞“解決一個定義明確的問題”設(shè)計程序极舔,例如diff算法、grep模式匹配链瓦、yacc生成語法解析器等都是專門為了解決某個問題才出現(xiàn)的拆魏。

分離的價值指從零開始,先去想盡量少的能做的事情慈俯,有點類似前端的漸進增強思想稽揭。

在進行模塊化之前,我們還需要考慮一個問題:那就是軟件的層次肥卡。

大體可以分為自頂向下和自底向上的層次,自頂向下適用于精確事镣、穩(wěn)定步鉴、底層自由的軟件,自底向上適用于探索性的編程璃哟,同時拋棄的代碼也比另外一種少氛琢。我們需要根據(jù)情況去設(shè)計,要么抽象化細節(jié)随闪,要么圍繞某個模型組織代碼阳似,而實際情況往往是結(jié)合兩種方式設(shè)計程序,這其中需要膠合層用來協(xié)調(diào)铐伴。

但膠合層要盡量薄撮奏,可以看做是分離原則的升華俏讹,C語言就是一個很好的膠合層。

膠合層的應用之一就是各個共享庫畜吊。雖然理論上膠合層不應存在泽疆,只有多變的策略和不變的機制。

另外作者討論了OO的思想玲献,他指出OO只在某些領(lǐng)域適用殉疼,Unix程序員們大多是持懷疑態(tài)度的,因為堆砌抽象層是很累人的事情捌年,容易陷入過度分層瓢娜,而且過早設(shè)計喪失了優(yōu)化的機會,以至于說:“過早優(yōu)化就是萬惡之源礼预∶呃”

這章的最后,作者設(shè)計了幾個問題供讀者自測逆瑞,看自己的代碼是否遵循了模塊化的原則:

  1. 全局變量有多少荠藤?
  2. 單個模塊的大小是否合適?
  3. 模塊內(nèi)的單個函數(shù)是否太大获高?
  4. 代碼是否有內(nèi)部API哈肖?
  5. API的入口是否超過七個?
  6. 模塊的入口點分布怎么樣念秧?

第五章:文本化(好協(xié)議產(chǎn)生好實踐)

上一章講了如何把程序拆分成若干個模塊淤井,這章就關(guān)于這些模塊間如何通信給出了答案。比如用于協(xié)作通信的應用協(xié)議如何設(shè)計摊趾,當然還有一種文本化的應用場景:數(shù)據(jù)存儲币狠,也會提到。

  1. 為了便于數(shù)據(jù)傳輸砾层,通常需要序列化(列集)和反序列化(散集)漩绵,比如前端中JSON的parse和stringify方法。
  2. 設(shè)計協(xié)議時需要考慮互用性肛炮、透明性止吐、可拓展性和經(jīng)濟性。
  3. 性能不需要最先考慮侨糟,不然可能會是一種過早優(yōu)化碍扔。
  4. 數(shù)據(jù)文件和控制文件的信息流方向是不一樣的。

文本化最重要的特點是透明秕重、可拓展不同。

比如Unix口令格式就是犧牲性能換透明和可拓展性的例子,.newsrc格式同樣是舍經(jīng)濟性而取透明性和可操作性。但也有適用于二進制的情景二拐,比如PNG格式服鹅。

隨后作者又道出了數(shù)據(jù)存儲文本化非常重要的一個特點:擁有一套句法和詞法約定的數(shù)據(jù)文件元格式。具體給了幾個例子卓鹿,JSON是我加上去的菱魔。

格式名 特點
DSV(分隔符分隔值) 使用冒號分隔值,通過反斜杠轉(zhuǎn)義符處理特殊情況吟孙,和CSV形成鮮明對比
RFC 822 使用Tab或者Space來延續(xù)澜倦,空行解釋為結(jié)束。應用于郵件和HTTP協(xié)議杰妓,有多個記錄的時候邊界可能不明顯
Cookie-Jar fortune使用的格式藻治,使用%分隔,適用于結(jié)構(gòu)不易區(qū)別的文本段
Record-Jar 前兩個格式的混合體巷挥,使用%%\n分隔桩卵,適用于可變字段的集合
XML 類似于HTML、需要專門的解析器倍宾,適用于復雜的問題(比如遞歸嵌套)
Windows INI 使用名稱-屬性對分隔雏节,比較雞肋,復雜數(shù)據(jù)不及XML高职,簡單不如DSV
JSON 使用鍵值對分隔钩乍,如今比XML流行

那Unix對文本化格式的約定是什么樣的呢?

  1. 如果可能怔锌,以新行符結(jié)束的每一行只存一個記錄寥粹。
  2. 如果可能,每行不超過80個字符埃元。
  3. 使用#引入注釋涝涤。
  4. 支持反斜杠轉(zhuǎn)義約定。
  5. 在每行一條記錄的格式中岛杀,使用冒號或者任何連續(xù)的空白作為分隔符阔拳。
  6. 不要糾結(jié)tab和space。
  7. 優(yōu)先使用十六進制而不是八進制类嗤。
  8. 對于復雜的記錄衫生,使用“節(jié)”,如果有多行土浸,使用%%\n等作為分隔符。
  9. 節(jié)格式中彭羹,支持連續(xù)行黄伊。每行一個記錄字段或者用冒號終止字段名關(guān)鍵字作為引導字段。
  10. 格式可以自描述派殷,不然就設(shè)立一個版本號还最。
  11. 注意浮點數(shù)取整問題墓阀。
  12. 不要壓縮一部分。

前面花了這么多力氣描述數(shù)據(jù)存儲文本化拓轻,當然是給描述協(xié)議文本化做鋪墊斯撮。因為適用于數(shù)據(jù)文件格式的好處同樣也適用于協(xié)議。

協(xié)議設(shè)計另外需要注意的點就是要牢記端對端設(shè)計原則扶叉,包括安全勿锅、認證、性能枣氧。
同樣舉了例子溢十,關(guān)于郵件協(xié)議的:

  • SMTP發(fā)郵件,設(shè)計良好达吞。
  • POP3收郵件张弛,和SMTP如出一轍。
  • IMAP收郵件酪劫,希望取代POP3吞鸭,但是加重了服務端的載荷減輕了客戶端的壓力。

最后話題一收覆糟,開始闡述應用協(xié)議元格式:文本格式刻剥、使用單行請求和響應,有效載荷數(shù)據(jù)多行搪桂,可以隨時拓展透敌。

需要解決的問題是簡化網(wǎng)絡(luò)間事務處理的序列化操作,因為網(wǎng)絡(luò)的帶寬昂貴的多踢械。比如HTTP酗电,非常簡單和通用,需要在安全和便利間做出抉擇内列,基于HTTP協(xié)議的其他協(xié)議很方便撵术,但是缺點也很明顯:完全客戶端驅(qū)動,要額外接收HTTP報警信息话瞧。

還有其他的例子嫩与,比如BEEP使用二進制包序列,且支持服務端推送信息交排,XML-RPC划滋、SOAP、Jabber埃篓,XML...雖然它們已經(jīng)隨著歷史逐漸沒落了处坪,但它們的優(yōu)點應該會被未來的HTTP2吸收,到時候給我們一個更強大的HTTP。

第六章:透明性(來點光)

優(yōu)雅軟件的第三點特點是什么呢同窘?可顯和透明性玄帕。

透明性指可以預測到程序行為的全部或者大部分情況,可顯性指幫助人們對軟件建立正確的“做什么想邦、怎樣做”的觀念裤纹。

可以從用戶(UI)和程序員(代碼)的角度來看待可顯性和透明性。

舉幾個例子:

實例名 特點
audacity 音頻軟件丧没,UI透明
fetchmail 郵件軟件鹰椒,-v選項使得程序可顯,獲得“防彈程序”榮譽
GCC 編譯器骂铁,一系列處理階段都是為了可顯而設(shè)計的吹零,例如dif
kmail 郵件程序,UI可顯透明拉庵,可以訪問具體細節(jié)但是又不顯眼
SNG 圖形文本轉(zhuǎn)換軟件灿椅,可顯但不是很透明
Terminfo 數(shù)據(jù)庫,可顯透明钞支,使用文件系統(tǒng)作為數(shù)據(jù)庫
Freeciv 游戲茫蛹,數(shù)據(jù)文件以文本格式編寫

那怎樣設(shè)計軟件才能實現(xiàn)透明性和可顯性呢?這就需要我們專注代碼同其他人交流的方式了烁挟。

  1. 不要疊放太多抽象層婴洼,增加透明性。讓其他人能夠預測程序行為撼嗓。
  2. 編碼要求:調(diào)用深度要淺柬采、代碼要有明顯的不變性、API正交且警、全局設(shè)置唯一的記錄器粉捻、實體一對一映射、容易找到給定部分斑芜、避免增加特殊情況肩刃、避免意義含糊的常量。
  3. 避免過度保護杏头,對于錯誤調(diào)試應該是透明的盈包。
  4. 使用可編輯的表現(xiàn)形式:編寫文本化器或者瀏覽器。
  5. 便于故障診斷和故障恢復醇王,實現(xiàn)健壯性呢燥。

除此之外,還要為可維護性而設(shè)計寓娩,維護性就是其他開發(fā)者能夠順利地理解和修改軟件:

  1. 寧愿重構(gòu)疮茄,都要拋棄辣雞代碼滥朱。
  2. 努力讓代碼成為活代碼而不是睡代碼和死代碼,吸引別人來開發(fā)力试。
  3. 包含開發(fā)者手冊比用戶手冊更有效。

第七章:多道程序設(shè)計(分離進程為獨立的功能)

前面三章告訴我們軟件需要有模塊性排嫌、文本化畸裳、透明性、可顯性淳地、可維護性怖糊。這一章講述的部分更加接近實現(xiàn):如何將大型程序分解成多個協(xié)作進程,又稱多道程序設(shè)計颇象。

首先伍伤,我們需要遵循做單件事并做好的原則,提倡分解程序遣钳。

有三種方法:降低進程生成的開銷扰魂、簡化進程間通信、使用簡單透明的文本數(shù)據(jù)格式蕴茴。

但協(xié)議真正的設(shè)計挑戰(zhàn)是協(xié)議邏輯劝评,必須看得出很有表現(xiàn)力并可防范死鎖。

另外倦淀,不要過早關(guān)注性能蒋畜,我們需要從性能調(diào)整中分離復雜度控制,它們是兩碼事撞叽。于是作者強烈建議我們盡量不要使用線程姻成,還有模塊化可以達到更好的安全性。

接著作者介紹了Unix中的幾種IPC(進程間通信)方法愿棋,從最簡的逐步介紹到難的科展。

  1. 把任務轉(zhuǎn)給專門程序

最簡單的程序協(xié)作方法。專門程序運行時不需要和父進程進行交流初斑。
例如mutt郵件用戶代理辛润,將所有的編輯動作統(tǒng)一到單獨的emacs進程中。

  1. 管道见秤、重定向和過濾

各種IPC方法的誕生的源泉砂竖,管道約定每個程序一開始至少有兩個I/O數(shù)據(jù)流可用。
管道操作把一個程序的標準輸入連接到另一個程序的標準輸入鹃答,一系列管道被稱為管線乎澄,管道和重定向的組合威力很大,不需要單獨再寫一個完成某個功能的程序(類似鏈式調(diào)用)测摔,但它的缺點是單向性置济,不能讓數(shù)據(jù)雙向流動解恰。
實例是分頁程序的管道/制作單詞表、pic2graph浙于、bc(1)和dc(1)护盈、以及fetchmail為什么不用管線。

  1. 包裝器

它隱藏了shell管線的細節(jié)羞酗,被調(diào)用程序?qū)S没?br> 實例是備份腳本腐宋,只需要傳參調(diào)用就好。

  1. 安全性包裝器和Bernstein鏈

它是高級版包裝器檀轨,需要先認證再選擇性地調(diào)用胸竞。
實例是Bernstein鏈,每個繼發(fā)程序都取代了前一階段的程序参萄,并且可以在程序鏈中插入另一個程序來修改系統(tǒng)的行為

  1. 從進程

父子進程通信卫枝,只在兩種情況下使用:兩者使用的協(xié)議不重要或者那個協(xié)議是根據(jù)第五章原則設(shè)計的。(前端的mv*的父子組件通信也是這樣的)
實例是scp和ssh讹挎,scp從ssh中獲取信息制作進度條校赤。

  1. 對等進程間通信

對等通道,雙向數(shù)據(jù)流淤袜。(讓我想起了angular1.x的雙向數(shù)據(jù)綁定和其他前端框架的狀態(tài)管理)

種類 特點
臨時文件 簡單痒谴,易沖突,有安全性風險
信號 一種軟中斷形式铡羡,信號間可能會競爭
系統(tǒng)守護程序和常規(guī)信號 殺進程信號和常規(guī)信號
套接字 從封裝網(wǎng)絡(luò)數(shù)據(jù)訪問的行為引申出來积蔚,需要指定協(xié)議族(前后端分開)
共享內(nèi)存 最快,但是必須提供硬件烦周,自己處理競爭和死鎖

在使用這些IPC方法的時候尽爆,我們也需要注意一些問題:

  1. 不要讓IPC和API耦合在一起
  2. 盡量別使用二進制信息交換協(xié)議
  3. 避免混亂的流
  4. 避免遠程過程調(diào)用,它雖然會提升性能但延遲高
  5. 別用線程(線程恐嚇)读慎,因為作者認為它標準薄弱規(guī)范模糊

最后漱贱,我們在設(shè)計層次上的進程劃分無非就是完成程序在生命期內(nèi)交換數(shù)據(jù)的任務。
設(shè)計的過程中夭委,我們需要想清楚:

  1. 程序前后端分離幅狮,何時建立通信?
  2. 何時何地完成信息的列集和散集株灸?
  3. 何時產(chǎn)生緩沖問題崇摄?
  4. 怎樣保證獲取信息的原子性?

第八章:微型語言(尋找歌唱的樂符)

語言本身越精簡慌烧,出bug的可能性越低逐抑,當需要一個特定規(guī)則來完成任務時,微型語言就誕生了屹蚊。

它相對通用語言厕氨,體積小復雜度低进每。那什么情況下需要微型語言呢?當預先認識到設(shè)計一門微型語言命斧,注意到規(guī)格說明文件像微型語言田晚,或者老是打補丁的時候。

然后讓我們理解一下語言分類法国葬,由簡單到復雜肉瓦,是文件->微型語言->通用語言的。圖8.1很好地對當時主要語言進行了分類胃惜,它們的范疇從聲明型到命令型都有。

微型語言舉例

案例 特點
sng 圖文轉(zhuǎn)換哪雕,便于用通用工具編輯圖片
regexp 描述文本模型船殉,簡單地表達了識別行為
glade 界面創(chuàng)建,專門生成XML代碼
m4 宏處理斯嚎,便于把文本拓展成其他字符串利虫,但要慎用
XSLT 描述文本流變換,具有有限的類型分類和對外接口
DWB 公式排版堡僻,聲明性語義
fetchmail的運行控制語法 既有聲明性特點也有命令式特點糠惫,有語法糖
awk shell語言,既不緊湊也不通用所以被廢棄
PostScript 專門用于設(shè)備排版钉疫,堆棧式語言
bc和dc 命令性語言硼讽,任意精度。dc是逆波蘭標記牲阁,bc是代數(shù)標記
Emacs Lisp 前端語言固阁,可以描述編輯動作
JS 客戶端語言宣肚,逐漸變得通用

設(shè)計微型語言

當需要把問題說明規(guī)格提升一個層次時锐秦,且應用領(lǐng)域的域原語簡單而固定不變時,我們就需要設(shè)計一門微型語言了顶考。

  1. 選擇正確的復雜度

盡量簡單凌唬,自頂向下設(shè)計并齐,符合美學。
了解嵌入型微型語言容易被濫用客税,宏的安全性差况褪。
把語言一樣的特性加進去作為事后補救措施是飲鴆止渴,一個偶爾圖靈完備的語言是其他開發(fā)者的噩夢霎挟。

  1. 擴展和嵌入語言

通過別的語言擴展或者嵌入進別的語言窝剖。這對實現(xiàn)命令式語言來說很好,但這個選擇決定于設(shè)計本身酥夭。
嵌入的話還需要考慮錯誤語法檢查赐纱。

  1. 編寫自定義語法

參考XML作為語法基礎(chǔ)脊奋。
功能簡單的微型語言就不要殺雞用牛刀了,遵循最小立異原則疙描。
確實需要自定義語法的話使用yacc和lex幫助诚隙。

  1. 慎用宏

宏帶來的問題大于好處,因為預處理器遇到表達式而不是期望的值的時候會發(fā)生意想不到的結(jié)果起胰。并且宏難以閱讀和調(diào)試久又,擾亂了錯誤診斷。
C預處理器有相應的解決辦法效五,但m4沒有地消。

  1. 考慮清楚設(shè)計的是微型語言還是協(xié)議

考慮語言引擎是否可被其他程序交互調(diào)用,關(guān)鍵在于事務邊界的標定程度畏妖。

第九章:生成(提升規(guī)格說明的層次)

這章的核心觀點就只有一個:把程序的邏輯轉(zhuǎn)移到數(shù)據(jù)中去脉执。也就是數(shù)據(jù)驅(qū)動編程,讓開發(fā)者只關(guān)心數(shù)據(jù)結(jié)構(gòu)而不是代碼戒劫。

數(shù)據(jù)驅(qū)動編程和OO的區(qū)別是數(shù)據(jù)實際上定義了程序的控制流半夷,OO是封裝和固定的。數(shù)據(jù)驅(qū)動和狀態(tài)機也是有區(qū)別的迅细,一個是自動生成代碼巫橄,一個是手工寫。

概括起來就是始終把問題層次往上推茵典。

案例 特點
ascii 不維護代碼湘换,只維護數(shù)據(jù)
垃圾郵件統(tǒng)計 統(tǒng)計數(shù)據(jù)比精巧的模式匹配奏效
fetchmailconf 通過配置文件生成代碼

所以我們需要代碼生成代碼。建設(shè)性的懶惰是大師級程序員的美德敬尺。

案例 特點
生成ascii 發(fā)布的源碼包含一個文件枚尼,里面是數(shù)據(jù),通過它們生成代碼
生成HTML 數(shù)據(jù)+模板

第十章:配置(邁出正確的第一步)

配置是開發(fā)前啟動環(huán)境的重要步驟之一砂吞,另一個是交互通道署恍。

什么可以配置呢?理論上一切可配置蜻直,但配置項太多會爆炸盯质。(對新手不友好)

不如搞清楚什么不可配置:比如可以自動檢測的東西。用戶也不應該看到優(yōu)化開關(guān)概而,0.7秒以下藏起來呼巷。用其他程序能完成的任務就不要配置。

一般來說可以在五個地方配置:運行控制文件->系統(tǒng)環(huán)境變量->用戶運行控制文件->用戶自定義環(huán)境變量->命令行選項赎瑰。

這五個地方后面會覆蓋前面的王悍,而且越到后面變化的幾率越大,好的Unix實踐要求使用同參數(shù)選項預期壽命最匹配的機制餐曼。

  1. 運行控制文件

以rc結(jié)尾(比如eslintrc)压储,存放與程序相關(guān)的聲明或命令鲜漩,在程序啟動時解析。
它分系統(tǒng)的和用戶的集惋。語法有一套通用風格孕似,比如支持注釋、不區(qū)別空白符等刮刑『砑溃可以減少用戶閱讀和編輯時要接觸的新鮮事物,實例是.netrc文件:對用戶透明且遵循最小立異原則雷绢,但很難移植映射到其他操作系統(tǒng)里去泛烙。

  1. 環(huán)境變量

用來配置程序訪問的環(huán)境。如搜索路徑翘紊、系統(tǒng)默認值胶惰、uid、pid等關(guān)鍵信息霞溪。
也分系統(tǒng)的和用戶的。使用環(huán)境變量的時機是:變量值會根據(jù)上下文而變化或隨點文件不同而改變中捆、不能以改變命令行調(diào)用來表述鸯匹,操作系統(tǒng)間的移植同樣非常困難。

  1. 命令行選項

可以由腳本控制程序(如node腳本)泄伪,一般以-開頭殴蓬,有Unix(推薦)、GNU蟋滴、X toolkit風格染厅。
從-a到-z都被賦予了特殊的含義,某些大寫字母也是津函。盡一切辦法遵循最小立異原則和復用它們肖粮。
有命令行的地方就好移植。

那應該如何挑選方法呢尔苦?根據(jù)從運行控制文件->環(huán)境變量->命令行選項,是最不易改變到最易改變的原則挑選涩馆。

因為后者會覆蓋前者,并且依賴于程序在調(diào)用間隙需要保持多久的配置狀態(tài)允坚。

實例是fetchmail魂那,設(shè)置rc文件和環(huán)境變量,最后用命令行腳本化稠项。

但描述的約定不是絕對的涯雅,當明白自己想要什么并且想好了出錯后怎么補救,可以讓收益大于代價展运,是可以放手一搏的活逆。

第十一章:接口(Unix環(huán)境下的用戶接口設(shè)計模式)

接口是程序和程序精刷,程序和人類通訊的媒介。在設(shè)計時要遵循與其他程序通訊的前瞻性和最小立異原則划乖。

比如I/O有三種方式:程序贬养、IPC、已知文件或設(shè)備琴庵。所有存在的接口風格误算,存在即合理。

那如何應用最小立異原則來減少用戶學習負擔呢迷殿?

讓用戶對接口產(chǎn)生熟悉感儿礼,能共生和委派就弄,不能就效仿庆寺。

從Unix接口設(shè)計的歷史:打字機->命令行->可視化蚊夫,我們可以知道Unix接口鼓勵機制而非策略。

接口設(shè)計評估有五種度量標準:簡潔懦尝、表現(xiàn)力知纷、易用、透明和腳本化能力陵霉。

  • 簡潔是指操作起來容易程度
  • 表現(xiàn)力指接口可以表現(xiàn)出沒有預見到的行為組合
  • 易用指學習成本低
  • 透明說明用戶容易理解問題域
  • 腳本化是指接口能被其他程序使用

在接口發(fā)展歷史上琅轧,CLI和GNU接口之間的爭論一直存在,它們分別面向?qū)<壹売脩艉统鯇W者用戶踊挠,但我們需要權(quán)衡看待乍桂。

CLI表現(xiàn)力強、簡潔效床、透明睹酌、腳本化但不易用,GNU表現(xiàn)力差剩檀、易用憋沿,其他不確定(看開發(fā)者)。

比如計算器程序是一個很好的GNU程序沪猴,因為它考慮到了用戶的未來行為卤妒,這是值得的。

不過Unix程序員的編程喜好還是透明字币、表現(xiàn)力和可配置则披,所以不用說,CLI是他們的最愛洗出。

Unix接口模式

模式 特點
過濾器 標準輸入輸出士复,寬進嚴出,不丟不增,例如sort
Cantrip 一次性阱洪,例如clear
只出便贵,例如ls
接收器 只進,例如打印程序
編譯器 轉(zhuǎn)換信息冗荸,比如gcc
ed 有交互能力承璃,例如gdb
Roguelike 比GNU效率高,但難以腳本化蚌本,例如Roguelike游戲
引擎和接口分離 機制策略分離盔粹,遵循MVC模式,有配置者/行動者程癌、假脫機/守護進程舷嗡、驅(qū)動/引擎、C/S類型
CLI服務器 統(tǒng)一掌控程序啟動服務器進程嵌莉,例如CLI服務器
基于語言的接口 使用微型語言來做專門的事进萄,例如shell

那我們非Unix程序員怎么應用Unix接口模式呢?

答案是促進腳本化和管道線能力锐峭,接口要盡量簡單中鼠。

首先交互要分三種情況:和初級用戶、專家用戶沿癞、其他程序使用兜蠕。

而且通常有幾種接口模式混合,首先封裝API邏輯抛寝,然后產(chǎn)生一個多價程序。

最重要的是cantrip曙旭、GUI盗舰、腳本接口模式,可選Roguelike模式桂躏。

然后作者闡述了網(wǎng)頁瀏覽器作為通用前端的好處钻趋,它統(tǒng)一了前端,讓前后端徹底分離剂习。

優(yōu)點有很多蛮位,比如CGI公用網(wǎng)關(guān)接口和ajax助力前后端通信。缺點是網(wǎng)頁強迫以批處理風格處理交互操作鳞绕、使用無狀態(tài)協(xié)議管理持久會話失仁。還有語言的兼容性成為一個問題(現(xiàn)在已經(jīng)不是問題,js統(tǒng)一了)们何。難以腳本化或?qū)⑹聞兆詣踊胶蠖耍喝龑蛹軜?gòu)萄焦,前端->CGI->命令腳本。

最后作者告誡我們接口沒什么可說的就閉嘴:遵循緘默原則。

因為無用信息會干擾合作拂封、用戶茬射、帶寬消耗,還有長時間的操作要提供進度條而不是廢話冒签。確認提示最好是“不”而不是“是”在抛。

調(diào)試模式和開發(fā)模式的消息可以區(qū)別對待。

第十二章:優(yōu)化

最有效的優(yōu)化是優(yōu)化之外的事情萧恕,例如清晰干凈的設(shè)計刚梭。

作者對于優(yōu)化這件事提出了自己的特有觀點:最好啥也別做,時間會給我們答案廊鸥。不寫代碼就沒有bug望浩,這點真是無力反駁。

摩爾定律告訴我們付出得不到回報惰说,軟件優(yōu)化的那一點點很快就被硬件升級所抵消磨德。要做也是做降維復雜度優(yōu)化而不是常數(shù)級的,比如從O(n^2)降到O(nlogn)

真要優(yōu)化的話吆视,先估量再優(yōu)化典挑,找到瓶頸再談優(yōu)化。

一般來說造成瓶頸有三個原因:

  1. 工具誤差啦吧,根本性的問題您觉。檢測工具的代碼執(zhí)行有誤差,可以統(tǒng)計它們的調(diào)用次數(shù)授滓。
  2. 外部延遲琳水,也是根本的,不能隨機檢測般堆,要多次檢測在孝。
  3. 過度調(diào)用,把子程序的時間開銷算到了調(diào)用程序中淮摔。

所以衡量性能時不要只收集孤立的性能數(shù)字私沮,更應該綜合多個參數(shù),如問題規(guī)模和橙、CPU速度仔燕、磁盤速度等,最后建模得出結(jié)論魔招。

還需要考慮非定域性(不確定性)之害晰搀,保持代碼短小簡單,核心數(shù)據(jù)結(jié)構(gòu)必須留在最快的緩存里可以盡量避免办斑。

某些優(yōu)化是不值得的厕隧,比如循環(huán)展開。

緩存越大,緩存的開銷越大吁讨,這點也需要注意髓迎。

本章后面一部分是針對協(xié)議優(yōu)化的內(nèi)容,關(guān)注點主要在吞吐量和延遲上建丧。

總的來說要設(shè)計出良好的網(wǎng)絡(luò)協(xié)議排龄,需要盡量避免協(xié)議的往返。

實際上盡可能使用低的時延設(shè)計和忽略帶寬成本翎朱。作者提供了三種策略減少時延:對事務批處理橄维、允許事務重疊、緩存拴曲。

1.批處理

先把更新累積起來争舞,最后一次性處理,比如DOM操作和DOMFragment。

2.重疊

將好幾條更新一起發(fā)送出去澈灼,阻塞和等待中間結(jié)果都是致命的,比如IMAP協(xié)議對請求做了標記竞川。

3.緩存

兼得魚和熊掌的策略,但必須考慮更新緩存的問題叁熔,更新模式越復雜委乌,bug越容易產(chǎn)生。
而且作者認為緩存對于SPOT原則來說是不好的荣回,因為它純粹為了性能優(yōu)化遭贸。他建議轉(zhuǎn)用加速文件系統(tǒng)或者虛擬內(nèi)存實現(xiàn)會比緩存好。所以我們在使用緩存時也應該問問自己為什么要用緩存心软。

第十三章:復雜度(盡可能簡單壕吹,但別簡單過了頭)

真實世界的編程就是管理復雜度的問題,我們應盡量降低復雜度删铃。

首先耳贬,我們需要理解復雜度是什么。作者分別從橫向縱向的角度進行了比較泳姐。

橫向的復雜度有三個來源:程序員、用戶暂吉、代碼胖秒。

  1. 程序員-接口復雜度,可能會陷進硬撐陷阱(極端晦澀的技法)慕的。
  2. 用戶-實現(xiàn)復雜度阎肝,可能會造成人力尺度陷阱(將許多底層任務拋給用戶)。
  3. 代碼-代碼量肮街,可能會陷入過專用陷阱(重復代碼)风题。

現(xiàn)實中可以對接口復雜度和實現(xiàn)復雜度折中,做出一方面是簡潔的接口,一方面是便于傳播的簡單軟件沛硅。

RG的文章認為MIT哲學(簡潔的接口)雖然讓軟件抽象地更好眼刃,但是New Jersey模型(簡單軟件)更具傳播特性,這兩種方法的平衡就在于可以拿此換彼摇肌,例如404的出現(xiàn)擂红。

縱向的復雜度有本質(zhì)的、選擇的和偶然的復雜度围小。

  1. 本質(zhì)的-有些問題天生就是復雜的昵骤,比如設(shè)計火箭程序。
  2. 選擇的-由工程目標決定肯适。
  3. 偶然的-沒有找到實現(xiàn)規(guī)定功能集合的最簡方法变秦。

我們必須要注意選擇和偶然復雜度的區(qū)別,偶然的可以由良好的設(shè)計去除框舔,選擇的只能改變工程目標了蹦玫。

映射復雜度

復雜度.png
  • 本質(zhì)接口復雜度通常無法去除,但可以調(diào)整代碼庫規(guī)模來減少代碼復雜度雨饺。
  • 選擇復雜度邊界模糊钳垮,工程所涉及的任何方面都可能產(chǎn)生實現(xiàn)復雜度。
  • 偶然復雜度可以通過良好的設(shè)計避免额港。
  • 代碼復雜度可以采用更好的工具解決饺窿,實現(xiàn)復雜度可以選擇更好的算法解決,接口復雜度著眼于更好的交互設(shè)計移斩。
  • 處理復雜度依賴于見識而非方法肚医。

有的時候由于本質(zhì)復雜度的存在,簡潔不能勝任向瓷,我們只能保證功能肠套,犧牲簡潔了。

為了讓我們對復雜度的理解更加深刻猖任,作者講了五個編輯器的故事你稚。(字處理器不在討論范圍內(nèi),因為過于專用)

種類 特點
純文本 編輯器只知道其字節(jié)或者行結(jié)構(gòu)
富文本 文本帶有屬性朱躺,如字體大小顏色等
句法感知 高亮刁赖,自動縮進
批命令輸出解析 可以編譯并捕捉錯誤
同輔助子進程交互 可以調(diào)試/版本控制/和其他程序通信
編輯器 特點
ed 純文本編輯
vi 四不像
Sam ed的進化版,新增了功能
Emacs 大而全
Wily 鼠標控制

由此作者總結(jié)了一下长搀,編輯器的適當規(guī)模應該是什么樣的宇弛。

首先甄別它們的復雜度:ed最簡單,Emacs最復雜源请,vi是折中派枪芒,Sam繼承了ed的簡潔彻况,Wily優(yōu)雅但有過于依賴鼠標的代價。接著批判了vi:折中無用舅踪。(雖然現(xiàn)在vi還是很火)

不過最后一句話說的還是好:少吃多干還是多吃多干取決于時代纽甘。(vscode應該是多吃多干,sublime應該是少吃多干)

結(jié)尾的時候引申到如何構(gòu)建軟件的適度規(guī)模:選擇需要管理的上下文環(huán)境硫朦,并且按照邊界所允許的最小化方式構(gòu)建程序贷腕。先證明其他方法行不通時再編寫大型程序。

具體實現(xiàn)

第十四章到第十六章介紹了Unix中涉及到的語言咬展、工具以及輪子泽裳,我們前端也需要考慮自身領(lǐng)域的相關(guān)問題,這對我們真正編碼的時候提升效率是非常有幫助的破婆。

第十四章:語言(C還是非C)

Unix下的語言是豐饒的涮总,并且鼓勵專門領(lǐng)域語言的設(shè)計。一方面祷舀,C語言是Unix的伴生語言瀑梗,另一方面,各種腳本語言在動態(tài)存儲管理的自動化上有巨大優(yōu)勢裳扯。

C和Unix的關(guān)系是巧妙的抛丽,沒有Unix就沒有C,沒有C就沒有如今Unix文化的繁榮饰豺,C和C++取代了匯編語言在工業(yè)界的地位亿鲜,重新掀起了一波技術(shù)浪潮。

雖然C和C++對要求極高的程序有意義冤吨,但損耗了程序員的精力蒿柳。

隨之而來急劇下降的成本又改變了編程的經(jīng)濟含義。軟件的復雜化說明自動化內(nèi)存管理越來越重要漩蟆,而且真正性能的損失往往來自外界垒探。(網(wǎng)絡(luò)延遲、事件等待等)

到當今這個年代怠李,混合策略才有可能使得效率最大化圾叼。即一種在主語言中嵌入其他語言的策略。

比如可以嵌入內(nèi)存管理器完成內(nèi)存管理捺癞,嵌入腳本膠合邏輯夷蚊。高級shell編程甚至可以自由混合語言編程。

接著作者對當時的主流語言進行了一番評估翘簇,因為熟悉語言才能更好地使用和組合它們撬码。

語言 特點
C 資源效率最接近機器語言儿倒,但資源管理非常困難
C++ 效率高版保,支持OO和泛型編程呜笑,但非常難用,鼓勵過于復雜的設(shè)計
Shell 完成小型任務自然快捷彻犁,但大型腳本必須依賴大量輔助命令造成兼容性問題
Perl 強大的工具語言以及正則匹配叫胁,但大型項目不優(yōu)雅、難以維護
Tcl 節(jié)儉緊湊的設(shè)計和作為解釋器語言的可拓展性汞幢,但數(shù)據(jù)結(jié)構(gòu)和命名空間等很怪異以至于難以用于大型項目
Python 為嵌入而生的膠水語言驼鹅,代碼清晰優(yōu)雅,但效率不高
Java 自動管理內(nèi)存并且支持OO森篷,但設(shè)計的有些復雜而且沒達到一次編寫處處運行的目的
Emacs Lisp 結(jié)合了Lisp输钩,優(yōu)雅、自動管理內(nèi)存仲智,但難以移植买乃、性能差

作者還對這幾種語言的未來趨勢做了預測:C/C++/Java不變、Tcl/Perl衰退钓辆、Python增長剪验,事實證明他基本上是對的。

前面分析了那么多前联,該到自己動手選擇編程工具包的時候了功戚,因為GUI工具包是會影響編程狀態(tài)的,而且某些語言和工具包的綁定有特定要求似嗤,比如Qt屹立不倒啸臀,但我用vsc。

第十五章:工具(開發(fā)的技術(shù))

語言選好了双谆,工欲善其事必先利其器壳咕,接著就是選工具了。

首先顽馋,我們需要一個對開發(fā)者友好的操作系統(tǒng)谓厘,像Unix就沒有固定的IDE,需要自己組合工具完成IDE的功能寸谜。這樣可以讓程序員更加專注于設(shè)計竟稳,以編輯/編譯/調(diào)試為中心,其他細節(jié)用工具完成熊痴。前端也需要自己組合他爸。

  1. 編輯器

作者主要對比了vi和Emacs,但我認為vi類似于sublime果善,可以靈活拓展诊笤,Emacs類似于vsc宜咒,大而全抢韭,不過兩者兼用,用于不同的場景才是最佳策略。

  1. 專用代碼生成器

作者以lex和yacc這兩款生成語言詞法分析器的工具為例钳宪,介紹了lex是從輸入流中獲取標記符號离唬,而yacc是解析一系列標記符號來檢查是否符合語法啦桌。
但lex意外地被用于各種模式識別准颓,輸入一堆,最后找出某個模式凉馆。
工具生成的代碼還是比手工正確高效薪寓。

  1. 自動化編譯

把源碼進行裝配打包發(fā)布才是最重要的,以make為例
它會尋找代碼間的依賴關(guān)系從而生成正確的打包版本(類似webpack)澜共,但要注意不能非常復雜向叉,比如遞歸make。
一些腳本語言生成任務所需的文件也是很方便的嗦董,有all植康、test、clean展懈、install等命令销睁,類似npm。
makefile的可移植性和分析依賴能力靠幾個工具完成:makedepend存崖、Imake冻记、autoconf、automake等来惧。

  1. 版本控制系統(tǒng)

為了追蹤變化冗栗,特別是bug,查看作者供搀、時間隅居、內(nèi)容等,我們需要版本控制系統(tǒng)葛虐,而計算機更加擅長這些細節(jié)胎源。
手工版本控制隱性成本非常高,自動化的版本控制能夠保存項目的歷史評注并避免修改沖突屿脐。
舉例為VCS涕蚤,SVN是CVS的衍生版本(基于文件),GIT是現(xiàn)代版本控制系統(tǒng)(基于變化)的诵。

  1. 運行期調(diào)試工具

能夠打斷點万栅,檢查程序狀態(tài),可控執(zhí)行某個單一語句層次的部分西疤,這是透明性設(shè)計的另一幫手烦粒。

  1. 性能分析工具

程序90%的執(zhí)行時間都耗費在10%的代碼上,性能分析軟件幫助定位問題代赁,這樣就可以優(yōu)化關(guān)鍵的10%的代碼并遵循之前的優(yōu)化原則扰她。

  1. 整合工具

編輯/編譯/測試/調(diào)試/版本控制...一體的工具,對前端來說vsc+chrome可以完成95%的工作邮偎,不是IDE勝似IDE。

第十六章:重用(論不要重新發(fā)明輪子)

無為代碼义黎,天下希及。這個無為是指最經(jīng)濟的行為豁跑,對無論是人員資本還是經(jīng)濟收益都有好處廉涕。

而讓代碼無為就是重用代碼,重用代碼又是避免發(fā)明輪子的最有效方法艇拍。Unix里里外外都支持重用狐蜕,組合優(yōu)先于獨立。

作者還特意講了一個豬小兵的故事卸夕,這是千千萬萬程序員的縮影:

我們在工作中重用的代碼可能會有問題层释,不得逼我們重造一個輪子。但重用代碼是技術(shù)問題快集、知識產(chǎn)權(quán)壁壘贡羔、行政問題以及個人自我意識的綜合,所以代碼專用化還是開放化讓程序員們糾結(jié)个初。

不過乖寒,決定重用了,就必須透明院溺。比如用源碼和注釋幫助使用者理解代碼楣嘁,牢記只有變化才是永恒的,源碼可以延續(xù)而二進制碼不行珍逸。

那重用和開源的關(guān)系又是什么樣呢逐虚?作者說開源和重用就像愛情和繁殖的關(guān)系一樣,開源也是為了重用自然而然發(fā)展而成保護透明性優(yōu)勢的策略谆膳。對開發(fā)者來說叭爱,保證了經(jīng)驗的價值,這也是職業(yè)發(fā)展的動力漱病。

開放源碼是從意識形態(tài)上解決這些所有問題的優(yōu)先方法涤伐。

另外一點是,開源質(zhì)量通常大于閉源缨称。因為同行復議保證了標準凝果,評估開源代碼的方法是閱讀其文檔和它的部分代碼,如果有一定年頭睦尽、反饋器净、協(xié)同作者數(shù)、社區(qū)当凡,這份代碼就是質(zhì)量高的山害。

去哪找呢纠俭?代碼庫和專用開源網(wǎng)站。作者推薦了SourceForge浪慌、Freshmeat等網(wǎng)站冤荆,現(xiàn)在應該是Github。

找到重用代碼就是節(jié)約自己的編碼時間权纤,閱讀代碼的元數(shù)據(jù)并且試一試對自己是有好處的钓简,并且閱讀代碼的細節(jié)也是為未來投資。

但使用開源軟件還需要注意幾個問題:考慮質(zhì)量汹想、文檔外邓、許可證。

文檔的話古掏,專用文檔不如How To&FAQ等搜索來理解的快损话。

許可證相關(guān)的我們需要知道版權(quán)和許可證是兩碼事,誰是版權(quán)所有者不重要槽唾,關(guān)鍵是許可證條款丧枪。它讓我們使用、修改代碼的權(quán)利有限制庞萍,標準許可證有MIT豪诲、BSD等,GPL帶有病毒性質(zhì)挂绰,LGPL和MPL則削弱了這一點屎篱。另外記得,找律師只有1%的幫助...

社區(qū)的力量

最后幾章揭示了Unix為何生命力如此長久的原因葵蒂,在人和技術(shù)的平衡關(guān)系上做了非常仔細而微妙的分析交播。

第十七章:軟件可移植性與遵循標準

軟件開源了,你想讓更多的人使用你的軟件践付,但是傳播的障礙常常來自操作系統(tǒng)和硬件結(jié)構(gòu)秦士。

移植性一直是Unix的主要優(yōu)勢,所以一旦設(shè)想軟件項目生命周期很短永高,就容易犯錯隧土。

只要在架構(gòu)、接口和實現(xiàn)上命爬,API是穩(wěn)定的曹傀,其他特殊細節(jié)都是無關(guān)緊要的。

比如饲宛,C和Unix緊密關(guān)聯(lián)皆愉,是硬件和操作系統(tǒng)間的薄膠合層。它是在1971年誕生的,后期逐步引入typedef幕庐、union等操作符久锥,版本7引入了枚舉,并且將結(jié)構(gòu)體和union作為一等公民异剥。C語言標準造成了“K&R C”和“ANSIC”的區(qū)別瑟由,并且產(chǎn)生了一個很好的實踐:在標準化之前,先實現(xiàn)各種pollify冤寿。

再延伸到Unix標準歹苦,同樣使用公開標準作為API說明。雖然經(jīng)過了分裂和內(nèi)戰(zhàn)疚沐,但Unix的標準在實踐中得以奠定下來。

開源社區(qū)為了標準化潮模,也需要確保源碼的兼容性很強亮蛔。

舉個例子:IETF和RFC標準化過程,里面就體現(xiàn)了互聯(lián)網(wǎng)工程任務組的思維方式:標準必須來自于一個可用原型實現(xiàn)的經(jīng)驗擎厢。

當然也有理想化的標準究流,比如臭名昭著的七層OSI模型。我們要考慮這點:在成為標準之前动遭,實現(xiàn)的要求是越來越高的芬探。所以只有當草案標準經(jīng)過了實現(xiàn)的廣泛測試并且達到了普遍接受的程度,就真正成為標準了厘惦。

對此作者打了個形象的比方:規(guī)格是DNA偷仿,代碼是RNA。因為代碼是可棄的宵蕉,標準才是應該保留完善的酝静。

代碼從屬于標準,先做一個原型再不斷地測試和演進才是好辦法羡玛,生成半自動化的測試套件也是一個主要優(yōu)勢别智,可以穩(wěn)步迭代。至于相關(guān)的系統(tǒng)行為爭論可以在規(guī)則功能層面解決稼稿,非規(guī)格(功能)即bug薄榛。

話題順著到可移植性編程上,這個問題看似是準空間問題让歼,實際上時間上的持久性同樣重要敞恋。

首要問題是選擇語言,作者對當時流行的語言做了移植性分析:

語言 移植性特點
C 高谋右,但對于IPC耳舅、線程和GUI接口有困難
C++ 類似C
Shell 差,大部分shell使用了其他可移植性差的工具
Perl 良,看情況
Python 優(yōu)秀
Tcl 一般浦徊,隨項目復雜度有差異(看依賴)
Java 出色馏予,但幾個版本間的GUI有兼容問題
Emacs Lisp 相當好,問題出在使用C接口的地方

總的來說就是避免系統(tǒng)依賴性盔性,發(fā)布源碼勝過二進制碼霞丧,不要想著幫助不大的移植工具。

所以現(xiàn)在js成了可移植性語言之王冕香。JavaScript is everywhere蛹尝。

另外一點和移植化有關(guān)的是國際化,實現(xiàn)它我們需要分離信息庫和代碼悉尾,并且盡量使用UTF8字符集突那,使用正則時注意字符范圍就好了。

那可移植性/開放標準和開放源碼有什么關(guān)系呢构眯?可移植性需要標準愕难,而開源促進了標準化。另外惫霸,不要依賴專有技術(shù)猫缭,哪天作者跳坑就GG。

第十八章:文檔(向網(wǎng)絡(luò)世界闡釋代碼)

Unix最初的目的就是整理文檔壹店,troff格式器是始祖猜丹,現(xiàn)在的趨勢是朝著html和url鏈接發(fā)展。

首先讓我們區(qū)分一下標記型和可視型的文檔:一種是面向程序員的硅卢,一種是面向初級用戶的射窒。

標記型又分表現(xiàn)型和結(jié)構(gòu)型的,而大多數(shù)以標記為中心的文檔系統(tǒng)都支持宏将塑。

Unix風格的文檔具備幾個文化和技術(shù)特征:

  1. 偏愛大文檔
  2. 寫給技術(shù)人員看轮洋,手冊頁往往包含一個BUGS部分
  3. 擅長編寫參考書籍

各種Unix文檔格式

文檔類型 特征
troff和DWT 表示層語言不如結(jié)構(gòu)層語言,大量用于技術(shù)文檔
TEX 使用輔助程序比如LETEX編寫抬旺,大量用于數(shù)學和科學領(lǐng)域
Texinfo 可以生成HTML
POD Perl的標記系統(tǒng)弊予,可以生成手冊但不能生成HTML
HTML 未來趨勢,在生成索引上有問題
DocBook XML文檔類型定義开财,可以轉(zhuǎn)換成HTML汉柒、PDF等格式

于是書中大膽的預言未來的出路是XML一統(tǒng)天下...然而現(xiàn)在json橫空出世...

對于DocBook,作者還特意描述了一下:有一條轉(zhuǎn)換工具鏈责鳍,先驗證是否是符合正確的文檔格式碾褂,再根據(jù)樣式單加樣式最后輸出。

但是最后還是批判了這條又臭又長的工具鏈历葛,即使優(yōu)化成FOP了還是不咋地正塌。

最后本章總結(jié)了編寫文檔的最佳實踐:就是不要忽悠讀者嘀略。

  • 數(shù)量多不會被認為質(zhì)量高
  • 信息密度要適中
  • 大項目最好發(fā)布手冊頁/教程/常見問題解答列表
  • 文檔中要有readme
  • 考慮新手用戶,技術(shù)名詞盡量用全稱
  • 文檔格式應該易于傳播

第十九章:開源(在社區(qū)中編程)

Unix在開放源碼上就做了很好的表率乓诽,將找/改bug的任務分解成多個并行的子任務帜羊,然后眾力編程。

而開源有如下幾個特點:

  1. 源碼公開
  2. 盡早發(fā)布/經(jīng)常發(fā)布鸠天,前提是項目正常運行
  3. 給貢獻給予表揚
  4. 開源項目管理盡量自動化

之后便是本章的重點:如何與開源開發(fā)者協(xié)同工作的最佳實踐

  1. 良好的修補實踐
    1.1 是否換位思考/知道合并的后果
    1.2 發(fā)送dif部分/針對當前版本/不要包含可生成文件/不要發(fā)送系統(tǒng)自動拓展的字段
    1.3 在補丁中包含文檔/解釋/有用的注釋

通過代碼質(zhì)量評估補丁

  1. 良好的命名實踐
    2.1 使用GNU風格讼育,例如foobar-1.2.3.tar。gz
    2.2 文件名/版本和區(qū)分度是最重要的
    2.3 尊重適當?shù)谋镜丶s定
    2.4 選擇容易鍵入的前綴

  2. 良好的開發(fā)實踐
    3.1 不要依賴專有代碼
    3.2 使用GNU自動工具管理項目
    3.3 先測試再發(fā)布代碼
    3.4 發(fā)布前對代碼進行健全檢查(能夠捕捉到錯誤)
    3.5 對readme進行拼寫檢查
    3.6 考慮移植性

  3. 良好的發(fā)布制作實踐
    4.1 確保打包文件總是解包到單一新目錄下
    4.2 包含README文件(項目介紹稠集、項目demo演示奶段、環(huán)境問題、關(guān)鍵架構(gòu)剥纷、編譯安裝指令痹籍、維護者光榮榜、項目新聞晦鞋、項目郵件列表地址等)
    4.3 尊重和遵從標準文件命名實踐(看社區(qū)的習俗)
    4.4 為可升級性設(shè)計
    4.5 提供RPM(類似npm)
    4.6 提供校驗和

供他人更好地下載蹲缠、獲取和使用

  1. 良好的交流實踐
    5.1 在社區(qū)和社交平臺發(fā)公告
    5.2 建立一個網(wǎng)站
    5.3 提供項目郵件列表
    5.4 發(fā)布到主要的檔案站點

便于招攬用戶與合作者

本章最后分析了許可證如何挑選,畢竟它會對軟件施加限制鳖宾。

雖然可以直接放在公共域吼砂,但使用某個標準許可證可以避免很多爭論逆航。

有MIT鼎文、BSD、GPL等許可證因俐,具體可以看阮一峰的如何選擇開源許可證

終章:危機與機遇

本書的結(jié)尾章拇惋,總結(jié)了過去如何應對的設(shè)計挑戰(zhàn),以及未來確定需要解決的問題和有待開拓的機會抹剩。

Unix最終要的是什么撑帖?當然是它的文化,而從傳統(tǒng)來看它有平質(zhì)和偶然屬性澳眷,平質(zhì)屬性和偶然屬性是可以互相轉(zhuǎn)化的胡嘿。

在歷史的長河中,三個特殊的技術(shù)變化驅(qū)動了Unix設(shè)計風格中的重大變革:網(wǎng)絡(luò)互聯(lián)钳踊、位圖圖形顯示和PC普及衷敌。

在這其中Unix一直保持著獨有的設(shè)計準則:模塊化、透明性拓瞪、機制同策略分離等缴罗。

有人嘗試重做Unix(Plan9),但最終失敗祭埂,不過給予了Unix發(fā)展的啟迪面氓。這是一個比Unix更Unix的設(shè)計,并且還增加了一個概念:私有命名空間,但更優(yōu)秀解決方案的最危險敵人舌界,就是一個現(xiàn)存的掘譬、足夠優(yōu)秀的代碼庫,沒有質(zhì)變禀横,誰會改變自己的慣性使用新事物呢屁药?

當然,Unix設(shè)計中也存在許多問題柏锄,這里著重討論幾個存在爭論的失敗之處:

  • Unix文件只有字節(jié)
  • Unix對GUI的支持孱弱
  • 文件刪除不可撤銷
  • 假定文件系統(tǒng)是靜態(tài)的
  • 作業(yè)控制設(shè)計拙劣
  • API的異常處理不好
  • 設(shè)備中插入鉤子的方法(ioctl和fcntl)是個雞肋
  • 安全模型太過原始
  • 名字種類太多
  • 文件系統(tǒng)的爭論
  • 朝向全局互聯(lián)網(wǎng)地址空間

跳出程序員的眼界酿箭,來看看整個社會環(huán)境下,Unix如何發(fā)展:

首先要獲得持續(xù)的經(jīng)濟支持趾娃,提高程序員的社會價值缭嫡,然后組織終端用戶測試,獲取良好的反饋抬闷,最后要反對微軟/好萊塢等巨頭妇蛀,為自由而斗爭。

Unix文化中也有問題:內(nèi)部轉(zhuǎn)型的小問題和克服歷史上的優(yōu)越感的大問題笤成。

比如和Mac之爭评架,但Mac和Unix的設(shè)計哲學都有正確的一面,應該互相理解炕泳。不要把自己從騎士變成惡龍纵诞。

舍得拋棄過去,不再過分依賴那些已經(jīng)很好地為我們工作過的設(shè)想培遵。

勝利也不是全面的浙芙,低端市場和非技術(shù)用戶被忽略了。

最后的最后籽腕,作者語重心長的說:

“我們能贏嗡呼,只要我們想贏』屎模“

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末南窗,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子郎楼,更是在濱河造成了極大的恐慌万伤,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件箭启,死亡現(xiàn)場離奇詭異壕翩,居然都是意外死亡,警方通過查閱死者的電腦和手機傅寡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門放妈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來北救,“玉大人,你說我怎么就攤上這事芜抒≌洳撸” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵宅倒,是天一觀的道長攘宙。 經(jīng)常有香客問我,道長拐迁,這世上最難降的妖魔是什么蹭劈? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮线召,結(jié)果婚禮上铺韧,老公的妹妹穿的比我還像新娘。我一直安慰自己缓淹,他們只是感情好哈打,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著讯壶,像睡著了一般料仗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上伏蚊,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天立轧,我揣著相機與錄音,去河邊找鬼丙挽。 笑死肺孵,一個胖子當著我的面吹牛匀借,可吹牛的內(nèi)容都是我干的颜阐。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼吓肋,長吁一口氣:“原來是場噩夢啊……” “哼凳怨!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起是鬼,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤肤舞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后均蜜,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體李剖,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年囤耳,在試婚紗的時候發(fā)現(xiàn)自己被綠了篙顺。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片偶芍。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖德玫,靈堂內(nèi)的尸體忽然破棺而出匪蟀,到底是詐尸還是另有隱情,我是刑警寧澤宰僧,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布材彪,位于F島的核電站,受9級特大地震影響琴儿,放射性物質(zhì)發(fā)生泄漏段化。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一造成、第九天 我趴在偏房一處隱蔽的房頂上張望穗泵。 院中可真熱鬧,春花似錦谜疤、人聲如沸佃延。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽履肃。三九已至,卻和暖如春坐桩,著一層夾襖步出監(jiān)牢的瞬間尺棋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工绵跷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留膘螟,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓碾局,卻偏偏與公主長得像荆残,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子净当,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容