程式碼質量(權威精選植根於開發實踐的最佳讀物)

broadviewbj發表於2012-08-27

Jolt大獎精選叢書

程式碼質量(權威精選植根於開發實踐的最佳讀物)

(希)斯賓耐立思(Spinellis,D.)著

左飛,吳躍,李潔譯

ISBN 978-7-121-17421-6  

2012年7月出版

定價:89.00元

16開

512頁

宣傳語:一項技術產品只有在獲得了Jolt獎之後才能真正成為行業的主流,一本技術圖書只有在獲得了Jolt獎之後才能真正奠定經典的地位。

內 容 簡 介

Jolt大獎素有“軟體業之奧斯卡”的美稱,本叢書精選自Jolt歷屆獲獎圖書,以植根於開發實踐中的獨到工程思想與傑出方法論為主要甄選方向。Diomidis Spinellis首部著作《程式碼閱讀》(Code Reading)旨在闡明程式設計師應如何理解與修改程式碼,與此不同的是,本書重點討論程式碼的非功能特性,深入講述程式碼如何滿足重要的非功能性需求,如可靠性、安全性、可移植性和可維護性,以及時間效率和空間效率。本書從Apache Web應用伺服器、BSD UNIX作業系統和HSQLDB Java資料庫等開源專案中攫取數百個小例子,並以例項為基準點,輔以理論分析,從實用的角度講述每個專業軟體開發人員能立即運用的概念和技術。

本書榮獲2007年Jolt大獎,適用於不同知識層次的軟體工作、程式開發和研究人員。

出版說明

經久不息的迴盪

今時的讀書人,不復有無書可讀之苦,卻時有品種繁多而無從擇優之惑,甚而專業度頗高的技術書領域,亦日趨遭逢亂花迷眼的境地。此時,若得覓權威書評,抑或有公信力的排行榜,可按圖索驥,大大增加選中好書的命中率。然而,如此良助,不可多得,縱觀中外也唯見一枝獨秀——素有“軟體業奧斯卡”之美譽的Jolt獎!

震撼世界者為誰

在計算裝置已經成為企業生產和日常生活之必備工具的今天,專業和大眾使用者對於軟體的功能、效能和使用者體驗的要求都在不斷提高。在這樣的背景下,如何能夠發揮出軟體開發的最高效率和最大效能,已經是擺在每一個從業者面前的重大課題,而這也正是Jolt大獎橫空出世的初衷及堅持數年的宗旨。

Jolt大獎歷時20餘年,在圖書及軟體業知名度極高,廣受推崇。獎如其名,為引領電腦科學與工程發展主流,Jolt堅持將每年的獎項只頒給那些給整個IT業界帶來震撼結果的圖書、工具、產品及理念等,因一流的眼光及超高的專業度而得以聞名遐邇,聲名遠播。

除圖書外,Jolt針對軟體產品設有諸多獎項分類,如配置管理、協作工具、資料庫引擎/資料庫工具、設計工具/建模、開發環境、企業工具、庫/框架、移動開發工具等。但圖書歷來是Jolt大獎中最受矚目且傳播最廣的一個獎項分支。Jolt曾設有通用類圖書、技術類圖書等分類,每個分類又設有“卓越獎”(Jolt Award,一般為一個)和“生產力獎”(Productivity Award,一般為2或3個)。獲獎技術圖書一經公佈,即打上經典烙印,可謂一舉“震撼全世界”(贊助商Jolt可樂的廣告詞)。

作為計算機技術圖書的厚愛者,我們總在追問——是誰在震撼世界,是誰在照亮明天?Jolt大獎恰似擺在眼前的櫥窗,讓我們可以近距離觀看潮流在舞蹈,傾聽震撼在轟鳴!

朝花夕拾為哪般

Jolt像是一年一度的承諾,在茫茫書海中為我們淘礪出一批批經得起歲月沖刷的傑作,頭頂桂冠的佳作也因而得以一批批引進中國,為國人開闊了眼界,滋補了技術養分。然而,或因技術差距造就的生不逢時、水土不服,或因翻譯、製作的不如人意,抑或是疏於宣傳等諸多原因,這些經典著作在國內出版後,儘管不乏如獲至寶的擁躉,卻仍不為諸多人所知,從而與大量本應從中獲益的讀者擦肩而過。既然這生生錯失的遺憾本不該發生,則更不應延續。為此,我們邀國外出版同行、國內技術專家一道,踏上朝花夕拾之路,竭力為廣大讀者篩選出歷久彌新、震撼依舊的Jolt圖書精品。

Jolt獲獎圖書皆由業界專家一致評出,並得到軟體從業人員的高度認可,雖然這些書今天讀來,不再能看到上世紀史詩時代那般日新月異的理論突破,以及依賴於高深繁複的科學研究所取得的系統化成果,更多是在日復一日的開發實踐中總結和提煉出來的工程思想和方法論。重新選材之所以有所棄取,從Jolt多年來的評獎規律中可窺端倪——

一萬小時真理見

凡是在工程思想領域取得革命性、顛覆性突破的圖書,就被歸於“震撼”獲獎分類。比如,從基於過程的程式設計模型過渡到物件導向的全新模型,就是軟體開發思想上的一次帶來巨大震撼的革命;再比如,打破傳統的瀑布模型而轉向持續整合的軟體交付模型,這也是一場業界的重大思想轉變。像這樣的重大思想突破,可以說是數年甚至數十年一遇的,而榮獲Jolt大獎的圖書中更為常見的,則是基於最佳實踐的“生產效率”獲獎者。獲得此類殊榮的圖書,都是作者們從平凡的、重複的,甚至用一般人的眼光看來不怎麼起眼的日常開發實踐中,以獨具的慧眼、過人的耐心和大膽的創新,闖開一條不平常道路的心血與經驗總結。

這些圖書所涉及的主題,都是普通的軟體開發人員每天要面對的工作——程式碼閱讀、撰寫測試用例、修復軟體問題……但就是這樣貌似平淡無奇的工作,是否能每一天、每一個專案都做好,著實拉開了軟體開發人員素質的差距,也決定了軟體企業開發出來的產品和服務的質量。我們中國有一句古話,叫做熟能生巧;某位著名企業家也說過一句家喻戶曉的名言:“把簡單的事千百萬次地做好,就是不簡單的。”這些樸素而實際的真理,同樣也是本套叢書最能彰顯的所謂程式設計師精神。它建立在腳踏實地的實踐基礎之上,也充滿了對於自由和創新的嚮往。

名作可堪比名曲

