莊周夢(mèng)蝶

          生活、程序、未來(lái)
             :: 首頁(yè) ::  ::  :: 聚合  :: 管理

          模塊性:保持清晰,保持簡(jiǎn)潔

          軟件設(shè)計(jì)有兩種方式:一種是設(shè)計(jì)得極為簡(jiǎn)潔沒(méi)有看得到的缺陷;另一種是設(shè)計(jì)得極為復(fù)雜有缺陷也看不出來(lái)。第一種方式的難度要大得多。

          模塊化代碼的首要特質(zhì)就是封裝API在模塊間扮演雙重角色,實(shí)現(xiàn)層面作為模塊之間的滯塞點(diǎn),阻止各自的內(nèi)部細(xì)節(jié)被相鄰模塊知曉;在設(shè)計(jì)層面,正是API真正定義了整個(gè)體系。

          養(yǎng)成在編碼前為API編寫一段非正式書面描述的習(xí)慣,是一個(gè)非常好的方法。

          模塊的最佳大小,邏輯行200-400行,物理行在400-800之間。

          緊湊性就是一個(gè)設(shè)計(jì)能否裝入人腦中的特性。測(cè)試軟件緊湊性的一個(gè)簡(jiǎn)單方法是:一個(gè)有經(jīng)驗(yàn)的用戶通常需要用戶手冊(cè)嗎?如果不需要,那么這個(gè)設(shè)計(jì)是緊湊的。

          理解緊湊性可以從它的“反面”來(lái)理解,緊湊性不等于“薄弱”,如果一個(gè)設(shè)計(jì)構(gòu)建在易于理解且利于組合的抽象概念上,則 這個(gè)系統(tǒng)能在具有非常強(qiáng)大、靈活的功能的同時(shí)保持緊湊。緊湊也不等同于“容易學(xué)習(xí)”:對(duì)于某些緊湊 設(shè)計(jì)而言,在掌握其精妙的內(nèi)在基礎(chǔ)概念模型之前,要理解這個(gè)設(shè)計(jì)相當(dāng)困難;但一旦理解了這個(gè)概念模型,整個(gè)視角就會(huì)改變,緊湊的奧妙也就十分簡(jiǎn)單了。緊湊也不意味著“小巧”。即使一個(gè)設(shè)計(jì)良好的系統(tǒng),對(duì)有經(jīng)驗(yàn)的用戶來(lái)說(shuō)沒(méi)什么特異之處、“一眼”就能看懂,但仍然可能包含很多部分。

          評(píng)測(cè)一個(gè)API緊湊性的經(jīng)驗(yàn)法則是:API入口點(diǎn)通常在7個(gè)左右,或者按《代碼大全2》的說(shuō)法,7+27-2的范圍內(nèi)。

          重構(gòu)技術(shù)中的很多壞味道,特別是重復(fù)代碼,是違反正交性的明顯例子,“重構(gòu)的原則性目標(biāo)就是提高正交性”。

          DRY原則,或者稱為SPOT原則(single point of truth)——真理的單點(diǎn)性。重復(fù)的不僅僅是代碼,還包括數(shù)據(jù)結(jié)構(gòu),數(shù)據(jù)結(jié)構(gòu)模型應(yīng)該最小化,提倡尋找一種數(shù)據(jù)結(jié)構(gòu),使得模型中的狀態(tài)跟真實(shí)世界系統(tǒng)的狀態(tài)能夠一一對(duì)應(yīng)

          要提高設(shè)計(jì)的緊湊性,有一個(gè)精妙但強(qiáng)大的方法,就是圍繞“解決一個(gè)定義明確的問(wèn)題”的強(qiáng)核心算法組織設(shè)計(jì),避免臆斷和捏造,將任務(wù)的核心形式化,建立明確的模型。


          文本化:好協(xié)議產(chǎn)生好實(shí)踐

          文本流是非常有用的通用格式,無(wú)需專門工具就可以很容易地讀寫和編輯文本流,這些格式是透明的。如果擔(dān)心性能問(wèn)題,就在協(xié)議層面之上或之下壓縮文本協(xié)議流,最終產(chǎn)生的設(shè)計(jì)會(huì)比二進(jìn)制協(xié)議更干凈,性能可能更好。使用二進(jìn)制協(xié)議的唯一正當(dāng)理由是:如果要處理大批量的數(shù)據(jù),因而確實(shí)關(guān)注能否在介質(zhì)上獲得最大位密度,或者是非常關(guān)心將數(shù)據(jù)轉(zhuǎn)化為芯片核心結(jié)構(gòu)所必須的時(shí)間或指令開(kāi)銷

          數(shù)據(jù)文件元格式:

          1DSV風(fēng)格,DElimiter-Seperated Values

          使用分隔符來(lái)分隔值,例如/etc/passwd

          適合場(chǎng)景:數(shù)據(jù)為列表,名稱(首個(gè)字段)為關(guān)鍵字,而且記錄通常很短(小于80個(gè)字符)

          2、RFC 822格式

          互聯(lián)網(wǎng)電子郵件信息采用的文本格式,使用屬性名+冒號(hào)+值的形式,記錄屬性每行存放一個(gè),如HTTP 1.1協(xié)議。

          適合場(chǎng)景:任何帶屬性的或者與電子郵件類似的信息,非常適合具有不同字段集合而字段中數(shù)據(jù)層次又扁平的記錄。

          3、Cookie-jar格式。簡(jiǎn)單使用跟隨%%的新行符(或者有時(shí)只有一個(gè)%)作為記錄分隔符,很適用于記錄非結(jié)構(gòu)化文本的情況。

          適合場(chǎng)景:詞以上結(jié)構(gòu)沒(méi)有自然順序,而且結(jié)構(gòu)不易區(qū)別的文本段,或適用于搜索關(guān)鍵字而不是文本上下文的文本段。

          4、Record-jar格式,cookie-jarRFC-822的結(jié)合,形如

          name:dennis
          age:
          21
          %%
          name:catty
          age:
          22
          %%
          name:green
          age:
          10

          這樣的格式。

          適合場(chǎng)景:那些類似DSV文件,但又有可變字段數(shù)據(jù)而且可能伴隨無(wú)結(jié)構(gòu)文本的字段屬性關(guān)系集合。

          5、XML格式,適合復(fù)雜遞歸和嵌套數(shù)據(jù)結(jié)構(gòu)的格式,并且經(jīng)??梢栽跓o(wú)需知道數(shù)據(jù)語(yǔ)義的情況下僅通過(guò)語(yǔ)法檢查就能發(fā)現(xiàn)形式不良損壞或錯(cuò)誤生成的數(shù)據(jù)。缺點(diǎn)在于無(wú)法跟傳統(tǒng)unix工具協(xié)作。

          6、Windows INI格式,形如

          [DEFAULT]
          account
          =esr

          [python]
          directory
          =/home/ers/cvs/python
          developer
          =1

          [sng]
          directory
          =/home/esr/WWW/sng
          numeric_id
          =1001
          developer
          =1

          [fetchmail]
          numeric_id
          =4928492

          這樣的格式

          適合場(chǎng)景:數(shù)據(jù)圍繞指定的記錄或部分能夠自然分成“名稱-屬性對(duì)”兩層組織結(jié)構(gòu)。

          Unix文本文件格式的約定:

          1、如果可能,以新行符結(jié)束的每一行只存一個(gè)記錄

          2、如果可能,每行不超過(guò)80個(gè)字符

          3、使用”“引入注釋

          4、支持反斜杠約定

          5、在每行一條記錄的格式中,使用冒號(hào)或連續(xù)的空白作為字段分隔符。

          6、不要過(guò)分區(qū)分tabwhitespace

          7、優(yōu)先使用十六進(jìn)制而不是八進(jìn)制。

          8、對(duì)于復(fù)雜的記錄,使用“節(jié)(stanza)”格式,要么讓記錄格式和RFC 822電子郵件頭類似,用冒號(hào)終止的字段名關(guān)鍵字作為引導(dǎo)字段。

          9、在節(jié)格式中,支持連續(xù)行,多個(gè)邏輯行折疊成一個(gè)物理行

          10、要么包含一個(gè)版本號(hào),要么將格式設(shè)計(jì)成相互獨(dú)立的的自描述字節(jié)塊。

          11、注意浮點(diǎn)數(shù)取整。

          12不要僅對(duì)文件的一部分進(jìn)行壓縮或者二進(jìn)制編碼。

          應(yīng)用協(xié)議元格式

          1、經(jīng)典的互聯(lián)網(wǎng)應(yīng)用元協(xié)議 RFC 3117《論應(yīng)用協(xié)議的設(shè)計(jì)》,如SMTP、POP3IMAP等協(xié)議

          2、作為通用應(yīng)用協(xié)議的HTTP,在HTTP上構(gòu)建專用協(xié)議,如互聯(lián)網(wǎng)打印協(xié)議(IPP

          3、BEEP:塊可擴(kuò)展交換協(xié)議,既支持C/S模式,又支持P2P模式

          4、XMP-RPCSOAPJabber,基于XML的協(xié)議。


          透明性:來(lái)點(diǎn)光

          美在計(jì)算科學(xué)中的地位,要比在其他任何技術(shù)中的地位都重要,因?yàn)?strong>軟件是太復(fù)雜了。美是抵御復(fù)雜的終極武器。

          如果沒(méi)有陰暗的角落和隱藏的深度,軟件系統(tǒng)就是透明的。透明性是一種被動(dòng)品質(zhì)。如果實(shí)際上能預(yù)測(cè)到程序行為的全部或大部分情況,并能建立簡(jiǎn)單的心理模型,這個(gè)程序就是透明的,因?yàn)榭梢?strong>看透機(jī)器究竟在干什么。

          如果軟件系統(tǒng)所包含的功能是為了幫助人們對(duì)軟件建立正確的“做什么、怎樣做”的心理模型而設(shè)計(jì),這個(gè)軟件系統(tǒng)就是可顯的。

          不要讓調(diào)試工具僅僅成為一種事后追加或者用過(guò)就束之高閣的東西。它們是通往代碼的窗口:不要只在墻上鑿出粗糙的洞,要修整這些洞并裝上窗。如果打算讓代碼一直可被維護(hù),就始終必須讓光照進(jìn)去。例如fetchmail-v選項(xiàng)將處理SMTP、POP的處理過(guò)程打印到標(biāo)準(zhǔn)輸出,使得fetchmail行為具有可顯性。

          在“這個(gè)設(shè)計(jì)能行嗎?”之后要提出的頭幾個(gè)問(wèn)題就是“別人能讀懂這個(gè)設(shè)計(jì)嗎?這個(gè)設(shè)計(jì)優(yōu)雅嗎?”我們希望,此時(shí)大家已經(jīng)很清楚,這些問(wèn)題不是廢話,優(yōu)雅不是一種奢侈。在人類對(duì)軟件的反映中,這些品質(zhì)對(duì)于減少軟件bug和提高軟件長(zhǎng)期維護(hù)性是最基本的。

          要追求代碼的透明性,最有效的方法是很簡(jiǎn)單,就是不要在具體操作的代碼上疊放太多的抽象層。

          OO語(yǔ)言使得抽象變得容易——也許是太容易了。OO語(yǔ)言鼓勵(lì)“具有厚重的膠合和復(fù)雜層次”的體系。當(dāng)問(wèn)題領(lǐng)域真的很復(fù)雜,確實(shí)需要大量抽象時(shí),這可能是好事,但如果coder到頭來(lái)用復(fù)雜的辦法做簡(jiǎn)單的事情——僅僅是為他們能夠這樣做,結(jié)果便適得其反。

          所有的OO語(yǔ)言都顯示出某種使程序員陷入過(guò)度分層陷阱的傾向。對(duì)象框架和對(duì)象瀏覽器并不能代替良好的設(shè)計(jì)和文檔,但卻常常被混為一談。過(guò)多的層次破壞了透明性:我們很難看清這些層次,無(wú)法在頭腦中理清代碼到底是怎樣運(yùn)行的。簡(jiǎn)潔、清晰和透明原則通通被破壞了,結(jié)果代碼中充滿了晦澀的bug,始終存在維護(hù)問(wèn)題。

          膠合層中的“智能數(shù)據(jù)”卻經(jīng)常不代表任何程序處理的自然實(shí)體——僅僅只是膠合物而已(典型現(xiàn)象就是抽象類和混入(mixin)的不斷擴(kuò)散)

          OO抽象的另一個(gè)副作用就是程序往往喪失了優(yōu)化的機(jī)會(huì)。

          OO在其取得成功的領(lǐng)域(GUI、仿真和圖形)之所以能成功,主要原因之一可能是因?yàn)樵谶@些領(lǐng)域里很難弄錯(cuò)類型的本體問(wèn)題。例如,在GUI和圖形系統(tǒng)中,類和可操作的可見(jiàn)對(duì)象之間有相當(dāng)自然的映射關(guān)系。

          Unix風(fēng)格程序設(shè)計(jì)所面臨的主要挑戰(zhàn)就是如何將分離法的優(yōu)點(diǎn)(將問(wèn)題從原始的場(chǎng)景中簡(jiǎn)化、歸納)同代碼和設(shè)計(jì)的薄膠合、淺平透層次結(jié)構(gòu)的優(yōu)點(diǎn)相組合。

          太多的OO設(shè)計(jì)就像是意大利空心粉一樣,把“is-a”have a的關(guān)系弄得一團(tuán)糟,或者以厚膠合層為特征,在這個(gè)膠合層中,許多對(duì)象的存在似乎只不過(guò)是為了在陡峭的抽象金字塔上占個(gè)位置罷了。這些設(shè)計(jì)都不透明,它們晦澀難懂并且難以調(diào)試。

          為透明性和可顯性而編碼:

          1、程序調(diào)用層次中(不考慮遞歸)最大的靜態(tài)深度是多少?如果大于,就要當(dāng)心。

          2、代碼是否具有強(qiáng)大、明顯的不變性質(zhì)(約束)?不變性質(zhì)幫助人們推演代碼和發(fā)現(xiàn)有問(wèn)題的情況。

          3、每個(gè)API中各個(gè)函數(shù)調(diào)用是否正交?或者是否存在太多的magic flags或者模式位?

          4、是否存在一些順手可用的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)或全局唯一的記錄器,捕獲系統(tǒng)的高層次狀態(tài)?這個(gè)狀態(tài)是否容易被形象化和檢驗(yàn),還是分布在數(shù)目眾多的各個(gè)全局變量或?qū)ο笾卸y以找到?

          5、程序的數(shù)據(jù)結(jié)構(gòu)或分類和它們所代表的外部實(shí)體之間,是否存在清晰的一對(duì)一映射。

          6、是否容易找到給定函數(shù)的代碼部分?不僅單個(gè)函數(shù)、模塊,還有整個(gè)代碼,需要花多少精力才能讀懂?

          7、代碼增加了特殊情況還是避免了特殊情況?每一個(gè)特殊情況可能對(duì)任何其他特殊情況產(chǎn)生影響:所有隱含的沖突都是bug滋生的溫床。然而更重要的是,特殊情況使得代碼更難理解。

          8、代碼中有多少個(gè)magic number?通過(guò)審查是否很容易查出代碼中的限制(比如關(guān)鍵緩沖區(qū)的大?。?/p>

          隱藏細(xì)節(jié)無(wú)法訪問(wèn)細(xì)節(jié)有著重要區(qū)別。不要過(guò)度保護(hù)。

          無(wú)論何時(shí)碰到涉及編輯某類復(fù)雜二進(jìn)制對(duì)象的設(shè)計(jì)問(wèn)題時(shí),unix傳統(tǒng)都提倡首先考慮,是否能夠編寫一個(gè)能夠在可編輯的文本格式和二進(jìn)制格式之間來(lái)回進(jìn)行無(wú)損轉(zhuǎn)換的工具?這類工具可稱為文本化器(textualizer).

          寧愿拋棄、重建代碼也不愿修補(bǔ)那些蹩腳的代碼。

          “代碼是活代碼、睡代碼還是死代碼?”活代碼周圍存在一個(gè)非常活躍的開(kāi)發(fā)社團(tuán)。睡代碼之所以“睡著”,經(jīng)常是因?yàn)閷?duì)作者而言,維護(hù)代碼的痛苦超過(guò)了代碼本身的效用。死代碼則是睡得太久,重新實(shí)現(xiàn)一段等價(jià)代碼更容易。


          評(píng)論

          # re: 《Unix編程藝術(shù)》重讀筆記(二)  回復(fù)  更多評(píng)論   

          2011-03-30 16:06 by xufeng
          受益匪淺!
          主站蜘蛛池模板: 新干县| 濮阳县| 卢湾区| 大庆市| 澄迈县| 青河县| 黄平县| 中方县| 惠东县| 沭阳县| 方正县| 特克斯县| 黑水县| 周宁县| 措美县| 涞水县| 栖霞市| 凤冈县| 滦平县| 金门县| 南宁市| 调兵山市| 丰顺县| 宜昌市| 乌鲁木齐县| 博罗县| 荥经县| 康乐县| 介休市| 河津市| 平谷区| 佛教| 广河县| 南充市| 息烽县| 婺源县| 象山县| 浪卡子县| 玛多县| 霍邱县| 循化|