一、整潔代碼
A.混亂的代價(jià)
1.有些團(tuán)隊(duì)在項(xiàng)目初期進(jìn)展迅速,但有那么一兩年的時(shí)間卻慢去蝸行。對(duì)代碼的每次修改都影響到其他兩三處代碼
2.花時(shí)間保持代碼整潔不但有關(guān)效率,還有關(guān)生存
3.程序員遵從不了解混亂風(fēng)險(xiǎn)經(jīng)理的意愿,也是不專業(yè)的做法
4.Bjarne Stroustrup,C++發(fā)明者:我喜歡優(yōu)雅和高效的代碼。代碼邏輯應(yīng)該直接了當(dāng),叫缺陷難以隱藏;盡量減少依賴關(guān)系,使之便于維護(hù);依據(jù)某種分層戰(zhàn)略完善錯(cuò)誤處理代碼;性能調(diào)至最優(yōu),省得引誘別人做沒規(guī)矩的優(yōu)化,搞出一堆混亂來。整潔的代碼只做好一件事。
5.Grady Booch,《面向分析與設(shè)計(jì)》:整潔的代碼簡單直接。整潔的代碼如同優(yōu)美的散文。整潔的代碼從不隱藏設(shè)計(jì)者的意圖,充滿了干凈利落的抽象和直接了當(dāng)?shù)目刂普Z句。
6.Dave Thomas,OTI公司創(chuàng)始人:整潔的代碼應(yīng)可由作者之外的開發(fā)者閱讀和增補(bǔ)。它應(yīng)有單元測試和驗(yàn)收測試。它使用有意義的命名。它只提供一種而非多種做一件事的途徑。它只有盡量少的依賴關(guān)系,而且要明確地定義和提供清晰、盡量少的API。代碼應(yīng)通過其字面表達(dá)含義,因?yàn)椴煌恼Z言導(dǎo)致并非所有必須信息均可通過代碼自身清晰表達(dá)。
7.Michael Feathers,《修改代碼的藝術(shù)》:我可以列出我留意到的整潔代碼的所有特點(diǎn),但其中有一條是根本性的。整潔的代碼總是看起來像是某位特別在意它的人寫的。幾乎沒有改進(jìn)的余地。代碼作者什么都想到了,如果你企圖改進(jìn)它,總會(huì)回到原點(diǎn),贊嘆某人留給你的代碼——全心投入的某人留下的代碼。
8.Ron Jeffries,《極限編程實(shí)施》:簡單代碼,依其重要順序:能通過所有測試;沒有重復(fù)代碼;體現(xiàn)系統(tǒng)中的全部設(shè)計(jì)理念;包括盡量少的實(shí)體,比如類、方法、函數(shù)等
9.Ward Cunningham,Wiki發(fā)明者:如果每個(gè)例程都讓你感到深合已意,那就是整潔代碼。如果代碼讓編程語言看起來像是專為解決那個(gè)問題而存在,就可以稱之為漂亮的代碼。
B.思想流派
1.讀與寫花費(fèi)時(shí)間的比例起過10:1
C.童子軍軍規(guī)
1.“讓營地比你來時(shí)更干凈”
2.如果每次簽入時(shí),代碼都比簽出時(shí)干凈,那么代碼就不會(huì)腐壞
二、有意義的命名
A.名副其實(shí)
1.變量、函數(shù)或類的名稱應(yīng)該已經(jīng)答復(fù)了所有的大問題,如果名稱需要注釋來補(bǔ)充,那就不算名副其實(shí)
2.代碼的模糊度:即上下文在代碼中未被明確體現(xiàn)的程度
B.避免誤導(dǎo)
1.程序員必須避免留下掩藏代碼本意的錯(cuò)誤線索。應(yīng)當(dāng)避免使用與本意相悖的詞
2.以同樣的方式拼寫出同樣的概念才是信息,拼寫前后不一致就是誤導(dǎo)
3.要注意使用小寫字母i和大寫字母O作為變量名,看起來像“壹”和“零”
C.做有意義的區(qū)分
1.同一作用范圍內(nèi)兩樣不同的東西不能重名,如果名稱必須相異,那其意思也應(yīng)該不同才對(duì)
2.廢話是另一種沒意義的區(qū)分。假設(shè)你有一個(gè)Product類,如果還有一個(gè)ProductInfo或ProductData類,那它們的名稱雖然不同,意思卻無區(qū)別
3.只要體現(xiàn)出有意義的區(qū)分,使用a和the這樣的前綴就沒錯(cuò)
4.廢話都是冗余。Variable一詞記錄不應(yīng)當(dāng)出現(xiàn)在變量名中,Table一詞永遠(yuǎn)不應(yīng)當(dāng)出現(xiàn)在表名中
D.使用讀得出來的名稱
E.使用可搜索的名稱
1.單字母名稱和數(shù)字常量有個(gè)問題,就是很難在一大篇文字中找出來
F.避免使用編碼
1.把類型或作用域編進(jìn)名稱里面,徒然增加了解碼的負(fù)擔(dān)
2.也不必用m_前綴來標(biāo)明成員變量,應(yīng)當(dāng)把類和函數(shù)做得足夠小,消除對(duì)成員前綴的需要
3.不加修飾的接口,不要用前導(dǎo)字母I
G.避免思維映射
1.不應(yīng)當(dāng)讓讀者在腦中把你的名稱翻譯為他們熟知的名稱,單字母變量名就是個(gè)問題
2.專業(yè)程序員了解,明確是王道
H.類名
1.類名和對(duì)象名應(yīng)該是名詞或名詞短語,類名不應(yīng)當(dāng)是動(dòng)詞
I.方法名
1.方法名應(yīng)該是動(dòng)詞或動(dòng)詞短語。屬性訪問器、修改器和斷言應(yīng)該根據(jù)其值命名,并依Javabean標(biāo)準(zhǔn)加上get、set和is前綴
2.可以考慮將相應(yīng)構(gòu)造器設(shè)置為private,強(qiáng)制使用這種命名手段
J.別扮可愛
1.言到意到,意到言到
K.別用雙關(guān)語
1.避免將同一單詞用于不同目的
2.應(yīng)盡力寫出易于理解的代碼,把代碼寫得讓別人能一目盡覽而不必殫精竭慮地研究
L.使用解決方案領(lǐng)域名稱
1.盡管用那些計(jì)算機(jī)科學(xué)術(shù)語、算法名、模式名、數(shù)學(xué)術(shù)語
M.使用源自所涉問題領(lǐng)域的名稱
1.如果不能用程序員熟悉的術(shù)語來給手頭的工作命名,就采用從所涉問題領(lǐng)域而來的名稱
2.優(yōu)秀的程序員和設(shè)計(jì)師,其工作之一就是分離解決方案領(lǐng)域和問題領(lǐng)域的概念
N.添加有意義的語境
1.你需要用有良好命名的類、函數(shù)或名稱空間來放置名稱,給讀者提供語境
2.如果沒這么做,給名稱添加前綴就是最后一招了
O.不要添加沒用的語境
1.只要短名稱足夠清楚,就要比長名稱好
P.最后的話
1.取好名字最難的地方在于需要良好的描述技巧和共有文化背景
三、函數(shù)
A.短小
1.函數(shù)的第一規(guī)則是要短小,第二條規(guī)則是還要更短小
2.if語句、else語句、while語句等,其中的代碼塊應(yīng)該只有一行,該行大抵是一個(gè)函數(shù)調(diào)用語句
3.函數(shù)不應(yīng)該大到足以容納嵌套結(jié)構(gòu),所以,函數(shù)的縮進(jìn)層級(jí)不該多于一層或兩層
B.只做一件事
1.函數(shù)應(yīng)該做一件事。做好這件事,只做這一件事
2.要判斷函數(shù)是否不止做了一件事,就是看看是否能再拆出一個(gè)函數(shù),該函數(shù)不僅只是單純地重新詮釋其實(shí)現(xiàn)
3.只做一件事的函數(shù)無法被合理地切分為多個(gè)區(qū)段
C.每個(gè)函數(shù)一個(gè)抽象層級(jí)
1.要確保函數(shù)只做一件事,函數(shù)中的語句都要在同一抽象層級(jí)上
2.自頂向下讀代碼:向下規(guī)則,讓代碼擁有自頂向下的閱讀順序,讓每個(gè)函數(shù)后面都跟著下一抽象層級(jí)的函數(shù)
D.switch語句
1.寫出短小的switch語句很維,寫出只做一件事的switch語句也很難,Switch天生要做N件事
2.將switch語句埋到抽象工廠底下,不讓任何人看到
3.如果只出現(xiàn)一次,用于創(chuàng)建多態(tài)對(duì)象,而且隱藏在某個(gè)繼承關(guān)系中,在系統(tǒng)其他部分看不到,就還能容忍
E.使用描述性的名稱
1.沃德原則:“如果每個(gè)例程都讓你感到深合已意,那就是整潔代碼”
2.函數(shù)越短小,功能越集中,就越便于取個(gè)好名字
3.別害怕長名稱,長而具有描述性的名稱,要比短而令人費(fèi)解的名稱好
4.命名方式要保持一致。使用與模塊名一脈相承的短語、名詞和動(dòng)詞給函數(shù)命名
F.函數(shù)參數(shù)
1.最理想的參數(shù)數(shù)量是零,有足夠的理由才能用三個(gè)以上參數(shù)
2.事件:在這種形式中,有輸入?yún)?shù)而無輸出參數(shù),程序?qū)⒑瘮?shù)看作一個(gè)事件,使用該參數(shù)修改系統(tǒng)狀態(tài)
3.對(duì)于轉(zhuǎn)換,使用輸出參數(shù)而非返回值令人迷惑,如果函數(shù)要對(duì)輸入?yún)?shù)進(jìn)行轉(zhuǎn)換操作,轉(zhuǎn)換結(jié)果就該體現(xiàn)為返回值
4.向函數(shù)傳入布爾值會(huì)使方法簽名立刻變得復(fù)雜起來,大聲宣布函數(shù)不止做一件事
5.如果函數(shù)看來需要兩個(gè)、三個(gè)或三個(gè)以上參數(shù),就說明其中一些參數(shù)應(yīng)該封裝為類了
6.有可變參數(shù)的函數(shù)可能是一元、二元甚至三元,超過這個(gè)數(shù)量就可能要犯錯(cuò)了
7.對(duì)于一元函數(shù),函數(shù)和參數(shù)應(yīng)當(dāng)形成一種非常良好的動(dòng)詞/名詞對(duì)形式
G.無副作用
1.函數(shù)承諾只做一件事,但還是會(huì)做其他被藏起來的事,會(huì)導(dǎo)致古怪的時(shí)序性耦合及順序依賴
2.參數(shù)多數(shù)會(huì)被自然而希地看作是函數(shù)的輸入
H.分隔指令與詢問
1.函數(shù)要么做什么事,要么回答什么事,但二者不可得兼
I.使用異步替代返回錯(cuò)誤碼
1.從指令式函數(shù)返回錯(cuò)誤碼輕微違反了指令與詢問分隔的規(guī)則。它鼓勵(lì)了在if語句判斷中把指令當(dāng)作表達(dá)式使用
2.try/catch代碼塊把錯(cuò)誤處理與正常流程混為一談,最好把try和catch代碼塊的主體部分抽離出來,另外形成函數(shù)
3.錯(cuò)誤處理就是一件事,處理錯(cuò)誤的函數(shù)不該做其他事
4.依賴磁鐵(dependency magnet):其他許多類都得導(dǎo)入和使用它
J.別重復(fù)自己
1.重復(fù)可能是軟件中一切邪惡的根源,許多原則與實(shí)踐規(guī)則都是為控制與消除重復(fù)而創(chuàng)建
K.結(jié)構(gòu)化編程
1.每個(gè)函數(shù)、函數(shù)中的每個(gè)代碼塊都應(yīng)該有一個(gè)入口、一個(gè)出口。遵循這些規(guī)則,意味著在每個(gè)函數(shù)中只該有一個(gè)return語句,循環(huán)中不能有break或者continue語句,而且永永遠(yuǎn)遠(yuǎn)不能有任何的goto語句
2.只有在大函數(shù)中這些規(guī)則才會(huì)有明顯好處,因?yàn)椋灰瘮?shù)保持短小,偶爾出現(xiàn)的return、break或continue語句沒有壞處,goto語句盡量避免
L.如何寫出這樣的函數(shù)
1.打磨代碼,分解函數(shù)、修改名稱、消除重復(fù)
2.縮短和重新安置方法、拆散類、保持測試通過
四、注釋
1.若編程語言足夠有表達(dá)力,就不需要注釋
2.注釋的恰當(dāng)用法是彌補(bǔ)我們?cè)谟么a表達(dá)意圖時(shí)遭遇的失敗。注釋總是一種失敗
3.程序員應(yīng)當(dāng)負(fù)責(zé)將注釋保持在可維護(hù)、有關(guān)聯(lián)、精確的高度,更應(yīng)該把力氣用在寫清楚代碼上,直接保證無須編寫注釋
4.不準(zhǔn)確的注釋要比沒注釋壞得多
A.注釋不能美化糟糕的代碼
1.帶有少量注釋的整潔而有表達(dá)力的代碼,要比帶有大量注釋的零碎而復(fù)雜的代碼像樣得多
2.與其花時(shí)間編寫解釋你搞出的糟糕的代碼的注釋,不如花時(shí)間清潔那堆糟糕的代碼
B.用代碼來闡述
1.用代碼解釋你大部分的意圖,很多時(shí)候,簡單到只需要?jiǎng)?chuàng)建一個(gè)描述與注釋所言同一事物的函數(shù)即可
C.好注釋
1.法律信息
2.提供信息的注釋
3.對(duì)意圖的解釋:提供某個(gè)決定后面的意圖
4.闡釋:注釋把某些晦澀難懂的參數(shù)或返回值的意義翻譯為某種可讀形式
5.警示
6.TODO注釋:注意要清理
7.放大:放大某種看來不合理之物的重要性
8.公共API中的Javadoc
D.壞注釋
1.喃喃自語
2.多余的注釋
3.誤導(dǎo)性注釋
4.循規(guī)式注釋
5.日志式注釋
6.廢話注釋
7.可怕的廢話
8.能用函數(shù)或變量時(shí)就別用注釋
9.位置標(biāo)記:如果標(biāo)記欄不多,就會(huì)顯而易見,所以,盡量少用標(biāo)記欄,只在特別有價(jià)值的時(shí)候用
10.括號(hào)后面的注釋
11.歸屬與署名
12.注釋掉的代碼
13.HTML注釋
14.非本地信息
15.信息過多
16.不明顯的聯(lián)系
17.函數(shù)頭
18.非公共代碼中的Javadoc
19.范例
五、格式
A.格式的目的
1.代碼格式關(guān)乎溝通,而溝通是專業(yè)開發(fā)者的頭等大事
B.垂直格式
1.短文件通常比長文件易于理解
2.源文件也要像報(bào)紙文章那樣 ,名稱應(yīng)當(dāng)簡單且一目了然,最頂部應(yīng)該給出高層次概念和算法,細(xì)節(jié)應(yīng)該往下漸次展開
3.幾乎所有的代碼都是從上往下讀,從左往右讀。每行展現(xiàn)一個(gè)表達(dá)式或一個(gè)子句,每代碼行展示一條完整的思路。這些思路用空白行區(qū)隔開來。
4.如果說空白行隔開了概念,靠近的代碼行則暗示了它們之間的緊密關(guān)系
5.除非有很好的理由,否則就不要把關(guān)系密切的概念放到不同的文件中,實(shí)際上,這也是避免使用protected變量的理由之一,應(yīng)避免迫使讀者在源文件和類中跳來跳去
6.變量聲明應(yīng)盡可能靠近其使用位置,在函數(shù)頂部出現(xiàn),循環(huán)的控制變量總是在循環(huán)語句中聲明
7.實(shí)體變量在類的頂部聲明
8.相關(guān)函數(shù),若某個(gè)函數(shù)調(diào)用了另外一個(gè),就應(yīng)該把它們放到一起,而且調(diào)用者應(yīng)該盡可能放在被調(diào)用者上面
9.概念相關(guān)的代碼應(yīng)該放到一起,相關(guān)性越強(qiáng),彼此之間的距離就該越短
10.我們想自上向下展示函數(shù)調(diào)用依賴順序,被調(diào)用的函數(shù)應(yīng)該放在執(zhí)行調(diào)用的函數(shù)下面,這就建立了一種自頂向下貫穿源代碼模塊的良好信息流
C.橫向格式
1.盡力保持代碼行短小,遵循無需拖動(dòng)滾動(dòng)條到右邊的原則,最好不超過120個(gè)
2.我們使用空格字符將彼此緊密相關(guān)的事物連接到一起,也用空格字符把相關(guān)性較弱的事物分隔開
3.對(duì)齊,像是在強(qiáng)調(diào)不重要的東西,把目光從真正的意義上拉開
4.如果有較長的列表需要做對(duì)齊處理,那問題就是在列表的長度上而不是對(duì)齊上
5.程序員相當(dāng)依賴縮進(jìn)模式
6.有時(shí),while或for語句的語句體為空,如果無法避免,就確保空范圍體的縮進(jìn),用括號(hào)包圍起來
D.團(tuán)隊(duì)規(guī)則
1.一組開發(fā)者應(yīng)當(dāng)認(rèn)同一種模式風(fēng)格,每個(gè)成員都應(yīng)該采用那種風(fēng)格
2.好的軟件系統(tǒng)是由一系列讀起來不錯(cuò)的代碼文件組成的,需要擁有一致和順暢的風(fēng)格
六、對(duì)象和數(shù)據(jù)結(jié)構(gòu)
A.數(shù)據(jù)抽象
1.隱藏實(shí)現(xiàn)關(guān)乎抽象,類并不簡單地用取值器和賦值器將其變量推向外部,而是曝露抽象接口,以便用戶無需了解數(shù)據(jù)的實(shí)現(xiàn)就能操作數(shù)據(jù)本體
B.數(shù)據(jù)、對(duì)象的反對(duì)稱性
1.對(duì)象把數(shù)據(jù)隱藏于抽象之后,曝露操作數(shù)據(jù)的函數(shù)。數(shù)據(jù)結(jié)構(gòu)曝露其數(shù)據(jù),并沒有提供有意義的函數(shù)
2.對(duì)象與數(shù)據(jù)結(jié)構(gòu)之間的二分原理:
* 過程式代碼(使用數(shù)據(jù)結(jié)構(gòu)的代碼)便于在不改動(dòng)既有數(shù)據(jù)結(jié)構(gòu)的前提下添加新函數(shù)。面向?qū)ο蟠a便于在不改動(dòng)既有函數(shù)的前提下添加新類
* 過程式代碼難以添加新數(shù)據(jù)結(jié)構(gòu),因?yàn)楸仨毿薷乃泻瘮?shù)。面向?qū)ο蟠a難以添加新函數(shù),因?yàn)楸仨毿薷乃蓄?/p>
C.得墨忒耳律
1.得墨忒耳律(The Law of Demeter):模塊不應(yīng)了解它所操作對(duì)象的內(nèi)部情形,意味著對(duì)象不應(yīng)通過存取器曝露其內(nèi)部結(jié)構(gòu),因?yàn)檫@樣更像是曝露而非隱藏其內(nèi)部結(jié)構(gòu)
2.混合結(jié)構(gòu),一半是對(duì)象,一半是數(shù)據(jù)結(jié)構(gòu),應(yīng)避免這種結(jié)構(gòu)
D.數(shù)據(jù)傳送對(duì)象
1.最為精練的數(shù)據(jù)結(jié)構(gòu),是一個(gè)只有公共變量、沒有函數(shù)的類,這種被稱為數(shù)據(jù)傳送對(duì)象,或DTO(Data Transfer Objects)。在與數(shù)據(jù)庫通信、或解析套接字傳遞的消息之類場景中
2.JavaBean或Active Record
3.不要塞進(jìn)業(yè)務(wù)規(guī)則方法,把Active Record當(dāng)做數(shù)據(jù)結(jié)構(gòu),并創(chuàng)建包含業(yè)務(wù)規(guī)則、隱藏內(nèi)部數(shù)據(jù)(可能就是Active Record的實(shí)體)的獨(dú)立對(duì)象
七、錯(cuò)誤處理
1.錯(cuò)誤處理很重要,但如果它搞亂了代碼邏輯,就是錯(cuò)誤的做法
A.使用異常而非返回碼
1.遇到錯(cuò)誤時(shí),最好拋出一個(gè)異常。調(diào)用代碼很整潔,其邏輯不會(huì)被錯(cuò)誤處理搞亂
B.先寫Try-Catch-Finally語句
1.異常的妙處之一是,它們?cè)诔绦蛑卸x了一個(gè)范圍。執(zhí)行try-catch-finally語句中try部分的代碼時(shí),你是在表明可隨時(shí)取消執(zhí)行,并在catch語句中接續(xù)
2.在某種意義上,try代碼塊就像是事務(wù),catch代碼塊將程序維持在一種持續(xù)狀態(tài)
3.在編寫可能拋出異常的代碼時(shí),最好先寫try-catch-finally語句,能幫你定義代碼的用戶應(yīng)該期待什么,無論try代碼塊中執(zhí)行的代碼出什么錯(cuò)都一樣
C.使用不可控異常
1.可控異常的代價(jià)就是違反開放/閉合原則,得在catch語句和拋出異常處之間的每個(gè)方法簽名中聲明該異常
2.可控異常意味著對(duì)軟件中較低層級(jí)的修改,都將波及較高層級(jí)的簽名
D.給出異常發(fā)生的環(huán)境說明
1.拋出的每個(gè)異常,都應(yīng)當(dāng)提供足夠的環(huán)境說明,以便判斷錯(cuò)誤的來源和處所
2.應(yīng)創(chuàng)建信息充分的錯(cuò)誤消息,并和異常一起傳遞出去
E.依調(diào)用者需要定義異常類
1.最重要的考慮是它們?nèi)绾伪徊东@
2.將第三方API打包是個(gè)良好的實(shí)踐手段,降低了對(duì)每個(gè)第三方的依賴,也有助于模擬第三方調(diào)用
F.定義常規(guī)流程
1.特例模式(SPECIAL CASE PATTERN,[Fowler]),創(chuàng)建一個(gè)類或配置一個(gè)對(duì)象,用來處理特例,異常行為被封裝到特例對(duì)象中
G.別返回null值
1.返回null值,基本是在給自己增加工作量,也是在給調(diào)用者添亂,只要有一處沒檢查null值,應(yīng)用程序就會(huì)失控
H.別傳遞null值
1.將null值傳遞給其他方法更糟糕,除非API要求你向它傳遞null值,否則就要盡可能避免傳遞null值
八、邊界
A.使用第三方代碼
1.第三方程序包和框架提供者追求普適性,這樣就能在多個(gè)環(huán)境中工作,吸引廣泛的用戶
2.我們建議不要將Map(或在邊界上的其他接口)在系統(tǒng)中傳遞,把它保留在類或近親類中,避免從API中返回邊界接口,或?qū)⒔涌谧鳛閰?shù)傳遞給公共API
B.瀏覽和學(xué)習(xí)邊界
C.學(xué)習(xí)性測試的好處不只是免費(fèi)
1.學(xué)習(xí)性測試毫無成本,編寫測試是獲得這些知識(shí)(要使用的API)的容易而不會(huì)影響其他工作的途徑
2.學(xué)習(xí)性測試確保第三方程序包按照我們想要的方式工作
D.使用尚不存在的代碼
1.編寫我們想得到的接口,好處之一是它在我們控制之下,有助于保持客戶代碼更可讀,且集中于它該完成的工作
E.整潔的邊界
1.邊界上的改動(dòng),有良好的軟件設(shè)計(jì),無需巨大投入和重寫即可進(jìn)行修改
2.邊界上的代碼需要清晰的分割和定義了期望的測試。依靠你能控制的東西,好過依靠你控制不了的東西,免得日后受它控制
3.可以使用ADAPTER模式將我們的接口轉(zhuǎn)換為第三方提供的接口
九、單元測試
A.TDD三定律
1.在編寫能通過的單元測試前,不可編寫生產(chǎn)代碼
2.只可編寫剛好無法通過的單元測試,不能編譯也算不通過
3.只可編寫剛好足以通過當(dāng)前失敗測試的生產(chǎn)代碼
B.保持測試整潔
1.臟測試等同于沒測試,測試必須隨生產(chǎn)代碼的演進(jìn)而修改,測試越臟,就越難修改
2.測試代碼和生產(chǎn)代碼一樣重要,它需要被思考、被設(shè)計(jì)和被照料,它該像生產(chǎn)代碼一般保持整潔
3.如果測試不能保持整潔,你就會(huì)失去它們,沒有了測試,你就會(huì)失去保證生產(chǎn)代碼可擴(kuò)展的一切要素
C.整潔的測試
1.三個(gè)要素:可讀性、可讀性和可讀性,明確、簡潔還有足夠的表達(dá)力
2.構(gòu)造-操作-檢驗(yàn)(BUILD-OPERATE-CHECK)模式,第一個(gè)環(huán)節(jié)構(gòu)造測試數(shù)據(jù),第二個(gè)環(huán)節(jié)操作測試數(shù)據(jù),第三個(gè)部分檢驗(yàn)操作是否得到期望的結(jié)果
3.守規(guī)矩的開發(fā)者也將他們的測試代碼重構(gòu)為更簡潔和具有表達(dá)力的形式
D.每個(gè)測試一個(gè)斷言
1.JUnit中每個(gè)測試函數(shù)都應(yīng)該有且只有一個(gè)斷言語句
2.最好的說法是單個(gè)測試中的斷言數(shù)量應(yīng)該最小化
3.更好一些的規(guī)則或許是每個(gè)測試函數(shù)中只測試一個(gè)概念
4.最佳規(guī)則是應(yīng)該盡可能減少每個(gè)概念的斷言數(shù)量,每個(gè)測試函數(shù)只測試一個(gè)概念
E.F.I.R.S.T
1.快速(Fast)測試應(yīng)該夠快
2.獨(dú)立(Independent)測試應(yīng)該相互獨(dú)立
3.可重復(fù)(Repeatable)測試應(yīng)當(dāng)可在任何環(huán)境中重復(fù)通過
4.自足驗(yàn)證(Self-Validating)測試應(yīng)該有布爾值輸出
5.及時(shí)(Timely)測試應(yīng)及時(shí)編寫
十、類
A.類的組織
1.類應(yīng)該從一級(jí)變量列表開始,如果有公共靜態(tài)變量,應(yīng)該先出現(xiàn),然后是私有靜態(tài)變量,以及實(shí)體變量,很少會(huì)有公共變量
2.公共函數(shù)應(yīng)該跟在變量列表之后
3.保持變量和工具函數(shù)的私有性,但并不執(zhí)著于此
B.類應(yīng)該短小
1.第一規(guī)則是類應(yīng)該短小,第二規(guī)則是還要更短小
2.衡量方法,計(jì)算權(quán)責(zé)(responsibility)
3.類的名稱應(yīng)當(dāng)描述其權(quán)責(zé),如果無法為某個(gè)類命以精確的名稱,這個(gè)類大概就太長了,類名越含混,該類越有可能擁有過多權(quán)責(zé)
4.單一權(quán)責(zé)原則(SRP)認(rèn)為,類或模塊應(yīng)有且只有一條加以修改的理由
5.系統(tǒng)應(yīng)該由許多短小的類而不是少量巨大的類組成,每個(gè)小類封裝一個(gè)權(quán)責(zé),只有一個(gè)修改的原因,并與少數(shù)其他類一起協(xié)同達(dá)成期望的系統(tǒng)行為
6.方法操作的變量越多,就越黏聚到類上,如果一個(gè)類的每個(gè)變量都被每個(gè)方法所使用,則該類具有最大的內(nèi)聚性
7.保持函數(shù)和參數(shù)列表短小的策略,有時(shí)會(huì)導(dǎo)致為一組子集方法所用的實(shí)體變量數(shù)量增加。出現(xiàn)這種情況時(shí),往往意味著至少有一個(gè)類要從大類中掙扎出來。你應(yīng)當(dāng)嘗試將這些變量和方法分拆到兩個(gè)或多個(gè)類中,讓新的類更為內(nèi)聚
8.將大函數(shù)拆為許多小函數(shù),往往也是將類拆分為多個(gè)小類的時(shí)機(jī)
C.為了修改而組織
1.在整潔的系統(tǒng)中,我們對(duì)類加以組織,以降低修改的風(fēng)險(xiǎn)
2.開放-閉合原則(OCP):類應(yīng)當(dāng)對(duì)擴(kuò)展開放,對(duì)修改封閉
3.在理想系統(tǒng)中,我們通過擴(kuò)展系統(tǒng)而非修改現(xiàn)有代碼來添加新特性
4.依賴倒置原則(Dependency Inversion Principle,DIP),類應(yīng)該依賴于抽象而不是依賴于具體細(xì)節(jié)
十一、系統(tǒng)
A.如何建造一個(gè)城市
1.每個(gè)城市都有一組人管理不同的部分,有人負(fù)責(zé)全局,其他人負(fù)責(zé)細(xì)節(jié)
2.深化出恰當(dāng)?shù)某橄蟮燃?jí)和模塊,好讓個(gè)人和他們所管理的“組件”即便在不了解全局時(shí)也能有效地運(yùn)轉(zhuǎn)
B.將系統(tǒng)的構(gòu)造與使用分開
1.構(gòu)造與使用是非常不一樣的過程
2.軟件系統(tǒng)應(yīng)將啟始過程和啟始過程之后的運(yùn)行時(shí)邏輯分離開,在啟始過程中構(gòu)建應(yīng)用對(duì)象,也會(huì)存在互相纏結(jié)的依賴關(guān)系
3.將構(gòu)造與使用分開的方法之一是將全部構(gòu)造過程搬遷到main或被稱為main的模塊中,設(shè)計(jì)系統(tǒng)的其余部分時(shí),假設(shè)所有對(duì)象都已正確構(gòu)造和設(shè)置
4.可以使用抽象工廠模式讓應(yīng)用自行控制何時(shí)創(chuàng)建對(duì)象,但構(gòu)造的細(xì)節(jié)卻隔離于應(yīng)用程序代碼之外
5.控制反轉(zhuǎn)將第二權(quán)責(zé)從對(duì)象中拿出來,轉(zhuǎn)移到另一個(gè)專注于此的對(duì)象中,從而遵循了單一權(quán)責(zé)原則。在依賴管理情景中,對(duì)象不應(yīng)負(fù)責(zé)實(shí)體化對(duì)自身的依賴,反之,它應(yīng)當(dāng)將這份權(quán)責(zé)移交給其他“有權(quán)力”的機(jī)制,從而實(shí)現(xiàn)控制的反轉(zhuǎn)
C.擴(kuò)容
1.“一開始就做對(duì)系統(tǒng)”純屬神話,反之,我們應(yīng)該只去實(shí)現(xiàn)今天的用戶故事,然后重構(gòu),明天再擴(kuò)展系統(tǒng)、實(shí)現(xiàn)新的用戶故事,這就是迭代和增量敏捷的精髓所在。測試驅(qū)動(dòng)開發(fā)、重構(gòu)以及它們打造出的整潔代碼,在代碼層面保證了這個(gè)過程的實(shí)現(xiàn)
2.軟件系統(tǒng)與物理系統(tǒng)可以類比。它們的架構(gòu)都可以遞增式的增長,只要我們持續(xù)將關(guān)注面恰當(dāng)?shù)厍蟹?/p>
3.持久化之類關(guān)注面傾向于橫貫?zāi)硞€(gè)領(lǐng)域的天然對(duì)象邊界
D.Java代理
1.適用于簡單情況,例如在單獨(dú)的對(duì)象或類中包裝方法調(diào)用
2.舊式的Java對(duì)象(Plain-Old Java Object, POJO)
E.純Java AOP框架
F.AspectJ的方面
G.測試驅(qū)動(dòng)系統(tǒng)架構(gòu)
1.通過方面式(AOP)的手段切分關(guān)注面的威力不可低估。假使你能用POJO編寫應(yīng)用程序的領(lǐng)域邏輯,在代碼層面與架構(gòu)關(guān)注面分離開,就有可能真正地用測試來驅(qū)動(dòng)架構(gòu)
2.沒必要先做大設(shè)計(jì)(Big Design Up Front,BDUF),BDUF甚至是有害的,它阻礙改進(jìn),因?yàn)樾睦砩蠒?huì)抵制丟棄即成之事,也因?yàn)榧軜?gòu)上的方案選擇影響到后續(xù)的設(shè)計(jì)思路
3.我們可以從“簡單自然”但切分良好的架構(gòu)開始做軟件項(xiàng)目,快速交付可工作的用戶故事,隨著規(guī)模的增長添加更多基礎(chǔ)架構(gòu)
4.最佳的系統(tǒng)架構(gòu)由模塊化的關(guān)注面領(lǐng)域組成,每個(gè)關(guān)注面均用純Java(或其他語言)對(duì)象實(shí)現(xiàn),不同的領(lǐng)域之間用最不具有侵害性的方面或類方面工具整合起來,這種架構(gòu)能測試驅(qū)動(dòng),就像代碼一樣
H.優(yōu)化決策
1.模塊化和關(guān)注面切分成就了分散化管理和決策
2.延遲決策至最后一刻也是好手段,它讓我們能夠基于最有可能的信息做出選擇
3.擁有模塊化關(guān)注面的POJO系統(tǒng)提供的敏捷能力,允許我們基于最新的知識(shí)做出優(yōu)化的、時(shí)機(jī)剛好的決策,決策的復(fù)雜性也降低了
I.明智使用添加了可論證價(jià)值的標(biāo)準(zhǔn)
1.有了標(biāo)準(zhǔn),就更易復(fù)用想法和組件、雇用擁有相關(guān)經(jīng)驗(yàn)的人才、封裝好點(diǎn)子,以及將組件連接起來。不過,創(chuàng)立標(biāo)準(zhǔn)的過程有時(shí)卻漫長到行業(yè)等不及的程度,有些標(biāo)準(zhǔn)沒能與它要服務(wù)的采用者的真實(shí)需求相結(jié)合
J.系統(tǒng)需要領(lǐng)域特定語言
1.領(lǐng)域特定語言(Domain-Specific Language, DSL)是一種單獨(dú)的小型腳本語言或以標(biāo)準(zhǔn)語言寫就的API,領(lǐng)域?qū)<铱梢杂盟帉懽x像是組織嚴(yán)謹(jǐn)?shù)纳⑽囊话愕拇a
2.領(lǐng)域特定語言允許所有抽象層級(jí)和應(yīng)用程序中的所有領(lǐng)域,從高級(jí)策略到底層細(xì)節(jié),使用POJO來表達(dá)
十二、迭進(jìn)
A.通過迭進(jìn)設(shè)計(jì)達(dá)到整潔目的
1.“簡單規(guī)則”:
* 運(yùn)行所有測試
* 不可重復(fù)
* 表達(dá)了程序員的意圖
* 盡可能減少類和方法的數(shù)量
* 以上規(guī)則按其重要程序排列
B.簡單設(shè)計(jì)原則1:運(yùn)行所有測試
1.設(shè)計(jì)必須制造出如預(yù)期一般工作的系統(tǒng),這是首要因素
2.全面測試并持續(xù)通過所有測試的系統(tǒng),就是可測試的系統(tǒng),不可驗(yàn)證的系統(tǒng),絕不應(yīng)部署
3.只要系統(tǒng)可測試,就會(huì)導(dǎo)向保持類短小且目的單一的設(shè)計(jì)方案
4.緊耦合的代碼難以編寫測試
5.遵循有關(guān)編寫測試并持續(xù)運(yùn)行測試的簡單、明確的規(guī)則,系統(tǒng)就會(huì)更貼近OO低耦合度、高內(nèi)聚度的目標(biāo),編寫測試引致更好的設(shè)計(jì)
C.簡單設(shè)計(jì)原則2-4:重構(gòu)
1.有了測試,就能保持代碼和類的整潔,方法就是遞增式地重構(gòu)代碼
2.測試消除了對(duì)清理代碼就會(huì)破壞代碼的恐懼
D.不可重復(fù)
1.重復(fù)是擁有良好設(shè)計(jì)系統(tǒng)的大敵
2.極其雷同的代碼行當(dāng)然是重復(fù),還有實(shí)現(xiàn)上的重復(fù)等其他一些形態(tài)
3.“小規(guī)模復(fù)用”可大量降低系統(tǒng)復(fù)雜性,要想實(shí)現(xiàn)大規(guī)模復(fù)用,必須理解如何實(shí)現(xiàn)小規(guī)模復(fù)用
4.模板方法模式是一種移除高層級(jí)重復(fù)的通用技巧
E.表達(dá)力
1.軟件項(xiàng)目的主要成本在于長期維護(hù),代碼應(yīng)當(dāng)清晰地表達(dá)其作者的意圖
2.可以通過選用好名稱來表達(dá)
3.可以通過保持函數(shù)和類尺寸短小來表達(dá)
4.可以通過采用標(biāo)準(zhǔn)命名法來表達(dá)
5.編寫良好的單元測試也具有表達(dá)性
6.做到有表達(dá)力的最重要方式是嘗試
F.盡可能少的類和方法
1.類和方法的數(shù)量太多,有時(shí)是由毫無意義的教條主義導(dǎo)致的,應(yīng)該采用更實(shí)用的手段
2.目標(biāo)是在保持函數(shù)和類短小的同時(shí),保持整個(gè)系統(tǒng)短小精悍
十三、并發(fā)編程
A.為什么要并發(fā)
1.并發(fā)是一種解耦策略,它幫助我們把做什么(目的)和何時(shí)(時(shí)機(jī))做分解開
2.解耦目的與時(shí)機(jī)能明顯地改進(jìn)應(yīng)用程序的吞吐量和結(jié)構(gòu)
3.單線程程序許多時(shí)間花在等待web套接字I/O結(jié)束上面,通過采用同時(shí)訪問多個(gè)站點(diǎn)的多線程算法,就能改進(jìn)性能
4.常見的迷思和誤解
* 并發(fā)總能改進(jìn)性能:只在多個(gè)線程或處理器之間能分享大量等待時(shí)間的時(shí)候管用
* 編寫并發(fā)程序無需修改設(shè)計(jì):可能與單線程系統(tǒng)的設(shè)計(jì)極不相同
* 在采用web或ejb容器時(shí),理解并發(fā)問題并不重要
5.有關(guān)編寫并發(fā)軟件的中肯的說法:
* 并發(fā)會(huì)在性能和編寫額外代碼上增加一些開銷
* 正確的并發(fā)是復(fù)雜的,即使對(duì)于簡單的問題也是如此
* 并發(fā)缺陷并非總能重現(xiàn),所以常被看做偶發(fā)事件而忽略,未被當(dāng)做真的缺陷看待
* 并發(fā)常常需要對(duì)設(shè)計(jì)策略的根本性修改
B.挑戰(zhàn)
1.線程在執(zhí)行代碼時(shí)有許多可能路徑可行,有些路徑會(huì)產(chǎn)生錯(cuò)誤的結(jié)果
C.并發(fā)防御原則
1.單一權(quán)責(zé)原則(SRP):方法/類/組件應(yīng)當(dāng)只有一個(gè)修改的理由
* 并發(fā)相關(guān)代碼有自己的開發(fā)、修改和調(diào)優(yōu)生命周期
* 開發(fā)相關(guān)代碼有自己要對(duì)付的挑戰(zhàn),和非并發(fā)相關(guān)代碼不同
* 即使沒有周邊應(yīng)用程序增加的負(fù)擔(dān),寫得不好的并發(fā)代碼可能的出錯(cuò)方式數(shù)量也已經(jīng)足具有挑戰(zhàn)性
* 建議:分離并發(fā)相關(guān)代碼與其他代碼
2.推論:限制數(shù)據(jù)作用域
* 采用synchronized關(guān)鍵字在代碼中保護(hù)一塊使用共享對(duì)象的臨界區(qū)(critical section)
* 建議:謹(jǐn)記數(shù)據(jù)封閉;嚴(yán)格限制對(duì)可能被共享的數(shù)據(jù)的訪問
3.推論:使用數(shù)據(jù)復(fù)本
* 一開始就避免共享數(shù)據(jù),復(fù)制對(duì)象并以只讀方式對(duì)待,或復(fù)制對(duì)象,從多個(gè)線程收集所有復(fù)本的結(jié)果,并在單個(gè)線程中合并這些結(jié)果
4.推論:線程應(yīng)盡可能地獨(dú)立
* 讓每個(gè)線程在自己的世界中存在,不與其他線程共享數(shù)據(jù)
* 建議:嘗試將數(shù)據(jù)分解到可被獨(dú)立線程(可能在不同處理器上)操作的獨(dú)立子集
D.了解Java庫
?1.要注意:
* 使用類庫提供的線程安全群集
* 使用executor框架(executor framework)執(zhí)行無關(guān)任務(wù)
* 盡可能使用非鎖定解決方案
* 有幾個(gè)類并不是線程安全的
E.了解執(zhí)行模型
1.一些基礎(chǔ)定義
* 限定資源:并發(fā)環(huán)境中有著固定尺寸或數(shù)量的資源
* 互斥:每一時(shí)刻僅有一個(gè)線程能訪問共享數(shù)據(jù)或共享資源
* 線程饑餓:一個(gè)或一組線程在很長時(shí)間內(nèi)或永久被禁止
* 死鎖:兩個(gè)或多個(gè)線程互相等待執(zhí)行結(jié)束。每個(gè)線程都擁有其他線程需要的資源,行不到其他線程擁有的資源,就無法終止
* 活鎖:執(zhí)行次序一致的線程,每個(gè)都想要起步,但發(fā)現(xiàn)其他線程已經(jīng)“在路上”。由于競步的原因,線程會(huì)持續(xù)嘗試起步,但在很長時(shí)間內(nèi)卻無法如愿,甚至永遠(yuǎn)無法啟動(dòng)
2.生產(chǎn)者-消費(fèi)者模型:一個(gè)或多個(gè)生產(chǎn)者線程創(chuàng)建某些工作,并置于緩存或隊(duì)列中。一個(gè)或多個(gè)消費(fèi)者線程從隊(duì)列中獲取并完成這些工作。生產(chǎn)者消費(fèi)者之間的隊(duì)列是一種限定資源
3.讀者-作者模型:協(xié)調(diào)讀者線程,不去讀作者線程正在更新的信息(反之亦然),這是一種辛苦的平衡工作,作者線程傾向于長期鎖定許多讀者純種,從而導(dǎo)致吞吐量問題
4.宴席哲學(xué)家
5.建議學(xué)習(xí)這些基礎(chǔ)算法,理解其解決方案
F.警惕同步方法之間的依賴
1.同步方法之間的依賴會(huì)導(dǎo)致并發(fā)代碼中的狡猾缺陷,建議避免使用一個(gè)共享對(duì)象的多個(gè)方法
2.基于客戶端的鎖定:客戶端代碼在調(diào)用第一個(gè)方法前鎖定服務(wù)端,確保鎖的范圍覆蓋了調(diào)用最后一個(gè)方法的代碼
3.基于服務(wù)端的鎖定:在服務(wù)端內(nèi)創(chuàng)建鎖定服務(wù)端的方法,調(diào)用所有方法,然后解鎖。讓客戶端代碼調(diào)用新方法
4.適配服務(wù)端:創(chuàng)建執(zhí)行鎖定的中間層。這是一種基于服務(wù)端的鎖定的例子,但不修改原始服務(wù)端代碼
G.保持同步區(qū)域微小
1.同一個(gè)鎖維護(hù)的所有代碼區(qū)域在任一時(shí)刻保證只有一個(gè)線程執(zhí)行,因?yàn)樗鼈儙砹搜舆t和額外開銷,臨界區(qū)應(yīng)該被保護(hù)起來,應(yīng)該盡可能少地設(shè)計(jì)臨界區(qū)
H.很維編寫正確的關(guān)閉代碼
1.平靜關(guān)閉很難做到,常見問題與死鎖有關(guān),線程一直等待永遠(yuǎn)不會(huì)到來的信號(hào)
2.建議:盡早考慮關(guān)閉問題,盡早令其工作正常
I.測試線程代碼
1.建議:編寫有潛力曝露問題的測試,在不同的編程配置、系統(tǒng)配置和負(fù)載條件下頻繁運(yùn)行。如果測試失敗,跟蹤錯(cuò)誤。別因?yàn)楹髞頊y試通過了后來的運(yùn)行就忽略失敗
2.將偽失敗看作可能的線程問題:線程代碼導(dǎo)致“不可能失敗的”失敗,不要將系統(tǒng)錯(cuò)誤歸咎于偶發(fā)事件
3.先使非線程代碼可工作:不要同時(shí)追蹤非線程缺陷和線程缺陷,確保代碼在線程之外可工作
4.編寫可插拔的線程代碼,能在不同的配置環(huán)境下運(yùn)行
5.編寫可調(diào)整的線程代碼:允許線程依據(jù)吞吐量和系統(tǒng)使用率自我調(diào)整
6.運(yùn)行多于處理器數(shù)量的線程:任務(wù)交換越頻繁,越有可能找到錯(cuò)過臨界區(qū)域?qū)е滤梨i的代碼
7.在不同平臺(tái)上運(yùn)行:盡早并經(jīng)常地在所有目標(biāo)平臺(tái)上運(yùn)行線程代碼
8.裝置試錯(cuò)代碼:增加對(duì)Object.wait()、Object.sleep()、Object.yield()、Object.priority()等方法的調(diào)用,改變代碼執(zhí)行順序,硬編碼或自動(dòng)化
十四、逐步改進(jìn)
1.要編寫清潔代碼,必須先寫骯臟代碼,然后再清理它
2.毀壞程序的最好方法之一就是以改進(jìn)之名大動(dòng)其結(jié)構(gòu)
十五、JUnit內(nèi)幕
十六、重構(gòu)SerialDate
十七、味道與啟發(fā)
A.注釋
1.不恰當(dāng)?shù)男畔ⅲ鹤⑨屩粦?yīng)該描述有關(guān)代碼和設(shè)計(jì)的技術(shù)性信息
2.廢棄的注釋
3.冗余的注釋
4.糟糕的注釋:別閑扯,別畫蛇添足,保持簡潔
5.注釋掉的代碼:刪除它
B.環(huán)境
1.需要多步才能實(shí)現(xiàn)的構(gòu)建:構(gòu)建系統(tǒng)應(yīng)該是單步的小操作
2.需要多步才能做到的測試:應(yīng)當(dāng)能夠發(fā)出單個(gè)指令就可以運(yùn)行全部單元測試
C.函數(shù)
1.過多的參數(shù):參數(shù)量應(yīng)該少,三個(gè)以上的參數(shù)非常值得質(zhì)疑
2.輸出參數(shù):輸出參數(shù)違反直覺,直接修改它所有對(duì)象的狀態(tài)
3.標(biāo)識(shí)參數(shù):布爾值參數(shù)大聲宣告函數(shù)做了不止一件事,應(yīng)該消滅掉
4.死函數(shù):永不被調(diào)用的方法應(yīng)該丟棄
D.一般性問題:
1.一個(gè)源文件中存在多種語言:盡力減少源文件中額外語言的數(shù)量和范圍
2.明顯的行為未被實(shí)現(xiàn):遵循“最小驚異原則”(The principle of Least Surprise),函數(shù)或類應(yīng)該實(shí)現(xiàn)其他程序員有理由期待的行為?
3.不正確的邊界行為:別依賴直覺,追索每種邊界條件,并編寫測試
4.忽視安全
5.重復(fù):看到重復(fù)代碼,都代表遺漏了抽象
6.在錯(cuò)誤的抽象層級(jí)上的代碼:創(chuàng)建分離較高層級(jí)一般性概念(抽象類)與較低層級(jí)細(xì)節(jié)概念(派生類)的抽象模型
7.基類依賴于派生類:基類對(duì)派生類應(yīng)該一無所知
8.信息過多:設(shè)計(jì)良好的模塊有著非常小的接口,限制類或模塊中暴露的接口數(shù)量,類中的方法越少越好,隱藏你的數(shù)據(jù),隱藏你的工具函數(shù),隱藏常量和臨時(shí)變量
9.死代碼:刪除掉
10.垂直分隔:變量和函數(shù)應(yīng)該在靠近被使用的地方定義,垂直距離要短
11.前后不一致:從一而終,可以追溯到最小驚異原則,讓代碼更加易于閱讀和修改
12.混淆視聽:保持源文件整潔,良好地組織,不被搞亂
13.人為耦合:不互相依賴的東西不該耦合
14.特性依戀:類的方法只應(yīng)對(duì)其所屬類中的變量和函數(shù)感興趣,不該垂青其他類中的變量和函數(shù)
15.選擇算子參數(shù):使用多個(gè)函數(shù),通常優(yōu)于向單個(gè)函數(shù)傳遞某些代碼來選擇函數(shù)行為?
16.晦澀的意圖:代碼要盡可能具有表達(dá)力
17.位置錯(cuò)誤的權(quán)責(zé):代碼應(yīng)該放在讀者自然而然期待它所有的地方
18.不恰當(dāng)?shù)撵o態(tài)方法:如果的確需要靜態(tài)函數(shù),確保沒機(jī)會(huì)打算讓它有多態(tài)行為
19.使用解釋性變量:讓程序可讀的最有力方法之一就是將計(jì)算過程打散成用有意義的單詞命名的變量中放置的中間值
20.函數(shù)名稱應(yīng)該表達(dá)其行為
21.理解算法:在你認(rèn)為自己完成某個(gè)函數(shù)之前,確認(rèn)自己理解了它是怎么工作的,你必須知道解決方案是正確的
22.把邏輯依賴改為物理依賴:依賴模塊不應(yīng)對(duì)被依賴者模塊有假定,它應(yīng)當(dāng)明確地詢問后者全部信息
23.用多態(tài)替代if/Else或Switch/Case,“單個(gè)switch”規(guī)則:對(duì)于給定的選擇類型,不應(yīng)有多于一個(gè)switch語句
24.遵循標(biāo)準(zhǔn)約定,遵循基于通用行業(yè)規(guī)范的一套編碼標(biāo)準(zhǔn)
25.用命名常量替代魔術(shù)數(shù),在代碼中出現(xiàn)原始形態(tài)數(shù)字通常來說是壞現(xiàn)象,有些常量與非常具有自我解釋能力的代碼協(xié)同工作時(shí),就不必總是需要命名常量來隱藏了。“魔術(shù)數(shù)”泛指任何不能自我描述的符號(hào)
26.準(zhǔn)確,在代碼中做決定時(shí),確認(rèn)自己足夠準(zhǔn)確,明確自己為何要這么做,如果遇到異常情況如何處理
27.結(jié)構(gòu)甚于約定
28.封裝條件,如果沒有if或while語句的上下文,布爾邏輯就難以理解,應(yīng)該把解釋了條件意圖的函數(shù)抽離出來
29.避免否定性條件,盡可能將條件表示為肯定形式
30.函數(shù)只該做一件事
31.掩蔽時(shí)序耦合,排列函數(shù)參數(shù),好讓它們被調(diào)用的次序顯而易見
32.別隨意,構(gòu)建代碼需要理由,而且理由應(yīng)與代碼結(jié)構(gòu)相契合
33.封裝邊界條件,把處理邊界條件的代碼集中到一處,不要散落于代碼中
34.函數(shù)應(yīng)該只在一個(gè)抽象層級(jí)上,函數(shù)中的語句應(yīng)該在同一抽象層級(jí)上,該層級(jí)應(yīng)該是函數(shù)名所示操作的下一層
35.在較高層級(jí)放置可配置數(shù)據(jù),如果你有個(gè)已知并該在較高抽象層級(jí)的默認(rèn)常量或配置值,不要將它埋藏到較低層級(jí)的函數(shù)中
36.避免傳遞瀏覽,讓直接協(xié)作者提供所需的全部服務(wù),不必逛遍系統(tǒng)的對(duì)象全圖,搜尋我們要調(diào)用的方法
E.Java
1.通過使用通配符避免過長的導(dǎo)入清單
2.不要繼承常量,應(yīng)該直接導(dǎo)入常量類
3.常量 vs. 枚舉,放心使用枚舉
F.名稱
1.采用描述性名稱,事物的意義隨著軟件的演化而變化,要經(jīng)常性地重新估量名稱是否恰當(dāng)
2.名稱應(yīng)與抽象層級(jí)相符,不要取溝通實(shí)現(xiàn)的名稱;取反映類或函數(shù)抽象層級(jí)的名稱
3.盡可能使用標(biāo)準(zhǔn)命名法
4.無歧義的名稱,選用不會(huì)混淆函數(shù)或變量意義的名稱
5.為較大作用范圍選用較長名稱
6.避免編碼,不要用匈牙利命名法污染你的名稱
7.名稱應(yīng)該說明副作用
G.測試
1.測試不足,一套測試應(yīng)該測到所有可能失敗的東西
2.使用覆蓋率工具,能匯報(bào)你測試策略中的缺口
3.別略過小測試
4.被忽略的測試就是對(duì)不確定事物的疑問
5.測試邊界條件
6.全面測試相近的缺陷
7.測試失敗的模式有啟發(fā)性,完整的測試用例,按合理的順序排列,能暴露出模式
8.測試覆蓋率的模式有啟發(fā)性
9.測試應(yīng)該快速