就不因歲月流逝而褪色來說,與這些Jolt名作相媲美者,只有那些百年響徹、震撼古今的經典名曲。希望本叢書帶給大家的每部著作,也如百聽不厭的樂曲,掩卷良久方餘音繞樑,真知存心。仔細想來,軟體開發與古典音樂豈非有異曲同工之妙?既是人類心智索問精確科學的探究,亦是尋覓美學享受的追求。工程是藝術的根基,而藝術是工程的極致。衷心地希望各位讀者能夠認真閱讀本叢書的本本珍品,並切實地用於自己的日常工作中,在充分享受大師魅力的同時,為中國的軟體事業譜寫更多、更震撼的樂章。

 

電子工業出版社博文視點

二○一二年春 

原作者中文版序

中國是首個將我的“開源視角”系列作品再版的國家。這可能有很多原因,而其中一個特別吸引人的原因與孔子的著作有關,他在《論語》中廣泛地強調了學習研究的重要性。回顧之前撰寫《程式碼閱讀》和《程式碼質量》1 的歷程,我瞭解到,實際上,我鼓勵了那些從事開發工作的同事和學生藉助研究學習軟體程式碼來提升他們自身的知識和技能,這正是我遵循孔子金玉良言的一種方式。

《程式碼閱讀》一書闡述了開發者應當如何閱讀已有的程式碼。關於為何要進行程式碼閱讀,不少人也給出了許多現實中的原因:修正問題、新增特性、尋找有用的片段,或者作為你所在機構質量控制流程的一部分對其進行復查。然而,進行程式碼閱讀最重要的原因其實是從中學習。從已有的高質量程式碼中,我們可以學習如何將嚴謹的程式碼風格應用於實踐,如何編寫有用的註釋,如何編排程式碼以方便他人讀懂,如何選擇有意義的識別符號,以及如何將複雜的程式碼組織為可管控的部分。另外,通過研究程式碼,我們還可以學習到新的演算法、API及架構。簡而言之,閱讀程式碼可以幫助我們成為更加優秀的程式設計師。

《程式碼質量》一書,退後一步,方為大觀。當程式碼被組裝為程式時將會產生所謂的聚現屬性2 :可靠性、安全性、CPU利用率、空間佔用率、可移植性及可維護性。儘管這些屬性可能看起來抽象且難以約束,但是諸多成功的經驗表明,藉助研究專家級的程式碼,我們可以學習到許多極好的提升程式碼質量的方法。我們可以從中發現嚴謹的錯誤測試、安全證照的保守處理、高效的演算法、靈巧的抽象技術及應用於實踐中的基本設計模式。簡而言之,這將有助於我們成為極其優秀的程式設計師。

偉大的哲學家孔子曾經提過:“學而不思則罔,思而不學則殆”。因此我推薦大家主動花些時間來研究已有的程式碼並從中予以學習。

Diomidis Spinellis

2011年9月於雅典

推 薦 序

今年恰逢“十二五”開局之年,在全球軟體技術和產業格局孕育重大調整之際,我國軟體產業也在工業化、資訊化“兩化融合”的大背景下迎來了又一個快速發展的新階段,這其中機遇與挑戰並存。當下軟體和資訊服務業市場的規模不斷擴大,物聯網作為又一個萬億元級別的產業將產生千億元級別的服務外包。預計到2020年,全球潛在的服務外包市場需求將達到1.65~1.8萬億美元,大力發展軟體業及資訊服務業將成為各國抓住新機遇、全面深度參與全球化、提升軟體產業技術力量的重要途徑。目前我國軟體產業規模雖已過萬億元,但在核心技術、基礎軟體等方面仍有很大發展空間。

高素質人才的儲備是推進產業健康快速發展的根本保證。高階軟體人才的大量持續湧現,關鍵在於教育,這其中高校無疑要發揮重要的作用。我們高校軟體教育者既要繼續貫徹黨的教育理念,進一步深化我國高階軟體人才培養體系的發展程式;同時又要看到我國與歐美等高水平軟體人才教育國家之間的距離,師夷長技,以求在全球化浪潮中謀得一席之地。作為一位優秀的軟體教育者,Diomidis Spinellis教授的某些理念無疑是非常值得我們學習和借鑑的。他以人類學習自然語言的認知規律為出發點,獨闢新徑,強調藉助程式碼閱讀來提高程式設計能力。目前這一思潮也已逐漸由歐美向我國滲透。

程式碼閱讀是每一個軟體從業人員經常進行的活動,其重要性對於每一個開發者不言而喻,但人們更多的是在本著修改前人程式碼而進行此項活動的,換言之,僅僅使用了程式碼閱讀的工作屬性,而未見開發其學習屬性。其實,程式碼閱讀還幫助人們完成了“觀察—模仿—創造”這樣一個過程的初始階段。南朝劉勰《文心雕龍》裡講“觀千劍而後識器”,與之類似,清乾隆年間蘅塘退士還說“熟讀唐詩三百首,不會作詩也會吟”,這都是強調了觀察對於之後創造的重要性(巧合的是寫詩和寫程式碼的觀察都是藉助閱讀來完成的)。

令人遺憾的是,一直以來,許多人都認為閱讀程式碼不是件容易的事情,不僅不容易,很多時候還非常枯燥;即使是自己寫的程式碼,有時隔一段時間再回顧也會不知所云。很多人在自己的編碼生涯中都或多或少有過一些閱讀程式碼的經歷,有自己的一些方法,但也僅僅是一些個人實踐而已,缺乏對整體的把握,經常是隻見樹木不見森林(很多時候僅僅能看到一小部分樹木)。為了在學習的過程中少走一些彎路,業界程式碼閱讀與質量提升方面的開宗明義之作——Diomidis Spinellis教授所撰寫的兩部經典之作《程式碼閱讀》和《程式碼質量》無疑是推薦給每位從業人員的理想讀物。這兩部曾榮獲美國Jolt軟體開發震撼大獎的作品,影響了一代程式設計師,是相關領域中的經典名作。

我閱讀了兩部書的譯稿,並非常欣喜地將它們推薦給每一位讀者。該書譯者和編輯們嚴謹、認真的工作使得本版最大程度地還原了作者的原意,相信經由他們的辛勤努力,必將能為廣大讀者獻上一道驚豔的佳作。

歐陽修說:“立身以立學為先,立學以讀書為本。”衷心希望廣大讀者藉由本書立學解惑,提升自我。

 

李戰懷

於2011歲末

譯 者 序

