code reading
++++++++++++
第一章: 導(dǎo)論
++++++++++++
1.要養(yǎng)成一個(gè)習(xí)慣, 經(jīng)常花時(shí)間閱讀別人編寫的高品質(zhì)代碼.
2.要有選擇地閱讀代碼, 同時(shí), 還要有自己的目標(biāo). 您是想學(xué)習(xí)新的模式|編碼風(fēng)格|還是滿足某些需求的方法.
3.要注意并重視代碼中特殊的非功能性需求, 這些需求也許會(huì)導(dǎo)致特殊的實(shí)現(xiàn)風(fēng)格.
4.在現(xiàn)有的代碼上工作時(shí), 請(qǐng)與作者和維護(hù)人員進(jìn)行必要的協(xié)調(diào), 以避免重復(fù)勞動(dòng)或產(chǎn)生厭惡情緒.
5.請(qǐng)將從開放源碼軟件中得到的益處看作是一項(xiàng)貸款, 盡可能地尋找各種方式來(lái)回報(bào)開放源碼社團(tuán).
6.多數(shù)情況下, 如果您想要了解"別人會(huì)如何完成這個(gè)功能呢?", 除了閱讀代碼以外, 沒有更好的方法.
7.在尋找bug時(shí), 請(qǐng)從問題的表現(xiàn)形式到問題的根源來(lái)分析代碼. 不要沿著不相關(guān)的路徑(誤入歧途).
8.我們要充分利用調(diào)試器|編譯器給出的警告或輸出的符號(hào)代碼|系統(tǒng)調(diào)用跟蹤器|數(shù)據(jù)庫(kù)結(jié)構(gòu)化查詢語(yǔ)言的日志機(jī)制|包轉(zhuǎn)儲(chǔ)工具和Windows的消
息偵查程序, 定出的bug的位置.
9.對(duì)于那些大型且組織良好的系統(tǒng), 您只需要最低限度地了解它的全部功能, 就能夠?qū)λ龀鲂薷?
10.當(dāng)向系統(tǒng)中增加新功能時(shí), 首先的任務(wù)就是找到實(shí)現(xiàn)類似特性的代碼, 將它作為待實(shí)現(xiàn)功能的模板.
11.從特性的功能描述到代碼的實(shí)現(xiàn), 可以按照字符串消息, 或使用關(guān)鍵詞來(lái)搜索代碼.
12.在移植代碼或修改接口時(shí), 您可以通過編譯器直接定位出問題涉及的范圍, 從而減少代碼閱讀的工作量.
13.進(jìn)行重構(gòu)時(shí), 您從一個(gè)能夠正常工作的系統(tǒng)開始做起, 希望確保結(jié)束時(shí)系統(tǒng)能夠正常工作. 一套恰當(dāng)?shù)臏y(cè)試用例(test case)可以幫助您滿
足此項(xiàng)約束.
14.閱讀代碼尋找重構(gòu)機(jī)會(huì)時(shí), 先從系統(tǒng)的構(gòu)架開始, 然后逐步細(xì)化, 能夠獲得最大的效益.
15.代碼的可重用性是一個(gè)很誘人, 但難以理解與分離, 可以試著尋找粒度更大一些的包, 甚至其他代碼.
16.在復(fù)查軟件系統(tǒng)時(shí), 要注意, 系統(tǒng)是由很多部分組成的, 不僅僅只是執(zhí)行語(yǔ)句. 還要注意分析以下內(nèi)容: 文件和目錄結(jié)構(gòu)|生成和配置過程|
用戶界面和系統(tǒng)的文檔.
18.可以將軟件復(fù)查作為一個(gè)學(xué)習(xí)|講授|援之以手和接受幫助的機(jī)會(huì).
&<60;&<60; &<60;
++++++++++++++++++++
第二章: 基本編程元素
++++++++++++++++++++
19.第一次分析一個(gè)程序時(shí), main是一個(gè)好的起始點(diǎn).
20.層疊if-else if-...-else序列可以看作是由互斥選擇項(xiàng)組成的選擇結(jié)構(gòu).
21.有時(shí), 要想了解程序在某一方面的功能, 運(yùn)行它可能比閱讀源代碼更為恰當(dāng).
22.在分析重要的程序時(shí), 最好首先識(shí)別出重要的組成部分.
23.了解局部的命名約定, 利用它們來(lái)猜測(cè)變量和函數(shù)的功能用途.
24.當(dāng)基于猜測(cè)修改代碼時(shí), 您應(yīng)該設(shè)計(jì)能夠驗(yàn)證最初假設(shè)的過程. 這個(gè)過程可能包括用編譯器進(jìn)行檢查|引入斷言|或者執(zhí)行適當(dāng)?shù)臏y(cè)試用例.
25.理解了代碼的某一部分, 可能幫助你理解余下的代碼.
26.解決困難的代碼要從容易的部分入手.
27.要養(yǎng)成遇到庫(kù)元素就去閱讀相關(guān)文檔的習(xí)慣; 這將會(huì)增強(qiáng)您閱讀和編寫代碼的能力.
28.代碼閱讀有許多可選擇的策略: 自底向上和自頂向下的分析|應(yīng)用試探法和檢查注釋和外部文檔, 應(yīng)該依據(jù)問題的需要嘗試所有這些方法.
29.for (i=0; i<n; i++)形式的循環(huán)執(zhí)行n次; 其他任何形式都要小心.
30.涉及兩項(xiàng)不等測(cè)試(其中一項(xiàng)包括相等條件)的比較表達(dá)式可以看作是區(qū)間成員測(cè)試.
31.我們經(jīng)常可以將表達(dá)式應(yīng)用在樣本數(shù)據(jù)上, 借以了解它的含義.
32.使用De Morgan法則簡(jiǎn)化復(fù)雜的邏輯表達(dá)式.
33.在閱讀邏輯乘表達(dá)式時(shí), 問題可以認(rèn)為正在分析的表達(dá)式以左的表達(dá)式均為true; 在閱讀邏輯和表達(dá)式時(shí), 類似地, 可以認(rèn)為正在分析的表
達(dá)式以左的表達(dá)式均為false.
34.重新組織您控制的代碼, 使之更為易讀.
35.將使用條件運(yùn)行符? :的表達(dá)式理解為if代碼.
36.不需要為了效率, 犧牲代碼的易讀性.
37.高效的算法和特殊的優(yōu)化確實(shí)有可能使得代碼更為復(fù)雜, 從而更難理解, 但這并不意味著使代碼更為緊湊和不易讀會(huì)提高它的效率.
38.創(chuàng)造性的代碼布局可以用來(lái)提高代碼的易讀性.
39.我們可以使用空格|臨時(shí)變量和括號(hào)提高表達(dá)式的易讀性.
40.在閱讀您所控制的代碼時(shí), 要養(yǎng)成添加注釋的習(xí)慣.
41.我們可以用好的縮進(jìn)以及對(duì)變量名稱的明智選擇, 提高編寫欠佳的程序的易讀性.
42.用diff程序分析程序的修訂歷史時(shí), 如果這段歷史跨越了整體重新縮排, 常常可以通過指定-w選項(xiàng), 讓diff忽略空白差異, 避免由于更改了
縮進(jìn)層次而引入的噪音.
43.do循環(huán)的循環(huán)體至少執(zhí)行一次.
44.執(zhí)行算術(shù)運(yùn)算時(shí), 當(dāng)b=2n-1時(shí), 可以將a&b理解為a%(b+1).
45.將a<<n理解為a*k, k=2n.
46.將a>>n理解為a/k, k=2n.
47.每次只分析一個(gè)控制結(jié)構(gòu), 將它的內(nèi)容看作是一個(gè)黑盒.
48.將每個(gè)控制結(jié)構(gòu)的控制表達(dá)式看作是它所包含代碼的斷言.
49.return, goto, break和continue語(yǔ)句, 還有異常, 都會(huì)影響結(jié)構(gòu)化的執(zhí)行流程. 由于這些語(yǔ)句一般都會(huì)終止或重新開始正在進(jìn)行的循環(huán),
因此要單獨(dú)推理它們的行為.
50.用復(fù)雜循環(huán)的變式和不變式, 對(duì)循環(huán)進(jìn)行推理.
51.使用保持含義不變的變換重新安排代碼, 簡(jiǎn)化代碼的推理工作.
+++++++++++++++++++
第三章: 高級(jí)C數(shù)據(jù)類型
+++++++++++++++++++
52.了解特定語(yǔ)言構(gòu)造所服務(wù)的功能之后, 就能夠更好地理解使用它們的代碼.
53.識(shí)別并歸類使用指針的理由.
54.在C程序中, 指針一般用來(lái)構(gòu)造鏈?zhǔn)綌?shù)據(jù)結(jié)構(gòu)|動(dòng)態(tài)分配的數(shù)據(jù)結(jié)構(gòu)|實(shí)現(xiàn)引用調(diào)用|訪問和迭代數(shù)據(jù)元素|傳遞數(shù)組參數(shù)|引用函數(shù)|作為其他
值的別名|代表字符串|以及直接訪問系統(tǒng)內(nèi)存.
55.以引用傳遞的參數(shù)可以用來(lái)返回函數(shù)的結(jié)果, 或者避免參數(shù)復(fù)制帶來(lái)的開銷.
56.指向數(shù)組元素地址的指針, 可以訪問位于特定索引位置的元素.
57.指向數(shù)組元素的指針和相應(yīng)的數(shù)組索引, 作用在二者上的運(yùn)算具有相同的語(yǔ)義.
58.使用全局或static局部變量的函數(shù)大多數(shù)情況都不可重入(reentrant).
59.字符指針不同于字符數(shù)組.
60.識(shí)別和歸類應(yīng)用結(jié)構(gòu)或共用體的每種理由.
61.C語(yǔ)言中的結(jié)構(gòu)將多個(gè)數(shù)據(jù)元素集合在一起, 使得它們可以作為一個(gè)整體來(lái)使用, 用來(lái)從函數(shù)中返回多個(gè)數(shù)據(jù)元素|構(gòu)造鏈?zhǔn)綌?shù)據(jù)結(jié)構(gòu)|映射
數(shù)據(jù)在硬件設(shè)備|網(wǎng)絡(luò)鏈接和存儲(chǔ)介質(zhì)上的組織方式|實(shí)現(xiàn)抽象數(shù)據(jù)類型|以及以面向?qū)ο蟮姆绞骄幊?
62.共用體在C程序中主要用于優(yōu)化存儲(chǔ)空間的利用|實(shí)現(xiàn)多態(tài)|以及訪問數(shù)據(jù)不同的內(nèi)部表達(dá)方式.
63.一個(gè)指針, 在初始化為指向N個(gè)元素的存儲(chǔ)空間之后, 就可以作為N個(gè)元素的數(shù)組來(lái)使用.
64.動(dòng)態(tài)分配的內(nèi)在塊可以電焊工地釋放, 或在程序結(jié)束時(shí)釋放, 或由垃圾回收器來(lái)完成回收; 在棧上分配的內(nèi)存塊當(dāng)分配它的函數(shù)退出后釋放
.
65.C程序使用typedef聲明促進(jìn)抽象, 并增強(qiáng)代碼的易讀性, 從而防范可移植性問題, 并模擬C++和Java的類聲明行為.
66.可以將typedef聲明理解成變量定義: 變量的名稱就是類型的名稱; 變量的類型就是與該名稱對(duì)應(yīng)的類型.
&<60;&<60;&<60;
&<60;
+++++++++++++++
第四章: C數(shù)據(jù)結(jié)構(gòu)
+++++++++++++++
67.根據(jù)底層的抽象數(shù)據(jù)類型理解顯式的數(shù)據(jù)結(jié)構(gòu)操作.
68.C語(yǔ)言中, 一般使用內(nèi)建的數(shù)組類型實(shí)現(xiàn)向量, 不再對(duì)底層實(shí)現(xiàn)進(jìn)行抽象.
69.N個(gè)元素的數(shù)組可以被序列for (i=0; i<N; i++)完全處理; 所有其他變體都應(yīng)該引起警惕.
70.表達(dá)式sizeof(x)總會(huì)得到用memset或memcpy處理數(shù)組x(不是指針)所需的正確字節(jié)數(shù).
71.區(qū)間一般用區(qū)間內(nèi)的第一個(gè)元素和區(qū)間后的第一個(gè)元素來(lái)表示.
72.不對(duì)稱區(qū)間中元素的數(shù)目等于高位邊界與低位邊界的差.
73.當(dāng)不對(duì)稱區(qū)間的高位邊界等于低位邊界時(shí), 區(qū)間為空.
74.不對(duì)稱區(qū)間中的低位邊界代表區(qū)間的第一個(gè)元素; 高位邊界代表區(qū)間外的第一個(gè)元素.
75.結(jié)構(gòu)的數(shù)組常常表示由記錄和字段組成的表.
76.指向結(jié)構(gòu)的指針常常表示訪問底層記錄和字段的游標(biāo).
77.動(dòng)態(tài)分配的矩陣一般存儲(chǔ)為指向數(shù)組列的指針或指向元素指針的指針; 這兩種類型都可以按照二維數(shù)組進(jìn)行訪問.
78.以數(shù)組形式存儲(chǔ)的動(dòng)態(tài)分配矩陣, 用自定義訪問函數(shù)定位它們的元素.
79.抽象數(shù)據(jù)類型為底層實(shí)現(xiàn)元素的使用(或誤用)方式提供一種信心的量度.
80.數(shù)組用從0開始的順序整數(shù)為鍵, 組織查找表.
81.數(shù)組經(jīng)常用來(lái)對(duì)控制結(jié)構(gòu)進(jìn)行高效編碼, 簡(jiǎn)化程序的邏輯.
82.通過在數(shù)組中每個(gè)位置存儲(chǔ)一個(gè)數(shù)據(jù)元素和一個(gè)函數(shù)指針(指向處理數(shù)據(jù)元素的函數(shù)), 可以將代碼與數(shù)據(jù)關(guān)聯(lián)起來(lái).
83.數(shù)組可以通過存儲(chǔ)供程序內(nèi)的抽象機(jī)(abstract machine)或虛擬機(jī)(virtual machine)使用的數(shù)據(jù)或代碼, 控制程序的運(yùn)作.
84.可以將表達(dá)式sizeof(x) / sizeof(x[0])理解為數(shù)組x中元素的個(gè)數(shù).
85.如果結(jié)構(gòu)中含有指向結(jié)構(gòu)自身|名為next的元素, 一般說來(lái), 該結(jié)構(gòu)定義的是單向鏈表的結(jié)點(diǎn).
86.指向鏈表結(jié)點(diǎn)的持久性(如全局|靜態(tài)或在堆上分配)指針常常表示鏈表的頭部.
87.包含指向自身的next和prev指針的結(jié)構(gòu)可能是雙向鏈表的結(jié)點(diǎn).
88.理解復(fù)雜數(shù)據(jù)結(jié)構(gòu)的指針操作可以將數(shù)據(jù)元素畫為方框|指針畫為箭頭.
89.遞歸數(shù)據(jù)結(jié)構(gòu)經(jīng)常用遞歸算法來(lái)處理.
90.重要的數(shù)據(jù)結(jié)構(gòu)操作算法一般用函數(shù)參數(shù)或模板參數(shù)來(lái)參數(shù)化.
91.圖的結(jié)點(diǎn)常常順序地存儲(chǔ)在數(shù)組中, 鏈接到鏈表中, 或通過圖的邊鏈接起來(lái).
92.圖中的邊一般不是隱式地通過指針, 就是顯式地作為獨(dú)立的結(jié)構(gòu)來(lái)表示.
93.圖的邊經(jīng)常存儲(chǔ)為動(dòng)態(tài)分配的數(shù)組或鏈表, 在這兩種情況下, 邊都錨定在圖的結(jié)點(diǎn)上.
94.在無(wú)向圖中, 表達(dá)數(shù)據(jù)時(shí)應(yīng)該將所有的結(jié)點(diǎn)看作是等同的, 類似地, 進(jìn)行處理任務(wù)的代碼也不應(yīng)該基于它們的方向來(lái)區(qū)分邊.
95.在非連通圖中, 執(zhí)行遍歷代碼應(yīng)該能夠接通孤立的子圖.
96.處理包含回路的圖時(shí), 遍歷代碼應(yīng)該避免在處理圖的回路進(jìn)入循環(huán).
97.復(fù)雜的圖結(jié)構(gòu)中, 可能隱藏著其他類型的獨(dú)立結(jié)構(gòu).
+++++++++++++++++
第五章: 高級(jí)控制流程
+++++++++++++++++
98.采用遞歸定義的算法和數(shù)據(jù)結(jié)構(gòu)經(jīng)常用遞歸的函數(shù)定義來(lái)實(shí)現(xiàn).
99.推理遞歸函數(shù)時(shí), 要從基準(zhǔn)落伍測(cè)試開始, 并認(rèn)證每次遞歸調(diào)用如何逐漸接近非遞歸基準(zhǔn)范例代碼.
100.簡(jiǎn)單的語(yǔ)言常常使用一系列遵循該語(yǔ)言語(yǔ)法結(jié)構(gòu)的函數(shù)進(jìn)行語(yǔ)法分析.
101.推理互遞歸函數(shù)時(shí), 要基于底層概念的遞歸定義.
102.尾遞歸調(diào)用等同于一個(gè)回到函數(shù)開始處的循環(huán).
103.將throws子句從方法的定義中移除, 然后運(yùn)行Java編譯器對(duì)類的源代碼進(jìn)行編譯, 就可以容易地找到那些可能隱式地生成異常的方法.
104.在多處理器計(jì)算機(jī)上運(yùn)行的代碼常常圍繞進(jìn)程或線程進(jìn)行組織.
105.工作群并行模型用于在多個(gè)處理器間分配工作, 或者創(chuàng)建一個(gè)任務(wù)池, 然后將大量需要處理標(biāo)準(zhǔn)化的工作進(jìn)行分配.
106.基于線程的管理者/工人并行模型一般將耗時(shí)的或阻塞的操作分配給工人子任務(wù), 從而維護(hù)中心任務(wù)的響應(yīng)性.
107.基于進(jìn)程的管理者/工人并行模型一般用來(lái)重用現(xiàn)有的程序, 或用定義良好的接口組織和分離粗粒度的系統(tǒng)模塊.
108.基于流水線的并行處理中, 每個(gè)任務(wù)都接收到一些輸入, 對(duì)它們進(jìn)行一些處理, 并將生成的輸出傳遞給下一個(gè)任務(wù), 進(jìn)行不同的處理.
109.競(jìng)爭(zhēng)條件很難捉摸, 相關(guān)的代碼常常會(huì)將競(jìng)爭(zhēng)條件擴(kuò)散到多個(gè)函數(shù)或模塊; 因而, 很難隔離由于競(jìng)爭(zhēng)條件導(dǎo)致的問題.
110.對(duì)于出現(xiàn)在信號(hào)處理器中的數(shù)據(jù)結(jié)構(gòu)操作代碼和庫(kù)調(diào)用要保持高度警惕.
111.在閱讀包含宏的代碼時(shí), 要注意, 宏既非函數(shù), 也非語(yǔ)句.
112.do…while(0)塊中的宏等同于控制塊中的語(yǔ)句.
113.宏可以訪問在它的使用點(diǎn)可見的所有局部變量.
114.宏調(diào)用可改變參數(shù)的值
115.基于宏的標(biāo)記拼接能夠創(chuàng)建新的標(biāo)記符.
&<60;&<60;&<60;
+++++++++++++++++
第六章: 應(yīng)對(duì)大型項(xiàng)目
+++++++++++++++++
116.我們可以通過瀏覽項(xiàng)目的源代碼樹—包含項(xiàng)目源代碼的層次目錄結(jié)構(gòu), 來(lái)分析一個(gè)項(xiàng)目的組織方式. 源碼樹常常能夠反映出項(xiàng)目在構(gòu)架和
軟件過程上的結(jié)構(gòu).
117.應(yīng)用程序的源代碼樹經(jīng)常是該應(yīng)用程序的部署結(jié)構(gòu)的鏡像.
118.不要被龐大的源代碼集合嚇倒; 它們一般比小型的專門項(xiàng)目組織得更出色.
119.當(dāng)您首次接觸一個(gè)大型項(xiàng)目時(shí), 要花一些時(shí)間來(lái)熟悉項(xiàng)目的目錄樹結(jié)構(gòu).
120.項(xiàng)目的源代碼遠(yuǎn)不只是編譯后可以獲得可執(zhí)行程序的計(jì)算機(jī)語(yǔ)言指令; 一個(gè)項(xiàng)目的源碼樹一般還包括規(guī)格說明|最終用戶和開發(fā)人員文檔|
測(cè)試腳本|多媒體資源|編譯工具|例子|本地化文件|修訂歷史|安裝過程和許可信息.
121.大型項(xiàng)目的編譯過程一般聲明性地借助依賴關(guān)系來(lái)說明. 依賴關(guān)系由工具程序, 如make及其派生程序, 轉(zhuǎn)換成具體的編譯行動(dòng).
122.大型項(xiàng)目中, 制作文件常常由配置步驟動(dòng)態(tài)地生成; 在分析制作文件之前, 需要先執(zhí)行項(xiàng)目特定的配置.
123.檢查大型編譯過程的各個(gè)步驟時(shí), 可以使用make程序的-n開關(guān)進(jìn)行預(yù)演.
124.修訂控制系統(tǒng)提供從儲(chǔ)存庫(kù)中獲取源代碼最新版本的方式.
125.可以使用相關(guān)的命令, 顯示可執(zhí)行文件中的修訂標(biāo)識(shí)關(guān)鍵字, 從而將可執(zhí)行文件與它的源代碼匹配起來(lái).
126.使用修訂日志中出現(xiàn)的bug跟蹤系統(tǒng)內(nèi)的編號(hào), 可以在bug跟蹤系統(tǒng)的數(shù)據(jù)庫(kù)中找到有關(guān)的問題的說明.
127.可以使用修訂控制系統(tǒng)的版本儲(chǔ)存庫(kù), 找出特定的變更是如何實(shí)現(xiàn)的.
128.定制編譯工具用在軟件開發(fā)過程的許多方面, 包括配置|編譯過程管理|代碼的生成|測(cè)試和文檔編制.
129.程序的調(diào)試輸出可以幫助我們理解程序控制流程和數(shù)據(jù)元素的關(guān)鍵部分.
130.跟蹤語(yǔ)句所在的地點(diǎn)一般也是算法運(yùn)行的重要部分.
131.可以用斷言來(lái)檢驗(yàn)算法運(yùn)作的步驟|函數(shù)接收的參數(shù)|程序的控制流程|底層硬件的屬性和測(cè)試用例的結(jié)果.
132.可以使用對(duì)算法進(jìn)行檢驗(yàn)的斷言來(lái)證實(shí)您對(duì)算法運(yùn)作的理解, 或?qū)⑺鳛橥评淼钠瘘c(diǎn).
133.對(duì)函數(shù)參數(shù)和結(jié)果的斷言經(jīng)常記錄了函數(shù)的前置條件和后置條件.
134.我們可以將測(cè)試整個(gè)函數(shù)的斷言作為每個(gè)給定函數(shù)的規(guī)格說明.
135.測(cè)試用例可以部分地代替函數(shù)規(guī)格說明.
136.可以使用測(cè)試用例的輸入數(shù)據(jù)對(duì)源代碼序列進(jìn)行預(yù)演.
+++++++++++++++++++
第七章: 編碼規(guī)范和約定
+++++++++++++++++++
137.了解了給定代碼庫(kù)所遵循的文件組織方式后, 就能更有效率地瀏覽它的源代碼.
138.閱讀代碼時(shí), 首先要確保您的編輯器或優(yōu)美打印程序的tab設(shè)置, 與代碼遵循的風(fēng)格規(guī)范一致.
139.可以使用代碼塊的縮進(jìn), 快速地掌握代碼的總體結(jié)構(gòu).
140.對(duì)編排不一致的代碼, 應(yīng)該立即給予足夠的警惕.
141.分析代碼時(shí), 對(duì)標(biāo)記為XXX, FIXME和TODO的代碼序列要格外注意: 錯(cuò)誤可能就潛伏在其中.
142.常量使用大寫字母命名, 單詞用下劃線分隔.
143.在遵循Java編碼規(guī)范的程序中, 包名(package name)總是從一個(gè)頂級(jí)的域名開始(例如, org, com), 類名和接口名由大寫字母開始, 方法
和變量名由小寫字母開始.
144.用戶界面控件名稱之前的匈牙利記法的前綴類型標(biāo)記可以幫助我們確定它的作用.
145.不同的編程規(guī)范對(duì)可移植構(gòu)造的構(gòu)成有不同的主張.
146.在審查代碼的可移植性, 或以某種給定的編碼規(guī)范作為指南時(shí), 要注意了解規(guī)范對(duì)可移植性需求的界定與限制.
147.如果GUI功能都使用相應(yīng)的編程結(jié)構(gòu)來(lái)實(shí)現(xiàn), 則通過代碼審查可以輕易地驗(yàn)證給定用戶界面的規(guī)格說明是否被正確地采用.
148.了解項(xiàng)目編譯過程的組織方式與自動(dòng)化方式之后, 我們就能夠快速地閱讀與理解對(duì)應(yīng)的編譯規(guī)則.
149.當(dāng)檢查系統(tǒng)的發(fā)布過程時(shí), 常常可以將相應(yīng)發(fā)行格式的需求作為基準(zhǔn).
&<60;
&<60;
++++++++++++
第八章: 文檔
++++++++++++
150.閱讀代碼時(shí), 應(yīng)該盡可能地利用任何能夠得到的文檔.
151.閱讀一小時(shí)代碼所得到的信息只不過相當(dāng)于閱讀一分鐘文檔.
152.使用系統(tǒng)的規(guī)格說明文檔, 了解所閱讀代碼的運(yùn)行環(huán)境.
153.軟件需求規(guī)格說明是閱讀和評(píng)估代碼的基準(zhǔn).
154.可以將系統(tǒng)的設(shè)計(jì)規(guī)格說明作為認(rèn)知代碼結(jié)構(gòu)的路線圖, 閱讀具體代碼的指引.
155.測(cè)試規(guī)格說明文檔為我們提供可以用來(lái)對(duì)代碼進(jìn)行預(yù)演的數(shù)據(jù).
156.在接觸一個(gè)未知系統(tǒng)時(shí), 功能性的描述和用戶指南可以提供重要的背景信息,從而更好地理解閱讀的代碼所處的上下文.
157.從用戶參考手冊(cè)中, 我們可以快速地獲取, 應(yīng)用程序在外觀與邏輯上的背景知識(shí), 從管理員手冊(cè)中可以得知代碼的接口|文件格式和錯(cuò)誤消
息的詳細(xì)信息.
158.利用文檔可以快捷地獲取系統(tǒng)的概況, 了解提供特定特性的代碼.
159.文檔經(jīng)常能夠反映和提示出系統(tǒng)的底層結(jié)構(gòu).
160.文檔有助于理解復(fù)雜的算法和數(shù)據(jù)結(jié)構(gòu).
161.算法的文字描述能夠使不透明(晦澀, 難以理解)的代碼變得可以理解.
162.文檔常常能夠闡明源代碼中標(biāo)識(shí)符的含義.
163.文檔能夠提供非功能性需求背后的理論基礎(chǔ).
164.文檔還會(huì)說明內(nèi)部編程接口.
165.由于文檔很少像實(shí)際的程序代碼那樣進(jìn)行測(cè)試, 并受人關(guān)注, 所以它常常可能存在錯(cuò)誤|不完整或過時(shí).
166.文檔也提供測(cè)試用例, 以及實(shí)際應(yīng)用的例子.
167.文檔常常還會(huì)包括已知的實(shí)現(xiàn)問題或bug.
168.環(huán)境中已知的缺點(diǎn)一般都會(huì)記錄在源代碼中.
169.文檔的變更能夠標(biāo)出那些故障點(diǎn).
170.對(duì)同一段源代碼重復(fù)或互相沖突的更改, 常常表示存在根本性的設(shè)計(jì)缺陷, 從而使得維護(hù)人員需要用一系列的修補(bǔ)程序來(lái)修復(fù).
171.相似的修復(fù)應(yīng)用到源代碼的不同部分, 常常表示一種易犯的錯(cuò)誤或疏忽, 它們同樣可能會(huì)在其他地方存在.
172.文檔常常會(huì)提供不恰當(dāng)?shù)男畔? 誤導(dǎo)我們對(duì)源代碼的理解.
173.要警惕那些未歸檔的特性: 將每個(gè)實(shí)例歸類為合理|疏忽或有害, 相應(yīng)地決定是否應(yīng)該修復(fù)代碼或文檔.
174.有時(shí), 文檔在描述系統(tǒng)時(shí), 并非按照已完成的實(shí)現(xiàn), 而是系統(tǒng)應(yīng)該的樣子或?qū)?lái)的實(shí)現(xiàn).
175.在源代碼文檔中, 單詞gork的意思一般是指”理解”.
176.如果未知的或特殊用法的單詞阻礙了對(duì)代碼的理解, 可以試著在文檔的術(shù)語(yǔ)表(如果存在的話)|New Hacker’s Dictionary[Ray96]|或在
Web搜索引擎中查找它們.
177.總是要以批判的態(tài)度來(lái)看待文檔, 注意非傳統(tǒng)的來(lái)源, 比如注釋|標(biāo)準(zhǔn)|出版物|測(cè)試用例|郵件列表|新聞組|修訂日志|問題跟蹤數(shù)據(jù)庫(kù)|營(yíng)
銷材料|源代碼本身.
178.總是要以批判的態(tài)度來(lái)看待文檔; 由于文檔永遠(yuǎn)不會(huì)執(zhí)行, 對(duì)文檔的測(cè)試和正式復(fù)查也很少達(dá)到對(duì)代碼的同樣水平, 所以文檔常常會(huì)誤導(dǎo)
讀者, 或者完全錯(cuò)誤.
179.對(duì)于那些有缺陷的代碼, 我們可以從中推斷出它的真實(shí)意圖.
180.在閱讀大型系統(tǒng)的文檔時(shí), 首先要熟悉文檔的總體結(jié)構(gòu)和約定.
181.在對(duì)付體積龐大的文檔時(shí), 可以使用工具, 或?qū)⑽谋据敵龅礁咂焚|(zhì)輸出設(shè)備上, 比如激光打印機(jī), 來(lái)提高閱讀的效率.
++++++++++++++
第九章: 系統(tǒng)構(gòu)架
++++++++++++++
182.一個(gè)系統(tǒng)可以(在重大的系統(tǒng)中也確實(shí)如此)同時(shí)出多種不同的構(gòu)架類型. 以不同的方式檢查同一系統(tǒng)|分析系統(tǒng)的不同部分|或使用不同級(jí)
別的分解, 都有可能發(fā)現(xiàn)不同的構(gòu)架類型.
183.協(xié)同式的應(yīng)用程序, 或者需要協(xié)同訪問共享信息或資源的半自治進(jìn)程, 一般會(huì)采用集中式儲(chǔ)存庫(kù)構(gòu)架.
184.黑板系統(tǒng)使用集中式的儲(chǔ)存庫(kù), 存儲(chǔ)非結(jié)構(gòu)化的鍵/值對(duì), 作為大量不同代碼元件之間的通信集線器.
185.當(dāng)處理過程可以建模|設(shè)計(jì)和實(shí)現(xiàn)成一系列的數(shù)據(jù)變換時(shí), 常常會(huì)使用數(shù)據(jù)流(或管道—過濾器)構(gòu)架.
186.在批量進(jìn)行自動(dòng)數(shù)據(jù)處理的環(huán)境中, 經(jīng)常會(huì)采用數(shù)據(jù)流構(gòu)架, 在對(duì)數(shù)據(jù)工具提供大量支持的平臺(tái)上尤其如此.
187.數(shù)據(jù)流構(gòu)架的一個(gè)明顯征兆是: 程序中使用臨時(shí)文件或流水線(pipeline)在不同進(jìn)程間進(jìn)行通信.
188.使用圖示來(lái)建模面向?qū)ο髽?gòu)架中類的關(guān)系.
189.可以將源代碼輸入到建模工具中, 逆向推導(dǎo)出系統(tǒng)的構(gòu)架.
190.擁有大量同級(jí)子系統(tǒng)的系統(tǒng), 常常按照分層構(gòu)架進(jìn)行組織.
191.分層構(gòu)架一般通過堆疊擁有標(biāo)準(zhǔn)化接口的軟件組件來(lái)實(shí)現(xiàn).
192.系統(tǒng)中每個(gè)層可以將下面的層看作抽象實(shí)體, 并且(只要該層滿足它的需求說明)不關(guān)心上面的層如何使用它.
193.層的接口既可以是支持特定概念的互補(bǔ)函數(shù)族, 也可以是一系列支持同一抽象接口不同底層實(shí)現(xiàn)的可互換函數(shù).
194.用C語(yǔ)言實(shí)現(xiàn)的系統(tǒng), 常常用函數(shù)指針的數(shù)組, 表達(dá)層接口的多路復(fù)用操作.
195.用面向?qū)ο蟮恼Z(yǔ)言實(shí)現(xiàn)的系統(tǒng), 使用虛方法調(diào)用直接表達(dá)對(duì)層接口的多嘴復(fù)用操作.
196.系統(tǒng)可以使用不同的|獨(dú)特的層次分解模型跨各種坐標(biāo)軸進(jìn)行組織.
197.使用程序切片技術(shù), 可以將程序中的數(shù)據(jù)和控制之間依賴關(guān)系集中到一起.
198.在并發(fā)系統(tǒng)中, 一個(gè)單獨(dú)的系統(tǒng)組件起到集中式管理器的作用, 負(fù)責(zé)啟動(dòng)|停止和協(xié)調(diào)其他系統(tǒng)進(jìn)程和任務(wù)的執(zhí)行.
199.許多現(xiàn)實(shí)的系統(tǒng)都會(huì)博采眾家之長(zhǎng). 當(dāng)處理此類系統(tǒng)時(shí), 不要徒勞地尋找無(wú)所不包的構(gòu)架圖; 應(yīng)該將不同構(gòu)架風(fēng)格作為獨(dú)立但相關(guān)的實(shí)體
來(lái)進(jìn)行定位|識(shí)別并了解.
200.狀態(tài)變遷圖常常有助于理清狀態(tài)機(jī)的動(dòng)作.
201.在處理大量的代碼時(shí), 了解將代碼分解成單獨(dú)單元的機(jī)制極為重要.
202.大多數(shù)情況下, 模塊的物理邊界是單個(gè)文件|組織到一個(gè)目錄中的多個(gè)文件或擁有統(tǒng)一前綴的文件的集合.
203.C中的模塊, 由提供模塊公開接口的頭文件和提供對(duì)應(yīng)實(shí)現(xiàn)的源文件組成.
204.對(duì)象的構(gòu)造函數(shù)經(jīng)常用來(lái)分配與對(duì)象相關(guān)的資源, 并初始化對(duì)象的狀態(tài). 函數(shù)一般用來(lái)釋放對(duì)象在生命期中占用的資源.
205.對(duì)象方法經(jīng)常使用類字段來(lái)存儲(chǔ)控制所有方法運(yùn)作的數(shù)據(jù)(比如查找表或字典)或維護(hù)類運(yùn)作的狀態(tài)信息(例如, 賦給每個(gè)對(duì)象一個(gè)標(biāo)識(shí)符的
計(jì)數(shù)器).
206.在設(shè)計(jì)良好的類中, 所有的字段都應(yīng)在聲明為private, 并用公開的訪問方法提供對(duì)它們的訪問.
207.在遇到friend聲明時(shí), 要停下來(lái)分析一下, 看看繞過類封裝在設(shè)計(jì)上的理由.
208.可以有節(jié)制地用運(yùn)算符增強(qiáng)特定類的可用性, 但用運(yùn)算符重載, 將類實(shí)現(xiàn)為擁有內(nèi)建算術(shù)類型相關(guān)的全部功能的類實(shí)體, 是不恰當(dāng)?shù)?
209.泛型實(shí)現(xiàn)不是在編譯期間通過宏替換或語(yǔ)言所支持的功能(比如C++模板和Ada的泛型包)來(lái)實(shí)現(xiàn), 就是在運(yùn)行期間通過使用數(shù)據(jù)元素的指針
和函數(shù)的指針|或?qū)ο蟮亩鄳B(tài)性實(shí)現(xiàn).
210.抽象數(shù)據(jù)類型經(jīng)常用來(lái)封裝常用的數(shù)據(jù)組織方案(比如樹|列表或棧), 或者對(duì)用戶隱藏?cái)?shù)據(jù)類型的實(shí)現(xiàn)細(xì)節(jié).
211.使用庫(kù)的目的多種多樣: 重用源代碼或目標(biāo)代碼, 組織模塊集合, 組織和優(yōu)化編譯過程, 或是用來(lái)實(shí)現(xiàn)應(yīng)用程序各種特性的按需載入.
212.大型的|分布式的系統(tǒng)經(jīng)常實(shí)現(xiàn)為許多互相協(xié)作的進(jìn)程.
213.對(duì)于基于文本的數(shù)據(jù)儲(chǔ)存庫(kù), 可以通過瀏覽存儲(chǔ)在其中的數(shù)據(jù), 破譯出它的結(jié)構(gòu).
214.可以通過查詢數(shù)據(jù)字典中的表, 或使用數(shù)據(jù)庫(kù)專有的SQL命令, 比如show table, 來(lái)分析關(guān)系型數(shù)據(jù)庫(kù)的模式.
215.識(shí)別出重用的構(gòu)架元素后, 可以查找其最初的描述, 了解正確地使用這種構(gòu)架的方式, 以及可能出現(xiàn)的誤用.
216.要詳細(xì)分析建立在某種框架之上的應(yīng)用程序, 行動(dòng)的最佳路線就是從研究框架自身開始.
217.在閱讀向?qū)傻拇a時(shí), 不要期望太高, 否則您會(huì)感到失望.
218.學(xué)習(xí)幾個(gè)基本的設(shè)計(jì)模式之后, 您會(huì)發(fā)現(xiàn), 您查看代碼構(gòu)架的方式會(huì)發(fā)生改變: 您的視野和詞匯將會(huì)擴(kuò)展到能夠識(shí)別和描述許多通用的形
式.
219.頻繁使用的一些模式, 但并不顯式地指出它們的名稱, 這是由于構(gòu)架性設(shè)計(jì)的重用經(jīng)常先于模式的形成.
220.請(qǐng)?jiān)囍凑盏讓幽J絹?lái)理解構(gòu)架, 即使代碼中并沒有明確地提及模式.
221.大多數(shù)解釋器都遵循類似的處理構(gòu)架, 圍繞一個(gè)狀態(tài)機(jī)進(jìn)行構(gòu)建, 狀態(tài)機(jī)的操作依賴于解釋器的當(dāng)前狀態(tài)|程序指令和程序狀態(tài).
222.多數(shù)情況下, 參考構(gòu)架只是為應(yīng)用程序域指定一種概念性的結(jié)構(gòu), 具體的實(shí)現(xiàn)并非必須遵照這種結(jié)構(gòu).
+++++++++++++++++
第十章: 代碼閱讀工具
+++++++++++++++++
223.詞匯工具可以高效地在一個(gè)大代碼文件中或者跨多個(gè)文件查找某種模式.
224.使用程序編輯器和正則表達(dá)式查找命令, 瀏覽龐大的源代碼文件.
225.以只讀方式瀏覽源代碼文件.
226.使用正則表達(dá)式 ^function name 可以找出函數(shù)的定義.
227.使用正則表達(dá)式的字符類, 可以查找名稱遵循特定模式的變量.
228.使用正則表達(dá)式的否定字符類, 可以避免非積極匹配.
229.使用正則表達(dá)式 symbol-1. *symbol-2, 可以查找出現(xiàn)在同一行的符號(hào).
230.使用編輯器的 tags 功能, 可以快速地找出實(shí)體的定義.
231.可以用特定的 tag 創(chuàng)建工具, 增加編輯器的瀏覽功能.
232.使用編輯器的大綱視圖, 可以獲得源代碼結(jié)構(gòu)的鳥瞰圖.
233.使用您的編輯器來(lái)檢測(cè)源代碼中圓括號(hào)|方括號(hào)和花括號(hào)的匹配.
234.使用 grep 跨多個(gè)文件查找代碼模式.
235.使用 grep 定位符號(hào)的聲明|定義和應(yīng)用.
236.當(dāng)您不能精確地表述要查找的內(nèi)容時(shí), 請(qǐng)使用關(guān)鍵單詞的詞干對(duì)程序的源代碼進(jìn)行查找.
237.用 grep 過濾其他工具生成的輸出, 分離出您要查找的項(xiàng).
238.將 grep 的輸出輸送到其他工具, 使復(fù)雜處理任務(wù)自動(dòng)化.
239.通過對(duì) grep 的輸出進(jìn)行流編輯, 重用代碼查找的結(jié)果.
240.通過選取與噪音模式不匹配的輸出行(grep-v), 過濾虛假的 grep 輸出.
241.使用 fgrep 在源代碼中查找字符串列表.
242.查找注釋, 或標(biāo)識(shí)符大小寫不敏感的語(yǔ)言編寫的代碼時(shí), 要使用大小寫不敏感的模式匹配(grep -i).
243.使用 grep –n 命令行開關(guān), 可以創(chuàng)建與給定正則表達(dá)式匹配的文件和行號(hào)的檢查表.
244.可以使用 diff 比較文件或程序不同版本之間的差別.
245.在運(yùn)行 diff 命令時(shí), 可以使用 diff –b, 使文件比較算法忽略結(jié)尾的空格, 用 –w 忽略所有空白區(qū)域的差異, 用 –i 使文件比較對(duì)大
小寫不敏感.
246.不要對(duì)創(chuàng)建自己的代碼閱讀工具心存畏懼.
247.在構(gòu)建自己的代碼閱讀工具時(shí): 要充分利用現(xiàn)代快速原型語(yǔ)言所提供的能力; 從簡(jiǎn)單開始, 根據(jù)需要逐漸改進(jìn); 使用利用代碼詞匯結(jié)構(gòu)的
各種試探法; 要允許一些輸出噪音或寂靜(無(wú)關(guān)輸出或缺失輸出); 使用其他工具對(duì)輸入進(jìn)行預(yù)處理, 或者對(duì)輸出進(jìn)行后期處理.
248.要使編譯器成為您的: 指定恰當(dāng)級(jí)別的編譯器警告, 并小心地評(píng)估生成的結(jié)果.
249.使用C預(yù)處理器理清那些濫用預(yù)處理器特性的程序.
250.要徹底地了解編譯器如何處理特定的代碼塊, 需要查看生成的符號(hào)(匯編)代碼.
251.通過分析相應(yīng)目標(biāo)文件中的符號(hào), 可以清晰地了解源文件的輸入和輸出.
252.使用源代碼瀏覽器瀏覽大型的代碼集合以及對(duì)象類型.
253.要抵制住按照您的編碼規(guī)范對(duì)外部代碼進(jìn)行美化的誘惑; 不必要的編排更改會(huì)創(chuàng)建不同的代碼, 并妨礙工作的組織.
254.優(yōu)美打印程序和編輯器語(yǔ)法著色可以使得程序的源代碼為易讀.
255.cdecl 程序可以將難以理解的C和C++類型聲明轉(zhuǎn)換成純英語(yǔ)(反之亦然).
256.實(shí)際運(yùn)行程序, 往往可以更深刻地理解程序的動(dòng)作.
257.系統(tǒng)調(diào)用|事件和數(shù)據(jù)包跟蹤程序可以增進(jìn)對(duì)程序動(dòng)作的理解.
258.執(zhí)行剖析器可以找出需要著重優(yōu)化的代碼, 驗(yàn)證輸入數(shù)據(jù)的覆蓋性, 以及分析算法的動(dòng)作.
259.通過檢查從未執(zhí)行的代碼行, 可以找出測(cè)試覆蓋的弱點(diǎn), 并據(jù)此修正測(cè)試數(shù)據(jù).
260.要探究程序動(dòng)態(tài)動(dòng)作時(shí)的每個(gè)細(xì)節(jié), 需要在調(diào)試器中運(yùn)作它.
261.將您覺得難以理解的代碼打印到紙上.
262.可以繪制圖示來(lái)描繪代碼的動(dòng)作.
263.可以試著向別人介紹您在閱讀的代碼, 這樣做一般會(huì)增進(jìn)您對(duì)代碼的理解.
264.理解復(fù)雜的算法或巧妙的數(shù)據(jù)結(jié)構(gòu), 要選擇一個(gè)安靜的環(huán)境, 然后聚精會(huì)神地考慮, 不要借助于任何計(jì)算機(jī)化或自動(dòng)化的幫助.
+++++++++++++++++++++
第十一章: 一個(gè)完整的例子
+++++++++++++++++++++
265.模仿軟件的功能時(shí), 要依照相似實(shí)體的線路(類|函數(shù)|模塊). 在相似的現(xiàn)有實(shí)體中, 為簡(jiǎn)化對(duì)源代碼庫(kù)的文本查找, 應(yīng)選取比較罕見的名
稱.
266.自動(dòng)生成的文件常常會(huì)在文件的開關(guān)有一段注釋, 說明這種情況.
267.如果試圖精確地分析代碼, 一般會(huì)陷入數(shù)量眾多的類|文件和模塊中, 這些內(nèi)容會(huì)很快將我們淹沒; 因此, 我們必須將需要理解的代碼限定
在絕對(duì)必需的范圍之內(nèi).
268.采用一種廣度優(yōu)先查找策略, 從多方攻克代碼閱讀中存在的問題, 進(jìn)到找出克服它們的方法為止.
只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。 | ||
![]() |
||
網(wǎng)站導(dǎo)航:
博客園
IT新聞
Chat2DB
C++博客
博問
管理
|
||
相關(guān)文章:
|
||