軟體產業無疑是本世紀最具廣闊前景的新興產業之一。在該領域,中國擁有數以千億計的市場規模,更有無數富有才華和熱情的年輕從業者。作為一種“無汙染、微能耗、高產值且勞動力密集”的產業,軟體產業不但能大幅度提高國家整體經濟執行效率,而且自身也可以形成龐大規模,拉昇國民經濟總體水平。進入新世紀以來,中國的軟體產業迅猛發展,成果固然可喜,但我們也應清醒地看到中國軟體產業同美國、日本、印度等軟體強國之間的差距。隨著資訊科技的發展,軟體產業將會成為衡量一個國家綜合國力的標誌之一。因此,發展和扶持軟體產業,是一個國家提高國家競爭力的重要途徑,也是參與全球化競爭所必須佔領的戰略制高點。為鼓勵和促進軟體產業的健康、可持續發展,國務院先後印發了《鼓勵軟體產業和積體電路產業發展的若干政策》和《進一步鼓勵軟體產業和積體電路產業發展若干政策》兩項通知,以及《國務院振興軟體產業行動綱要》等綱領性、指導性檔案,力求在產業政策、人才培養及其他相關配套等各方面形成合力,共促中國軟體產業大發展。

作為推進中國軟體產業大發展戰略佈局中的重要一環,軟體人才培養始終是萬業之基、重中之重。為此,教育部於2001年在全國頂尖高校中組織成立了35所國家示範軟體學院。國家示範軟體學院本著“開拓創新、改革示範、育人為本、質量為先、面向產業、走向世界”的理念,以培養“國際化、工程型”人才為目標,在軟體人才培養的大路上披荊斬棘、一路求索,先後為國家輸送了十萬餘名高素質軟體人才,摸索出了一整套行之有效的軟體人才培養體系,為中國軟體產業發展提供了源源不斷的動力。

時光荏苒,2011年,國家示範軟體學院成立10週年慶祝大會在北京隆重舉行。包括國家部委領導、教育界和軟體企業界的耕耘者們、外國專家學者在內的業界精英濟濟一堂,共同慶祝這承載了無數光榮與夢想的歷史時刻。作為國家示範軟體學院的優秀畢業生代表,我也有幸參加了此次盛會。會上有關領導及專家充分肯定了國家示範軟體學院的辦學成果,同時寄予中國軟體產業和軟體教育事業以厚望。

科教可以興國,中國軟體產業的可持續發展,關鍵在於人才。要培養出更多高質量、國際化、工程型的軟體人才,高校與社會同樣承擔有艱鉅而光榮的使命。我們既要繼續發揚和鞏固已經取得的成果,推進中國軟體人才培養的科學化體系建設,同時也應看到中國同世界上其他軟體強國在軟體教育方面的差距,取人之長、以補己短。作為當今世界上的頭號科技強國和世界軟體產業的領跑者,美國在軟體人才培養方面同樣有許多可貴的經驗和成果值得我們借鑑。其中,關於軟體技術的許多真知灼見已經凝聚成了一本本經久不衰的科技專著。作為一名技術作家、譯者,我們一直希望同中國的IT出版業一道將這些承載著先進思想的著作介紹給國人,若能以這種方式為中國軟體產業和軟體教育事業略盡綿薄之力,吾輩也必將倍感歡欣。

由國際知名的Addison-Wesley出版社推出的“高效軟體開發系列”叢書為現代軟體開發的方方面面提供了專業的建議和意見。收錄在該系列中的書籍本本都是技術方面聲名卓著的佳作,這些書籍的作者在創作時煞費苦心,力求作品篇幅適中、易於閱讀,同時保證作品的價值能夠歷久彌新,而不會隨時光的流逝而漸顯黯淡。系列中的每一本都描述了一項軟體開發的核心話題,這些內容可能是業界專家們在開發中始終秉承的,也可能是需要本書的讀者們引以為戒的,而之所以這樣做的目的只有一個,就是要創造出最傑出的軟體。Diomidis Spinellis教授的兩部著作《程式碼質量》和《程式碼閱讀》均收錄在此係列中。在IT產業蓬勃發展的今日,電子工業出版社順應時代發展和廣大讀者希冀,隆重推出了“Jolt大獎精選叢書”,《程式碼閱讀》和《程式碼質量》再次被收入其中。經典之作《程式碼質量》得以撥雲開霧,同廣大中國讀者見面。

作者的這兩本書都可謂是在業界獨樹一幟的經典之作。在學習如何編寫程式碼之前,應當首先學習如何閱讀程式碼,因為眾所周知,學習其他語言方法都是先學閱讀,再學寫作,而且在當前,大多數開發人員的主要任務是修改已存在的程式碼,而不是開發程式碼。即使是主要從事開發的人員,也難免出於各種各樣的目的去閱讀他人的程式碼,其中一件重要的事情就是優化程式碼,提升程式碼質量。如果說作者的《程式碼閱讀》一書將閱讀程式碼的技巧傳授給了讀者,那麼《程式碼質量》則為後續的提高和優化提供了指導。《程式碼質量》一書重點討論了程式碼的非功能特性,深入講述程式碼如何滿足重要的非功能性需求,如可靠性、安全性、可移植性和可維護性,以及時間效率和空間效率。本書從Apache Web應用伺服器、BSD/UNIX作業系統和HSQLDB資料庫等開源專案中攫取數百個小例子,並以例項為基準點,輔以理論分析,從實用的角度講述每個專業軟體開發人員能立即運用的概念和技術。我們相信,每一名軟體從業者都會從中有所收穫、有所提高。作為譯者,我們真誠地將該書推薦給國內的讀者,希望藉由本書,可以提高廣大軟體從業人員的編碼質量,開啟中國軟體人才培養的新思路,若能如此,我心足矣。

懷揣著這樣的心情,我們始終秉持著一絲不苟的態度,力求把經典之作原汁原味地帶給中國讀者。而一本專業技術領域的譯作得以成功問世,其中之波折也是在所難免。幸得多位業內專家不吝指導,使得我們的工作倍感鼓舞。在本書翻譯之初,原書作者Diomidis Spinellis教授即給我們提出了許多寶貴的建議,他的指導給予我們極大的幫助。此外,西北工業大學博士生導師、計算機學院副院長李戰懷教授審閱了譯稿,並欣然為本書作序推薦,感激之情,溢於言表。參與本書翻譯校對工作的還有楊寧、丁瑋、張曼、王團團、胡宗正、王延青,對於他們嚴肅認真的工作態度,謹表示由衷敬佩。

最高品質的圖書始終是作譯者永恆的追求。但有一千個讀者,就有一千個哈姆雷特。因此,我們也真誠地希望本書的讀者能夠把閱讀中的所想所得與我們分享,能夠把書中的紕漏毫無保留地向我們指出,從而使得本書能夠日臻完善,以利來者。歡迎訪問筆者的技術部落格http://baimafujinji.blog.51cto.com,或發郵件至heisbaixingzhi@163.com。

 

左飛

2011年秋

原書序言

鮮有作者能夠在計算機領域中開闢全新的主題,但Diomidis Spinellis卻借其第一本書《程式碼閱讀》做到了這一點。目前大多數IT從業人員對研究閱讀程式碼而非編寫程式碼的書籍異常渴望。軟體思想的一個學派強調應在教授初學者編寫程式碼前先教授他們閱讀程式碼。原因在於:一,先讀後寫是其他自然語言常用的學習辦法;二,21世紀以來大多數程式設計師的任務為修改現有程式碼(這就是說應先閱讀),而非開發新的程式碼。故而我十分欣喜地發現Spinellis認識到了程式碼閱讀的重要性,並就該主題為我們撰寫了一本字字珠璣的圖書。

當然,這也引發了一個有趣的問題:Spinellis重灌上陣時會為我們帶來什麼?他能多少次開闢全新的主題?其實,遺憾的是他的新書《程式碼質量》並未做這方面的嘗試,但他卻在其中分析了在我看來最為重要和令人費解的軟體工程主題——軟體質量。說其重要是因為程式碼若無足夠的質量保證可能就完全沒有價值;說其費解是因為軟體質量在一千個軟體開發者眼中就有一千個標準,讓人難以捉摸。

Spinellis非常出色地闡述了這一重要而令人費解的主題。當前,大多數關於軟體質量的討論都是專注於高階管理層面的,身處在這樣一個環境中,Spinellis卻剖析事物本質,直擊程式碼質量中所反映的至關重要的主題——質量技術。在我自己看來(可能非常偏激),於管理層面上討論程式碼質量幾乎是毫無意義的,原因在於人們只有在程式碼實現層面上才能看清構成質量的各個元素。以Spinellis所討論的可維護性與可移植性這兩個質量特徵為例,若無對程式碼的分析,我們就不可能理解什麼是可維護和可移植的軟體。

對那些追求跨過技術層直接進入管理層的讀者來說——我認為這類人現在不在少數——這本書並不適於他們理解程式碼質量。但對於那些認為程式碼質量本質上首先是一個技術性主題,其次才是一個管理學主題的讀者,這本書正是一個合適的起點。作者Spinellis也在本書的開始這樣寫道:“從這本書中,你將學到如何判斷軟體質量。”向他致敬!

Robert L.Glass

2006年1月

前  言

程式設計和其他事情一樣,錯誤即重生。

——Alan J. Perlis

我希望自己能在前言中這樣寫道:你手邊的這本書是精心策劃而成的出版結果,其始於《程式碼閱讀》,而終於《程式碼質量》。然而,這麼做是對事實的一種歪曲,也是對我們這些工程師所喜愛的有序世界的一種媚從。其實真相是《程式碼質量》大體上源自一系列的偶然事件。

簽下出版《程式碼閱讀》一書的合同時,我手頭已有了一個綱要和一些完成的章節。基於這些完成章節的長度和所耗精力,我天真錯誤地估計了全書長度和成書日程。若你靠編寫軟體為生,可能已猜到,在書稿應完成之時,我僅僅完成了大綱章節的一半多一點,並已用完所有分撥篇幅。為體面脫身,我建議編輯將已完成的部分(除去關於可移植性的一章)作為《程式碼閱讀》的第1卷出版,而將剩下的工作作為第2卷。我們達成了一致,於是《程式碼閱讀》[Spi03a]出版。結果該書好評如潮,並獲得了2004年度軟體開發雜誌生產效率大獎(The 2004 Software Development Magazine Productivity Awards),還被譯為其他6種語言。

在《程式碼閱讀》一書中,我以取自實際工作中的開源專案為例,嘗試覆蓋軟體開發人員可能面對的大多數與程式碼相關的概念,包括程式結構、資料型別、資料結構、控制流、專案組織、編碼標準、文件及架構。在第2卷中,我先前計劃涉及介面與面向應用的程式碼,包括國際化與可移植性問題、常用庫與作業系統要素、底層程式碼、領域特定語言與宣告性語言、指令碼語言及混合語言系統。但當程式設計師們拿到《程式碼閱讀》一書後,我從他們那裡獲得了一些有益的看法。他們給我的反饋表明許多讀者都在焦急地等待著下一卷,不過他們期望的並不是一個對於裝置驅動程式的詳細剖析(我之前為接下來的一卷保留的一章)。2003年7月,時任編輯Mike Hendrickson建議我撰寫一本名為Secure Code Reading的書。雖然作為一個科學家,IT安全是個讓我感興趣的領域,但是我懶於追逐寫作安全方面書籍的時尚,故而僅寫了一個與安全有關的章節。在有了一個與可移植性相關的章節和一個與安全相關的章節後,我突然找到了新書的書名和主題——《程式碼質量》,其應將重點放於閱讀和編寫軟體程式碼及軟體程式碼的質量屬性上(這些也時常被稱為非功能屬性)。

藉助閱讀軟體系統的程式碼,我們可以發現非功能屬性與產品的非功能需求相關。該需求不與系統提供的特定功能直接相關,而是與更廣泛的重要系統屬性有一定的關係。常見的與系統屬性相關的非功能屬性為:可靠性、可移植性、易用性、互用性、適應性、相依性及可維護性。另外兩個與系統的效率有關的值得注意的非功能屬性是:系統與時間約束有關的效能和系統空間需求。

藉助閱讀程式碼來了解系統非功能屬性是開發者必不可少的一項技能,這裡面有兩個原因。一是未滿足非功能需求所引發的結果可能是危險的,甚至是災難性的。一個系統若僅某些功能需求出現錯誤(大多數軟體系統都含有這樣的錯誤),則其還能以降級模式執行,使用者也會被告知避免使用其中的一些功能。但若非功能需求出現錯誤則較為嚴重:不安全的Web伺服器或不可靠的防抱死系統(ABS)比無法使用更糟糕。二是非功能需求有時難於驗證。我們寫不出這樣一個測試用例使得它能夠驗證系統的可靠性或系統是否存在安全漏洞。基於以上兩點,我們在應對非功能需求及相關軟體屬性時,需利用我們所能利用的一切手段。將程式碼與非功能屬性聯絡起來的能力應是每一位軟體工程師都需具備的有力武器。

除去視角不同外,《程式碼質量》沿用了《程式碼閱讀》的成功祕訣,即重點關注已有程式碼的閱讀;僅分析取自現有開源系統的例項;給出所有例項的來源;採用註釋來剖析程式碼;提供有意義的練習來強化讀者的批判能力和技巧;在頁邊空白處指出編碼習慣及陷阱;以箴言錄的形式總結每章的建議;在“延伸閱讀”部分,給之前的實踐以理論的擴充;採用了UML(Unified Modeling Language)來繪製所有簡圖。其中最為精妙的元素就是我自行強加的規則——避免使用“玩具”示例(toy example),所有的用例都須取自現有開源專案。為踐行該規則,我常常花費數小時來尋找一個合適的例子,它應當既能表明我欲展示的概念,又要易於理解,並且還需足夠短小以便可放至一本書中。個人認為這樣的活動既有助於智力同時也可使作品更為嚴謹。通常在尋找某方面的缺點時,我會碰到其他值得討論的內容。有時我對於某理論概念示例的尋找沒有什麼結果,那麼在此情形下,我就有理由認為在實踐中這些概念並未重要到必須將其囊括於本書的地步。

《程式碼質量》和《程式碼閱讀》背後的原理與動機是一脈相承的——閱讀程式碼可能是計算機專業人員最常見的活動之一,不過其卻較少被當做一門課程來教授或被正式當做一種學習程式設計和編碼的方法來使用。所幸開源軟體的盛行已向人們提供了大量可供自由閱讀和學習的程式碼。基於開源軟體的初級讀本是提高個人程式設計能力的有價值的工具。所以我希望這兩本書能夠引發人們在計算機教育課程中加入程式碼閱讀的課程、活動及練習的熱情。如此一來,在不久的將來,就像是從優秀的文學作品中學習寫作一般,我們的學生就可從現有的開源系統中學習程式設計了。

內容及補充材料

我決定在《程式碼質量》中沿用同《程式碼閱讀》中一樣的系統和分發版本作為開原始碼樣例。原因是我認為兩卷間必須存在一定的延續性,這樣方可允許讀者觀察到同樣的原始碼如何既能在《程式碼閱讀》中被用於認識其所涵蓋的功能、架構及設計等功能特性,又能被用於《程式碼質量》中所涉及的非功能特性。

本書所用的程式碼來自於那些大多數僅有歷史意義的程式碼快照。然而有了它們,我就可以藉機展示那些在較新版本中已被發現並更正的安全漏洞、同步問題、可移植性問題、API呼叫的誤用及其他bug。這些許久之前的程式碼可能表明,其作者目前或已晉升至管理崗位以致不喜於閱讀此類書籍,或視力退化至無法看清書中字型。我可藉助這些變化來自由品評相關程式碼,而不用擔心險惡的報復。雖如此,我還是可能被指責誹謗那些懷有推進開源運動信念的作者所貢獻之程式碼,我對此表示理解,同時也認同我們應當改進這些程式碼而非僅僅對其評論。若我的評論使某些原始碼的作者感到冒犯,請允許我預先在這裡真誠的道歉。不過作為對自己言行的辯護,我個人認為在大多數例項中,我的評論並非針對特定的程式碼片段而是藉助其來指明開發者在實踐中應避免的行為。通常情況下,被我作為反例來使用的程式碼都是易受此類傷害的物件,原因在於它們被編寫時,技術及其他方面的限制使得其也算是一種合理的行為,抑或我的一些特定的批評其實脫離了程式碼所處上下文。無論何種情形,我都希望這些評論能得到你的善意一笑,同時我也坦率承認,我本人的程式碼也包含有類似的,甚至可能更糟的錯誤。

選擇本書示例所用系統時,出於實用的原因,我希望這些程式碼能夠適於作為教學載體。故而我所尋找的內容涵蓋程式碼質量、結構、設計、功用、流行度及無版權問題。我儘可能平衡語言的選擇,積極尋找合適的Java和C++程式碼。然而,當類似概念可被多種語言演示時,我選擇採用C作為“最小公分母”。所以,本書中引用的61%的程式碼為C程式碼,這其中包括適用所有語言的例項及系統級程式設計(多用C語言)例項。另外19%的例項引用了Java程式碼。選擇Java程式碼是為了展示與物件導向概念及相關API有關的元素。這些概念多也適用於C#,並且許多也適用於C++(4%的例項引用了C++程式碼)。

此外,在本書中我也更為強調UNIX中的API和工具而非Windows中的類似元素。原因依然涉及“最小公分母”邏輯——許多UNIX中的工具和API在Windows中也有對應元素,而反之則不然。大量與UNIX相相容的系統,如GNU/Linux與BSD的一些變體,都是免費提供的,並且常常還向使用者提供可引導的CD-ROM,如此一來任何人都可輕鬆體驗這樣的系統。最後,UNIX中的API和工具,從我所引示例的細節方面來看,在過去30餘年來一直保持著驚人的穩定,這就為我們討論和展示通用規則提供了一個堅實的根基。雖然如此,我還是在一些地方引用了Windows API及命令來討論非UNIX平臺上的情況。但是請別讓這些引用欺騙了你——我並不認為本書涉及Windows平臺的程式設計問題要比涉及UNIX平臺的相關問題完整和廣泛。

除去在所有例項中均採用開源軟體外,本書可能被(狹隘地)指為忽略了大量的流行時尚,如Java、C#、Windows、Linux及以解決現有問題為導向的寫作風格。其實我很看重前述這些元素:我這裡29%的機器執行著Linux,我教授一門Java課程,我已在Windows平臺上寫了大量程式,並且我的書架上至少有10本書充滿了帶序號的段落來提供解決很多問題的具體建議。然而,我還是相信在當今這個充滿變化的世界,理解說教背後的原理至關重要。正如你在下面的章節中將會看到的,一旦我們將重點關注於原理,則:

    底層技術的選擇常常會被虛化。

    我們學到的東西就擁有更廣的應用性和更長的時效。

    具體的建議會自行浮現(見每一章末的“那些值得記住的建議”)。

最重要的一點在於,是否理解程式設計講義背後的原理才是一個受尊重的軟體工程師同一個卑微的碼農之間的區別。

鳴謝

許多人都慷慨貢獻了他們的建議、評註及時間來助我完成本書的寫作。首先,我要感謝本系列的編輯Scott Myers,他擔起了類似於讀者的角色,巧妙地為本書指引了方向,系統地闡明瞭本書可在哪些地方變得更加易讀和精悍。Hal Fulton、Hang Lau與Gabor Liptak閱讀了本書的樣章並提出了許多有用的評註和意見。Chris Carpenter與Robert L. Glass也審閱了本書的樣章及之後的整個草稿,他們的智慧和經驗讓我受益匪淺。十分感謝Konstantinos Aboudolas、Damianos Chatziantoniou、Giorgos Gousios、Vassilios Karakoidas、Paul King、Spyros Oikonomopoulos、Colin Percival、Vassilis Prevelakis、Vassilis Vlachos、Giorgos Zervas,特別是Panagiotis Louridas,他們非正式地審閱了本書早期草稿的部分章節,並提供了用以改進的具體評註和建議。此外,Stephanos Androutsellis-Theotokis、Lefteris Angelis、Davide P. Cervone、Giorgos Giaglis、Stavros Grigorakakis、Fred Grott、Chris F. Kemerer、Spyros Kokolakis、Alexandros Kouloumbis、Isidor Kouvelas、Tim Littlefair、Apostolis Malatras、Nancy Pouloudi、Angeliki Poulymenakou、Yiannis Samoladas、Giorgos Sarkos、Dag-Erling Smørgrav、Ioannis Stamelos、Dave Thomas、Yar Tikhiy、Greg Wilson、Takuya Yamashita、Alexios Zavras、Giorgos Zouganelis也提供了有價值的建議,我時常突然跑到他們那裡請教一些專業領域中艱澀的問題。我還想感謝雅典經濟與貿易大學管理科學與技術系的同事們對於我工作的支援。我也感謝下面這三人在本書寫作過程中一些必不可少的方面給予我的指導:Mireille Ducassé(技術寫作——1990)、John Ioannidis(程式碼風格——1983)和Jan-Simon Pendry(時間與空間效能——1988)。

Addison-Wesley出版社的編輯Peter Gordon熟練地指導了本書的創作,處理了很多棘手的問題。Kim Boedigheimer以出眾的效率應對了日常事務。7小時的時差常常允許我們在一天內以20個小時一輪換的方式來開展本書的工作。

在本書的創作過程中,Elizabeth Ryan如同一個專業指揮家一般,高效地協調和團結著我們這個全球化多學科的寫作團隊。

其他作者將本書的文字編輯Evelyn Pyle描述為如同鷹一般目光犀利。我同意該說法並且還要說一句:她的工作真是十分出色,她找出了很多我永遠也想象不出的手稿錯誤,同時她也比較注意細節和一致性,並據此對相關文字做了修改,僅有少數頂尖程式設計師才能與之相比。另外兩位具有類似程式設計技藝的人員也為本書的完成做出了自己的貢獻:Clovis L. Tondo依靠對書中工具的深入理解和書中程式碼的驚人尊重完成了本書的排版工作,Sean Davey則依靠自身卓越的能力確保本書風格的一致。

本書絕大多數所引例項來自於已有的開源專案。使用源自真實世界的程式碼允許我能展示人們在實踐中可能遇到的程式碼型別,而非被簡化過的“玩具”程式。所以我想感謝所有對本書中所引開源程式有貢獻的開發者,感謝他們向程式設計社群貢獻其工作成果。若書中程式碼的作者姓名被列於相應的原始碼檔案中,則其也會出現於本書的附錄中。

 

目   錄

表目錄

圖目錄

原書序言

前言

第1章  導論       1

1.1  軟體質量      1

1.1.1  使用者、製造者和管理者眼中的質量       2

1.1.2  質量屬性   4

1.1.3  緊張的世界       6

1.2  如何閱讀本書      8

1.2.1  排版約定   8

1.2.2  圖示   9

1.2.3  圖表   11

1.2.4  彙編程式碼   11

1.2.5  練習   11

1.2.6  補充材料   12

1.2.7  工具   12

第2章  可靠性    15

2.1  輸入問題      16

2.2  輸出問題      19

2.2.1  不完整輸出或輸出缺失   19

2.2.2  錯誤時刻的正確結果       22

2.2.3  錯誤的格式       22

2.3  邏輯問題      24

2.3.1  偏差為一的錯誤與迴圈迭代   24

2.3.2  被忽視的極端情況   25

2.3.3  被遺漏的情況、條件測試或步驟   27

2.3.4  被遺漏的方法   32

2.3.5  多餘的功能       35

2.3.6  誤解   37

2.4  計算問題      39

2.4.1  不正確的演算法或計算       39

2.4.2  表示式中錯誤的運算元   41

2.4.3  表示式中不正確的運算子       44

2.4.4  運算子優先順序問題   45

2.4.5  溢位、下溢和符號轉換錯誤   46

2.5  並行性與時序問題      48

2.6  介面問題      53

2.6.1  不正確的例程或引數       53

2.6.2  沒有測試返回值       55

2.6.3  未做錯誤探查或恢復       58

2.6.4  資源洩漏   60

2.6.5  物件導向功能的誤用       63

2.7  資料處理問題      64

2.7.1  不正確的資料初始化       64

2.7.2  引用錯誤的資料變數       66

2.7.3  越界引用   69

2.7.4  不正確的下標使用   72

2.7.5  不正確的比例或資料單位       73

2.7.6  錯誤的資料打包與解包   75

2.7.7  不一致的資料   77

2.8  容錯      79

2.8.1  管理策略   79

2.8.2  空間冗餘   81

2.8.3  時間冗餘   83

2.8.4  可復原性   84

第3章  安全性    93

3.1  脆弱程式碼      94

3.2  緩衝區溢位   98

3.3  競態條件      103

3.4  問題API       106

3.4.1  容易出現緩衝區溢位的函式   106

3.4.2  格式字串漏洞       108

3.4.3  路徑和命令列直譯器元字元漏洞   110

3.4.4  臨時檔案   111

3.4.5  不適合做加密用途的函式       112

3.4.6  可篡改資料       114

3.5  不可信輸入   115

3.6  結果驗證      120

3.7  資料與特權洩漏   124

3.7.1  資料洩漏   124

3.7.2  特權洩漏   128

3.7.3  Java的方案       129

3.7.4  分離特權程式碼   131

3.8  特洛伊木馬   133

3.9  工具      135

第4章  時間效能       139

4.1  測量技術      143

4.1.1  負載描述   144

4.1.2  受限於I/O的任務    145

4.1.3  受限於核心的任務   148

4.1.4  受限於CPU的任務和剖析工具      149

4.2  演算法複雜性   158

4.3  獨立的程式碼   163

4.4  與作業系統互動   167

4.5  與外設互動   173

4.6  非故意的互動      175

4.7  快取      178

4.7.1  一個簡單的系統呼叫快取       178

4.7.2  替換策略   180

4.7.3  預先計算結果   182

第5章  空間效能       189

5.1  資料      190

5.1.1  基本資料型別   191

5.1.2  聚合資料型別   194

5.1.3  對齊   196

5.1.4  物件   202

5.2  記憶體組織      206

5.3  記憶體層級結構      210

5.3.1  主存及其快取記憶體   211

5.3.2  磁碟快取和後備儲存器   214

5.3.3  交換區和基於檔案的磁碟儲存       216

5.4  程式/作業系統介面   217

5.4.1  記憶體分配   218

5.4.2  記憶體對映   219

5.4.3  資料對映   219

5.4.4  程式碼對映   220

5.4.5  訪問硬體資源   221

5.4.6  程式間通訊       222

5.5  堆記憶體管理   224

5.5.1  堆碎片       225

5.5.2  堆剖析       230

5.5.3  記憶體洩漏   233

5.5.4  垃圾回收   237

5.6  棧記憶體管理   239

5.6.1  棧幀   240

5.6.2  棧空間       243

5.7  程式碼      248

5.7.1  設計期       250

5.7.2  編碼期       252

5.7.3  構建期       253

第6章  可移植性       261

6.1  作業系統      262

6.2  硬體與處理器架構      267

6.2.1  資料型別的屬性       267

6.2.2  資料儲存   269

6.2.3  特定於機器的程式碼   271

6.3  編譯器與語言擴充套件      273

6.3.1  編譯器錯誤       273

6.4  圖形使用者介面(GUI)       277

6.5  國際化與本地化   279

6.5.1  字符集       280

6.5.2  區域   282

6.5.3  訊息   285

第7章  可維護性       293

7.1  測量可維護性      294

7.1.1  可維護性指數   294

7.1.2  物件導向程式的度量       300

7.1.3  包的相關性度量       309

7.2  可分析性      316

7.2.1  一致性       318

7.2.2  表示式格式化   319

7.2.3  語句格式化       320

7.2.4  命名慣例   321

7.2.5  語句級註釋       324

7.2.6  版本註釋   326

7.2.7  視覺結構:塊與縮排       327

7.2.8  表示式、函式以及方法的長度       328

7.2.9  控制結構   331

7.2.10  布林表示式     335

7.2.11  可辨認性與內聚性  337

7.2.12  依賴和耦合     339

7.2.13  程式碼塊註釋     351

7.2.14  資料宣告註釋  354

7.2.15  恰當的識別符號名字  355

7.2.16  依賴的位置     356

7.2.17  不確定性  357

7.2.18  可複查性  358

7.3  可變性   363

7.3.1  識別   363

7.3.2  分離   368

7.4  穩定性   377

7.4.1  封裝與資料隱藏       378

7.4.2  資料抽象   381

7.4.3  型別檢查   383

7.4.4  編譯時斷言       386

7.4.5  執行時檢查和檢視時斷言       389

7.5  可測試性      390

7.5.1  單元測試   391

7.5.2  整合測試   394

7.5.3  系統測試   396

7.5.4  測試覆蓋度分析       398

7.5.5  偶發性測試       401

7.6  開發環境的影響   406

7.6.1  增量構建   407

7.6.2  調整構建效能   410

第8章  浮點運算       417

8.1  浮點數表示   418

8.1.1  量度誤差   420

8.1.2  舍入   421

8.1.3  記憶體格式   424

8.1.4  規格化和隱含的一位       425

8.1.5  階碼偏移   425

8.1.6  負數   426

8.1.7  反向規格化數   426

8.1.8  特殊值       427

8.2  舍入      428

8.3  溢位      432

8.4  下溢      434

8.5  消去      437

8.6  合併      441

8.7  無效運算      445

附錄A  原始碼致謝人員名單    453

參考文獻       455

 

表 目 錄

表2-1  測試極端情況  26

表2-2  測試一個不含尾端的非對稱範圍的例子     26

表2-3  整數量的範圍  46

表2-4  在程式生命週期不同階段所做的引數型別檢查  54

表2-5  在C++中約束類的使用  64

 

表3-1  UNIX伺服器開放網路埠列表   96

表3-2  Windows工作站開放網路埠列表     96

表3-3  進行ftpd緩衝區攻擊時的棧 100

表3-4  展開棧(預設情況)     102

表3-5  在攻擊過程中展開棧     102

表3-6  不安全的C函式及其安全的替代函式 107

表3-7  Java 2平臺SE 5.0的許可     130

 

表4-1  用時剖析特徵、診斷工具及解決方案  144

表4-2  由環境切換和程式間通訊導致的開銷  168

表4-3  低速外設導致的開銷     174

 

表5-1  不同架構下基本資料型別的表示  191

表5-2  AMD64架構上結構體元素的對齊       197

表5-3  一個程式在不同架構和作業系統上的記憶體佈局  209

表5-4  連續的地址空間限制及相應的解決方案     216

表5-5  構建選項對程式大小的影響  254

 

表6-1  各種開發平臺的可移植性問題     262

表6-2  Java平臺標準字元編碼  282

表6-3  區域特定的欄位     284

 

表7-1  可維護性指數的引數     295

表7-2  WebServerConnection方法與它們使用的欄位    306

表7-3  WebServerConnection類的相似(內聚)方法與相異方法 307

表7-4  不同型別的訪問控制下可以訪問類成員的方法數     379

 

表8-1  不同舍入模型的例子     422

表8-2  不同浮點格式的關鍵屬性     424

表8-3  導致異常的運算和運算元     445

圖 目 錄

圖1-1  軟體質量的各個方面的例子:使用中質量、

外部質量、內部質量及過程質量       3

圖1-2  本書脈絡:軟體質量的要素  5

圖1-3  質量特徵間的衝突  7

圖1-4  標註列表示例  9

圖1-5  基於UML的圖示符號   10

 

圖2-1  使用評註,toString方法的反射式實現       21

圖2-2  藉助策略模式關聯程式碼和資料     30

圖2-3  使用介面實現建立處理器     30

圖2-4  物件私有資源的顯式管理     34

圖2-5  郵件傳送代理守護程式sendmail的除錯程式碼     37

圖2-6  通過靜態分析探查null指標引用  42

圖2-7  藉助wait和notify管理資源的使用     49

圖2-8  使用有瑕疵的雙檢鎖模式     51

圖2-9  記憶體洩漏與資源洩漏之間的關係  61

圖2-10  在NetBSD核心中分配與釋放檔案描述符 62

圖2-11  使用自動產生的原始碼定義字型的輪廓    65

圖2-12  NetBSD原始碼中全域性變數定義(左)和引用(右)的位置 67

圖2-13  NetBSD核心全域性變數所用的型別     68

圖2-14  將位元組串編碼為改進過的UTF-8格式      76

圖2-15  SCSI裝置驅動程式中一個命令序列重傳  84

圖2-16  自有故障的磁碟上恢復資料       87

 

圖3-1  FTP守護程式中的緩衝區溢位     99

圖3-2  PPP守護程式碼中的一個競態條件  104

圖3-3  pppd漏洞的檢查/使用時間差利用       104

圖3-4  檢查/使用時間差漏洞利用時序圖 105

圖3-5  strcpy和strcat的不安全用法 108

圖3-6  strcpy和strcat正確應用在一個動態分配大小的緩衝區上 108

圖3-7  不安全地清除環境變數  116

圖3-8  安全地清除環境變數     116

圖3-9  未正確檢查traceroute實現中的錯誤返回值       122

圖3-10  在TCP Wrappers程式中嵌入特洛伊木馬程式碼   134

 

圖4-1  專家對於優化程式碼的警告     142

圖4-2  在HSQLDB程式碼中EJP對帕累托法則的闡述    151

圖4-3  對於vfprintf函式的gprof輸出的例子 153

圖4-4  呼叫圖中處理時間的傳播     156

圖4-5  某些常見演算法類別的相對效能     159

圖4-6  簡單cat呼叫中的系統呼叫   169

圖4-7  logger呼叫時本地程式間通訊產生的系統呼叫  171

圖4-8  ping名字查詢的遠端DNS程式間通訊所產生的系統呼叫       172

圖4-9  系統顛簸對執行時效能的影響     176

圖4-10  使用使用者ID來命名快取程式碼     179

圖4-11  快取資料庫行記錄       181

 

圖5-1  結構體的兩種儲存方式:填充以確保對齊(上),

打包以節省記憶體(下)       199

圖5-2  從大到小排列結構體元素,確保對齊且節省記憶體     200

圖5-3  OpenCL演算法繼承樹的UML類圖 203

圖5-4  三個OpenCL演算法類的C++虛擬函式表  204

圖5-5  指向例項資料的Java物件    205

圖5-6  有著一個指向例項資料和類資料的控制程式碼的Java物件 206

圖5-7  記憶體資源的型別     207

圖5-8  程式記憶體組織  207

圖5-9  現代計算機的一個儲存層次結構  211

圖5-10  100萬個分配物件的大小分佈    227

圖5-11  100萬個分配物件的生命週期分佈     227

圖5-12  用於顯示記憶體碎片的記憶體池快照       228

圖5-13  外部記憶體碎片的一個例子   229

圖5-14  內部記憶體碎片的一個例子   229

圖5-15  Apache HTTP伺服器記憶體分配剖析    231

圖5-16  sed流編輯器的記憶體剖析     232

圖5-17  valgrind記憶體洩漏測試工具的報告     236

圖5-18  C正規表示式庫中的記憶體洩漏    237

圖5-20  一個棧幀的內容   242

圖5-21  棧大小的快照       244

圖5-22  資料和棧大小的關係   245

圖5-23  原始檔與目標檔案大小之間的關係   249

圖5-24  ACE地址型別中的繼承      251

 

圖6-1  使用隔離層來提供可移植性  264

圖6-2  儲存於小端與大端架構上的整數0x04030201    270

圖6-3  GUI可移植性策略的例子     278

圖6-4  使用catgets介面做訊息處理 287

圖6-5  使用gettext介面做訊息處理 287

圖6-6  使用GNU gettext工具的訊息本地化流程   288

圖6-7  在Java servlet中訪問本地化訊息 290

 

圖7-1  測量擴充套件圈複雜度  297

圖7-2  FreeBSD核心和使用者程式的增長與可維護性指標隨時間的變化     298

圖7-3  所有FreeBSD模組的可維護性指數分佈     298

圖7-4  類的加權方法數度量:對所有的HSQLDB類(左);

不同的WMC值對應的Eclipse類個數(右)   301

圖7-5  繼承樹深度度量:對於所有的HSQLDB類(左);

不同DIT值對應的Eclipse類的數量(右)      302

圖7-6  HSQLDB:高DIT值的類的繼承樹度量和它們所定義的方法數     302

圖7-7  Eclipse類的子類數度量 303

圖7-8  物件類之間的耦合:對於每個HSQLDB類(左);

不同的CBO值對應的Eclipse類的數量(右) 304

圖7-9  類的響應:對於所有的HSQLDB類(左);

不同的CBO值對應的Eclipse類的數量(右) 305

圖7-10  方法的內聚缺乏度:對於所有的HSQLDB類(左);

對應於不同LCOM值的Eclipse類的個數(右)     308

圖7-11  org.hsqldb包中的公有類和私有類     310

圖7-12  Tomcat中一個不穩定的包   311

圖7-13  Eclipse中一個穩定的包      311

圖7-14  Eclipse的離心耦合與向心耦合之間的關係      312

圖7-15  Eclipse包(左)和第三方包(右)的不穩定性分佈      313

圖7-16  junit包的穩定依賴       313

圖7-17  MX4J包的不太穩定依賴    314

圖7-18  Eclipse包的不穩定性與抽象度分佈   315

圖7-19  Xerces與Eclipse間的迴圈依賴  316

圖7-20  所有的FreeBSD模組可維護性指數與模組大小的關係   329

圖7-21  65000個C函式的函式長度分佈 330

圖7-22  在處理使用者響應的過程中缺乏規則性       333

圖7-23  用於處理使用者響應的一個規則的控制結構       333

圖7-24  在同一程式碼段裡不同的break和continue範圍  334

圖7-25  ed的DES CBC實現中的公共耦合    345

圖7-26  ed的DES CBC實現中的公共耦合關係    346

圖7-27  在NetBSD核心中讀取並使用磁碟分割槽核心    349

圖7-28  低頻寬X(LBX)擴充套件中增量快取的設計       359

圖7-29  低頻寬X(LBX)擴充套件中增量快取的實現       360

圖7-30  servlet容器各元素間不必要的關係    370

圖7-31  使用責任鏈設計模式來分離類   370

圖7-32  兩個不同的Catalina檔案的公共程式碼行    374

圖7-33  難以修改的格式化註釋(左)與便於修改的格式化註釋(右)   377

圖7-34  在最內部的程式碼塊中宣告變數   378

圖7-35  第7版UNIX中直接解釋目錄的資料       383

圖7-36  Java 1.5之前的程式碼使用鬆散型別     384

圖7-37  C庫fomd實現中的特別單元測試     392

圖7-38  JUnit測試框架中的單元測試     393

圖7-39  Perl原始碼測試覆蓋度(左)和分支覆蓋度(右)

與測試用例執行數的關係    400

圖7-40  正規表示式引擎中斷言的使用   402

圖7-41  包含檔案依賴關係的簡化圖       409

圖7-42  文件依賴       411

 

圖8-1  二次方程消去誤差以及對精度的影響  440

圖8-2  計算遠離原點的三角形面積時的合併誤差  442

圖8-3  驗證浮點運算結果的程式碼     448

相關文章