Clean Code

整潔代碼

  • 代碼呈現(xiàn)了需求的細(xì)節(jié)。將需求明確到機(jī)器可以執(zhí)行的細(xì)節(jié)程度葫慎,就是編程要做的事衔彻。而這種規(guī)約正是代碼。
  • 勒布朗(LeBlanc)法則:Later equals never(稍后等于永不).
  • 糟糕的代碼引發(fā)混亂偷办!別人修改糟糕的代碼時(shí)艰额,往往會(huì)越改越亂。
  • 整潔的代碼只做好一件事椒涯。
  • 如果同一段代碼反復(fù)出現(xiàn)柄沮,就表示某種想法未在代碼中得到良好的體現(xiàn)。
  • 如果對(duì)象功能太多废岂,最好是切分為兩個(gè)或多個(gè)對(duì)象祖搓。如果方法功能太多,那就使用抽取手段重構(gòu)之湖苞,從而得到一個(gè)能較為清晰的說(shuō)明自身功能的方法拯欧,以及另外數(shù)個(gè)說(shuō)明如何實(shí)現(xiàn)這些功能的方法。
  • 整潔代碼的方法:減少重復(fù)代碼财骨,提高表達(dá)力镐作,提早構(gòu)建簡(jiǎn)單抽象。
  • 破窗理論:環(huán)境中的不良現(xiàn)象如果被放任存在隆箩,就會(huì)誘使人們仿效该贾,甚至變本加厲。以一幢有少許破窗的建筑為例捌臊,如果那些窗不被修理好杨蛋,可能將會(huì)有破壞者破壞更多的窗戶。最終他們甚至?xí)J入建筑內(nèi)理澎,如果發(fā)現(xiàn)無(wú)人居住逞力,也許就在那里占領(lǐng)、定居或者縱火矾端。
  • 如果每次簽入時(shí)掏击,代碼都比簽出時(shí)干凈,那么代碼就不會(huì)腐壞秩铆。童子軍軍規(guī):讓營(yíng)地比你來(lái)時(shí)更干凈砚亭。

有意義的命名

  • 名副其實(shí):變量、函數(shù)或類的命名應(yīng)該已經(jīng)答復(fù)了所有的大問(wèn)題殴玛,它該告訴你捅膘,它為什么會(huì)存在,它做什么事滚粟,應(yīng)該怎么用寻仗。如果名稱需要注釋來(lái)補(bǔ)充,那就不算是名副其實(shí)凡壤。
  • 避免誤導(dǎo):避免使用與本意相悖的詞署尤。提防使用不同之處較小的名稱耙替。
  • 做有意義的區(qū)分:廢話都是冗雜。只是為滿足編譯器或解釋器的需要而寫代碼曹体,就會(huì)制造麻煩俗扇。
  • 使用讀得出來(lái)的名稱:不要命名自造詞。如果名稱讀不出來(lái)的話箕别,討論的時(shí)候就會(huì)出現(xiàn)阻礙铜幽。
  • 使用可搜索的名稱:長(zhǎng)名稱勝于短名稱,搜得到的名稱勝于用自造編碼代寫就的名稱串稀。名稱長(zhǎng)短應(yīng)與其作用域大小相對(duì)應(yīng)除抛。
  • 避免使用編碼:編碼已經(jīng)太多,無(wú)謂再自找麻煩母截,帶編碼的名稱通常不便發(fā)音到忽,而且容易打錯(cuò)。
  • 避免思維映射:不應(yīng)當(dāng)讓讀者在腦中把你的名稱翻譯為他們熟知的名稱清寇。明確才是王道绘趋。
  • 類名:類名和對(duì)象名應(yīng)該是名詞或名詞短語(yǔ),類名不應(yīng)當(dāng)是動(dòng)詞颗管。
  • 方法名:方法名應(yīng)當(dāng)是動(dòng)詞或動(dòng)詞短語(yǔ)陷遮。屬性訪問(wèn)器、修改器和斷言應(yīng)該根據(jù)其值命名垦江,并依Javabean加上get帽馋、set、is前綴比吭。
  • 別扮可愛(ài):如果名稱太耍寶绽族,那就只有同作者一般有幽默感的人才能記得住。寧可明確衩藤,毋為好玩吧慢。言到意到,意到言到赏表。
  • 每個(gè)概念對(duì)應(yīng)一個(gè)詞:給每個(gè)抽象概念選一個(gè)詞检诗,并且一以貫之。
  • 別用雙關(guān)語(yǔ):避免將同一單詞用于不同目的瓢剿,同一術(shù)語(yǔ)用于不同概念逢慌。
  • 使用解決方案領(lǐng)域名稱:依據(jù)問(wèn)題所涉領(lǐng)域來(lái)命名不是聰明的做法。
  • 使用源自所涉問(wèn)題領(lǐng)域的名稱:如果不能用程序員熟悉的術(shù)語(yǔ)來(lái)給手頭的工作命名间狂,就采用從所涉問(wèn)題領(lǐng)域而來(lái)的名稱攻泼。
  • 添加有意義的語(yǔ)境:需要用有良好命名的類、函數(shù)或名稱空間來(lái)放置名稱,給讀者提供語(yǔ)境忙菠。如果沒(méi)這么做何鸡,給名稱添加前綴是最后一招∨;叮可以添加前綴addrFirstName音比、addrLastName、addrState等氢惋,以此提供語(yǔ)境。至少稽犁,讀者會(huì)明白這些變量是某個(gè)更大結(jié)構(gòu)的一部分焰望。當(dāng)然,更好的方案是創(chuàng)建名為Address的類已亥。這樣熊赖,即便是編譯器也會(huì)知道這些變量隸屬于某個(gè)更大的概念了。
  • 不要添加沒(méi)用的語(yǔ)境:只要短名稱足夠清楚虑椎,就要比長(zhǎng)名稱好。別給名稱添加不必要的語(yǔ)境。

函數(shù)

  • 短卸浞住:if识啦、else、while語(yǔ)句等泥技,其中的代碼塊應(yīng)該只有一行浆兰。該行大抵應(yīng)該是一個(gè)函數(shù)調(diào)用語(yǔ)句。這樣不但能保持函數(shù)短小珊豹,而且簸呈,因?yàn)閴K內(nèi)調(diào)用的函數(shù)擁有較具說(shuō)明性的名稱,從而增加了文檔上的價(jià)值店茶。函數(shù)不應(yīng)該大到足以容納嵌套結(jié)構(gòu)蜕便。
  • 只做一件事:要判斷函數(shù)是否不止只做了一件事,還有一個(gè)辦法贩幻,就是看是否能再拆出一個(gè)函數(shù)轿腺,該函數(shù)不僅只是單純地詮釋其實(shí)現(xiàn)。
  • 每個(gè)函數(shù)一個(gè)抽象層級(jí):要確保函數(shù)只做一件事丛楚,函數(shù)中的語(yǔ)句都要在同一抽象層級(jí)上吃溅。程序就像是一系列TO起頭的段落,每一段都描述當(dāng)前抽象層級(jí)鸯檬,并引用位于下一抽象層級(jí)的后續(xù)TO起頭段落决侈。讓代碼讀起來(lái)像是一系列自頂向下的TO起頭段落是保持抽象層級(jí)協(xié)調(diào)一致的有效技巧。
  • 使用描述性的名稱:長(zhǎng)而具有描述性的名稱,要比短而令人費(fèi)解的名稱好赖歌,比描述性的長(zhǎng)注釋好枉圃。
  • 函數(shù)參數(shù):最理想的參數(shù)數(shù)量是零,即無(wú)參庐冯,然后是一孽亲、二,最好不用三個(gè)參展父。如果函數(shù)看來(lái)需要兩個(gè)返劲、三個(gè)或更多參數(shù),就說(shuō)明其中一些參數(shù)應(yīng)該封裝為類了栖茉。對(duì)于一元函數(shù)篮绿,函數(shù)和參數(shù)應(yīng)當(dāng)形成一種良好的動(dòng)詞/名詞對(duì)形式。
  • 無(wú)副作用:參數(shù)多數(shù)會(huì)被自然而然地看作是函數(shù)的輸入吕漂。普遍而言亲配,應(yīng)避免使用輸出函數(shù)。如果函數(shù)必須要修改某種狀態(tài)惶凝,就修改所屬對(duì)象的狀態(tài)吧吼虎。
  • 分隔指令與詢問(wèn)
  • 使用異常替代返回錯(cuò)誤碼:如果使用異常替代返回錯(cuò)誤碼,錯(cuò)誤處理代碼就能從主路徑代碼中分離出來(lái)苍鲜。try…catch代碼塊搞亂了代碼結(jié)構(gòu)思灰,把錯(cuò)誤處理與正常流程混為一談,最好把try和catch代碼塊的主體部分抽離出來(lái)混滔,另外形成函數(shù)官辈。error.java依賴磁鐵,當(dāng)error枚舉修改時(shí)遍坟,所有這些其他的類都需要重新編譯和部署拳亿,使用異常代替錯(cuò)誤碼,新異常就可以從異常類派生出來(lái)愿伴,無(wú)需重新編譯和重新部署肺魁。
  • 別重復(fù)自己:重復(fù)會(huì)使代碼顯得臃腫,而且不易改動(dòng)隔节。重復(fù)可能是所有軟件中一切邪惡的根源鹅经,許多原則與實(shí)踐規(guī)則都是為控制與消除重復(fù)而創(chuàng)建。
  • 結(jié)構(gòu)化編程:只要函數(shù)保持短小怎诫,偶爾出現(xiàn)的return瘾晃、break或continue語(yǔ)句沒(méi)有壞處,甚至還比單入單出原則更具有表達(dá)力幻妓。另外蹦误,goto只在大函數(shù)中才有道理,所以應(yīng)該盡量避免使用。

注釋

  • 注釋的恰當(dāng)用法是彌補(bǔ)我們?cè)谟么a表達(dá)意圖時(shí)遭遇的失敗强胰。每次用代碼表達(dá)舱沧,都該夸獎(jiǎng)自己一下。每次寫注釋偶洋,都該做個(gè)鬼臉熟吏,感受自己在表達(dá)能力上的失敗。真是只在一處地方有:代碼玄窝。只有代碼能忠實(shí)地告訴你它所做的事牵寺。那是唯一真正準(zhǔn)確的信息來(lái)源。
  • 注釋不能美化糟糕的代碼:與其花時(shí)間編寫解釋你搞出的糟糕的代碼的注釋恩脂,不如花時(shí)間清潔那堆糟糕的代碼帽氓。
  • 好注釋:有些注釋是必須的,也是有利的东亦。1) 法律信息:公司代碼規(guī)范要求編寫與法律有關(guān)的注釋。這類注釋不應(yīng)是合同或法典唬渗。只要有可能典阵,就指向一份標(biāo)準(zhǔn)許可或其他外部文檔,而不要把所有條款放到注釋中镊逝。 2)提供信息的注釋:若注釋用來(lái)提供基本信息也是好的壮啊。 3) 對(duì)意圖的解釋:注釋不僅提供了有關(guān)實(shí)現(xiàn)的有用信息,而且還提供了某個(gè)決定后面的意圖撑蒜。 4) 闡釋:注釋把某些晦澀難明的參數(shù)或返回值的意義翻譯為某種可讀形式歹啼。通常,更好的辦法是盡量讓參數(shù)或返回值自身就足夠清楚座菠;但如果參數(shù)或返回值是某個(gè)標(biāo)準(zhǔn)庫(kù)的一部分狸眼,或是你不能修改代碼,幫助闡釋其含義的代碼就會(huì)有用浴滴。寫這類注釋回冒著闡述性注釋本身就不正確的風(fēng)險(xiǎn)拓萌。 5) 警示:用于警告其他程序員會(huì)出現(xiàn)某種后果的注釋也是有用的。 6) TODO注釋:TODO是一種程序員認(rèn)為應(yīng)該做升略,但由于某些原因目前還沒(méi)做的工作微王。無(wú)論TODO的目的如何,它都不是在系統(tǒng)中留下糟糕代碼的借口品嚣。你不會(huì)愿意代碼因?yàn)門ODO的存在而變成一堆垃圾炕倘,所以要定期查看,刪除不再需要的翰撑。 7)放大:注釋可以用來(lái)放大某種看來(lái)不合理之物的重要性罩旋。 8) 公共API中的Javadoc:沒(méi)有什么比被良好描述的公共API更有用和令人滿意的了,標(biāo)準(zhǔn)java庫(kù)中的Javadoc就是一例。但是瘸恼,就像其它注釋一樣劣挫,Javadoc也可能誤導(dǎo)、不適用或者提供錯(cuò)誤信息东帅。
  • 壞注釋:壞注釋都是糟糕的代碼的支撐或借口压固,或者對(duì)錯(cuò)誤決策的修正。 1) 喃喃自語(yǔ):如果只是因?yàn)槟阌X(jué)得或者因?yàn)檫^(guò)程需要就添加注釋靠闭,那就是無(wú)畏之舉帐我。如果你決定寫注釋,就要花必要的時(shí)間確保寫出最好的注釋愧膀。我們唯有檢視系統(tǒng)其他部分的代碼拦键,弄清事情原委。任何迫使讀者查看其他模塊的注釋都沒(méi)能與讀者溝通好檩淋,不值所費(fèi)芬为。 2) 多余的注釋:多余的代碼并不能比代碼本身提供更多的信息。它沒(méi)有證明代碼的意義蟀悦,也沒(méi)有給出代碼的意圖和邏輯媚朦。讀它并不比讀代碼更容易。 3) 誤導(dǎo)性注釋:不夠精確的注釋會(huì)誤導(dǎo)讀者日戈。 4) 循規(guī)式注釋:所謂每個(gè)函數(shù)都要有Javadoc或每個(gè)變量都要有注釋的規(guī)矩全然是愚蠢可笑的询张。這類注釋突然讓代碼變得散亂,滿口胡言浙炼,令人迷惑不解份氧。 5) 日志式注釋:有人會(huì)在每次編輯代碼時(shí),在模塊開(kāi)始處添加一條注釋弯屈,這類注釋就像是一種記錄每次修改的日志蜗帜。這種冗雜的記錄只會(huì)讓模塊變得凌亂不堪,應(yīng)當(dāng)全部刪除资厉。 5) 廢話注釋:對(duì)于顯然之事喋喋不休钮糖,毫無(wú)新意。 6) 能用函數(shù)或變量時(shí)就別用注釋酌住。 7) 位置標(biāo)記:如果標(biāo)記欄不多店归,就會(huì)顯而易見(jiàn)。所以酪我,盡量少用標(biāo)記欄消痛,只在特別有價(jià)值的時(shí)候用。 8) 括號(hào)后面的注釋:這對(duì)于含有深度嵌套結(jié)構(gòu)的長(zhǎng)函數(shù)可能有意義都哭,但只會(huì)給我們更愿意編寫的短小秩伞、封裝的函數(shù)帶來(lái)混亂逞带。如果你發(fā)現(xiàn)自己想標(biāo)記右括號(hào),其實(shí)應(yīng)該做的是縮短函數(shù)纱新。 9) 歸屬與署名 10) 注釋掉的代碼:直接把代碼注釋掉是討厭的做法展氓。不用的代碼直接刪掉即可。 11) HTML注釋:如果注釋將由某種工具(例如Javadoc)抽取出來(lái)脸爱,呈現(xiàn)到網(wǎng)頁(yè)遇汞,那么該是工具而非程序員來(lái)負(fù)責(zé)給注釋加上合適的HTML標(biāo)簽。 12) 非本地信息:假如你一定要寫注釋簿废,請(qǐng)確保他描述了離他最近的代碼空入。別在本地注釋的上下文環(huán)境中給出系統(tǒng)級(jí)的信息。 13) 信息過(guò)多:別在注釋中添加有趣的歷史性話題或者無(wú)關(guān)的細(xì)節(jié)描述族檬。 14) 不明顯的聯(lián)系:注釋及其描述的代碼之間的聯(lián)系應(yīng)該顯而易見(jiàn)歪赢,如果你不嫌麻煩要寫注釋,至少讓讀者能看著注釋和代碼单料,并且理解注釋所談何物埋凯。注釋的作用是解釋未能自行解釋的代碼,如果注釋本身還需要解釋扫尖,就太遺憾了白对。 15) 函數(shù)頭:短函數(shù)不需要太多描述,為只做一件事的短函數(shù)選個(gè)好名字藏斩,通常要比寫函數(shù)頭注釋要好躏结。 16) 非公共代碼中的Javadoc:javadoc對(duì)于公共的API非常有用却盘,但對(duì)于不打算成為公共用途的代碼就令人厭惡狰域。

格式

  • 格式的目的:或許你認(rèn)為“讓代碼能工作”是專業(yè)開(kāi)發(fā)者的頭等大事,然而黄橘,溝通才是兆览,而代碼格式就關(guān)乎溝通。
  • 垂直格式:短文件比長(zhǎng)文件易于理解塞关。 1) 向報(bào)紙學(xué)習(xí):名稱應(yīng)當(dāng)簡(jiǎn)單且一目了然抬探,名稱本身應(yīng)該足夠告訴我們是否在正確的模塊中。源文件最頂部應(yīng)該給出高層次概念和算法帆赢。細(xì)節(jié)應(yīng)該往下漸次展開(kāi)小压,直至找到源文件中最底層的函數(shù)和細(xì)節(jié)。 2) 概念間垂直方向上的區(qū)隔:幾乎所有的代碼都是從上往下讀椰于,從左往右讀怠益。每行展現(xiàn)一個(gè)表達(dá)式或一個(gè)子句,每組代碼行展示一條完整的思路瘾婿。這些思路用空白行區(qū)隔開(kāi)來(lái)蜻牢。 3) 垂直方向上的靠近:如果說(shuō)空白行隔開(kāi)了概念烤咧,靠近的代碼行則暗示了他們之間的緊密關(guān)系。 4) 垂直距離:變量聲明應(yīng)盡可能靠近其使用位置抢呆。實(shí)體變量應(yīng)該在類的頂部聲明煮嫌。相關(guān)函數(shù),若某個(gè)函數(shù)調(diào)用了另外一個(gè)抱虐,就應(yīng)該把他們放到一起昌阿,而且調(diào)用者應(yīng)該盡可能放在被調(diào)用者上面。概念相關(guān)梯码,概念相關(guān)的代碼應(yīng)該放到一起宝泵,相關(guān)性越強(qiáng),彼此之間的距離就該越短轩娶。
  • 橫向格式:一行代碼最好不要超過(guò)120個(gè)字符儿奶。 1) 水平方向上的區(qū)隔和靠近:賦值操作符的周圍加上空格,以此達(dá)到強(qiáng)調(diào)的目的鳄抒。函數(shù)名和左圓括號(hào)之間不加空格闯捎,這是因?yàn)楹瘮?shù)與其參數(shù)密切相關(guān),如果隔開(kāi)许溅,就會(huì)顯得互無(wú)關(guān)系瓤鼻。函數(shù)調(diào)用括號(hào)中的參數(shù)用空格隔開(kāi)。乘法因子之間不加空格贤重,因?yàn)樗麄兙哂休^高的優(yōu)先級(jí)茬祷,加減法運(yùn)算項(xiàng)之間用空格隔開(kāi),因?yàn)榧訙p法優(yōu)先級(jí)較低并蝗。 2) 水平對(duì)齊:這種對(duì)齊沒(méi)什么用祭犯,像是在強(qiáng)調(diào)不重要的東西,把讀者的眼光從真正的意義上拉開(kāi)滚停。如果有較長(zhǎng)的列表需要做對(duì)齊處理沃粗,那問(wèn)題就是在列表的長(zhǎng)度上而不是對(duì)齊上。 3) 縮進(jìn):源文件是一種繼承結(jié)構(gòu)键畴,而不是一種大綱結(jié)構(gòu)最盅。這種繼承結(jié)構(gòu)中的每一層級(jí)都圈出了一個(gè)范圍,名稱可以在其中聲明起惕,而聲明和執(zhí)行語(yǔ)句也可以在其中解釋涡贱。要讓這種范圍式繼承結(jié)構(gòu)可見(jiàn),我們依源代碼行在繼承結(jié)構(gòu)中的位置對(duì)源代碼行做縮進(jìn)處理惹想。 4) 空范圍:有時(shí)问词,while和for語(yǔ)句的語(yǔ)句體為空,但也要確保范圍體的縮進(jìn)勺馆。
  • 團(tuán)隊(duì)規(guī)則:每個(gè)程序員都有自己喜歡的格式規(guī)則戏售,但如果在一個(gè)團(tuán)隊(duì)中工作侨核,就是團(tuán)隊(duì)說(shuō)了算。一組開(kāi)發(fā)者應(yīng)當(dāng)認(rèn)同一種格式風(fēng)格灌灾,每個(gè)成員都應(yīng)該采用那種風(fēng)格搓译。

對(duì)象和數(shù)據(jù)結(jié)構(gòu)

  • 數(shù)據(jù)抽象:隱藏實(shí)現(xiàn)并非只是在變量之間放上一個(gè)函數(shù)層那么簡(jiǎn)單。隱藏實(shí)現(xiàn)關(guān)乎抽象锋喜!類并不簡(jiǎn)單地用取值器和賦值器將其變量推向外間些己,而是曝露抽象接口,以便用戶無(wú)需了解數(shù)據(jù)的實(shí)現(xiàn)就能操作數(shù)據(jù)本體嘿般。我們不愿曝露數(shù)據(jù)細(xì)節(jié)段标,更愿意以抽象形態(tài)表述數(shù)據(jù)。
  • 數(shù)據(jù)炉奴、對(duì)象的反對(duì)稱性:1) 過(guò)程式代碼(使用數(shù)據(jù)結(jié)構(gòu)的代碼)便于在不改動(dòng)既有數(shù)據(jù)結(jié)構(gòu)的前提下添加新函數(shù)逼庞。面向?qū)ο蟠a便于在不改動(dòng)既有函數(shù)的前提下添加新類。 2) 在任何一個(gè)復(fù)雜系統(tǒng)中瞻赶,都會(huì)有需要添加新數(shù)據(jù)類型而不是新函數(shù)的時(shí)候赛糟。這時(shí),對(duì)象和面向?qū)ο缶捅容^適合砸逊。另一方面璧南,也會(huì)有想要添加新函數(shù)而不是數(shù)據(jù)類型的時(shí)候。在這種情況下师逸,過(guò)程式代碼和數(shù)據(jù)結(jié)構(gòu)更合適司倚。 3) 一切都是對(duì)象只是一個(gè)傳說(shuō),有時(shí)候你真的想要在簡(jiǎn)單數(shù)據(jù)結(jié)構(gòu)上做一些過(guò)程式的操作篓像。 4) 對(duì)象與數(shù)據(jù)結(jié)構(gòu)之間的差異动知。對(duì)象把數(shù)據(jù)隱藏于抽象之后,曝露操作數(shù)據(jù)的函數(shù)遗淳。數(shù)據(jù)結(jié)構(gòu)曝露其數(shù)據(jù)拍柒,沒(méi)有提供有意義的函數(shù)心傀。5) 過(guò)程式形狀代碼:
    20170905221832670.jpg
    多態(tài)式形狀:
    20170905221833078.jpg
  • 得墨忒耳律:模塊不應(yīng)了解它所操作對(duì)象的內(nèi)部情形屈暗。更準(zhǔn)確的說(shuō),得墨忒耳律認(rèn)為脂男,類C的方法f只應(yīng)該調(diào)用以下對(duì)象的方法:a. 類C b. 由f創(chuàng)建的對(duì)象 c. 作為參數(shù)傳遞給f的對(duì)象 d. 由C的實(shí)體變量持有的對(duì)象养叛。方法不應(yīng)調(diào)用由任何函數(shù)返回的對(duì)象的方法,換句話說(shuō)就是宰翅,只跟朋友談話弃甥,不與陌生人談話。 1) 火車失事:這類代碼常被稱作火車失事汁讼,因?yàn)樗雌饋?lái)就像是一列火車淆攻。 2) 混雜:這種混淆有時(shí)會(huì)不幸導(dǎo)致混合結(jié)構(gòu)阔墩,一半是對(duì)象,一半是數(shù)據(jù)結(jié)構(gòu)瓶珊。這種結(jié)構(gòu)擁有執(zhí)行操作的函數(shù)啸箫,也有公共變量或公共訪問(wèn)器及改值器。 3) 隱藏結(jié)構(gòu)
  • 數(shù)據(jù)傳送對(duì)象:最為精煉的數(shù)據(jù)結(jié)構(gòu)伞芹,是一個(gè)只有公共變量忘苛、沒(méi)有函數(shù)的類。這種數(shù)據(jù)結(jié)構(gòu)有時(shí)候被稱為數(shù)據(jù)傳送對(duì)象唱较,或DTO(Data Transfer Objects)扎唾。DTO是非常有用的結(jié)構(gòu),尤其是在與數(shù)據(jù)庫(kù)通信南缓、或解析套接字傳遞的消息之類場(chǎng)景中胸遇。

錯(cuò)誤處理

  • 錯(cuò)誤處理很重要,但如果他搞亂了代碼邏輯汉形,就是錯(cuò)誤的做法狐榔。
  • 使用異常而非返回碼:設(shè)置一個(gè)錯(cuò)誤標(biāo)識(shí),或者返回給調(diào)用者檢查的錯(cuò)誤碼获雕,它們搞亂了調(diào)用者代碼薄腻。調(diào)用者必須在調(diào)用之后即刻檢查錯(cuò)誤。不幸的是届案,這個(gè)步驟很容易被遺忘庵楷。所以,遇到問(wèn)題時(shí)楣颠,最好拋出一個(gè)異常尽纽。調(diào)用代碼很整潔,其邏輯不會(huì)被錯(cuò)誤處理搞亂童漩。
  • 先寫try-catch-finally語(yǔ)句:異常的妙處之一是弄贿,它們?cè)诔绦蛑卸x了一個(gè)范圍。
  • 使用不可控異常:可控異常的代價(jià)就是違反開(kāi)放/閉合原則矫膨。如果你在方法中拋出可控異常差凹,而catch語(yǔ)句在三個(gè)層級(jí)之上,你就得在catch語(yǔ)句和拋出異常處之間的每個(gè)方法簽名中聲明該異常侧馅。
  • 給出異常發(fā)生的環(huán)境說(shuō)明:你拋出的每個(gè)異常危尿,都應(yīng)當(dāng)提供足夠的環(huán)境說(shuō)明,以便判斷錯(cuò)誤的來(lái)源和處所馁痴。在java中谊娇,你可以從任何異常里得到堆棧蹤跡(stack trace);然而罗晕,堆棧蹤跡卻無(wú)法告訴你該失敗操作的初衷济欢。應(yīng)創(chuàng)建信息充分的錯(cuò)誤信息赠堵,并和異常一起傳遞出去。在消息中法褥,包括失敗的操作和失敗類型顾腊。
  • 依調(diào)用者需要定義異常類:當(dāng)我們?cè)趹?yīng)用程序中定義異常類時(shí),最重要的考慮應(yīng)該是它們?nèi)绾伪徊东@挖胃。對(duì)于代碼的某個(gè)特定區(qū)域杂靶,單一異常類通常可行酱鸭。伴隨異常發(fā)送出來(lái)的信息能夠區(qū)分不同錯(cuò)誤吗垮。如果你想要捕獲某個(gè)異常,并且放過(guò)其他異常凹髓,就使用不同的異常類烁登。
  • 定義常規(guī)流程:創(chuàng)建一個(gè)類或配置一個(gè)對(duì)象,用來(lái)處理特例蔚舀。你來(lái)處理特例饵沧,客戶代碼就不用應(yīng)付異常行為了。異常行為被封裝到特例對(duì)象中赌躺。
  • 別返回null值:返回null值狼牺,基本上是在給自己增加工作量,也是在給調(diào)用者添亂礼患。只要有一處沒(méi)檢查null值是钥,應(yīng)用程序就會(huì)失控。如果你打算在方法中返回null值缅叠,不如拋出異常悄泥,或是返回特例對(duì)象。如果你在調(diào)用某個(gè)第三方API中可能返回null值的方法肤粱,可以考慮用新方法打包這個(gè)方法弹囚,在新方法中拋出異常或返回特例對(duì)象领曼。
  • 別傳遞null值:在方法中返回null值是糟糕的做法鸥鹉,但將null值傳遞給其他方法就更糟糕了。除非API要求你向他傳遞null值悯森,否則就要盡可能避免傳遞null值宋舷。

邊界

單元測(cè)試

  • TDD三定律:1) You must write a failing unit test before you write production code. ——編寫生產(chǎn)代碼前先寫單元測(cè)試 2) You must stop writing that unit test as soon as it fails; and not compiling is failing. ——測(cè)試一旦失敗绪撵,開(kāi)始寫生產(chǎn)代碼 3) You must stop writing production code as soon as the currently failing test passes. ——老測(cè)試一旦通過(guò)瓢姻,返回寫新測(cè)試。
  • 保持測(cè)試整潔:測(cè)試代碼和生產(chǎn)代碼一樣重要音诈。他可不是二等公民幻碱,他需要被思考绎狭,被設(shè)計(jì)和被照料,他該像生產(chǎn)代碼一般保持整潔褥傍。單元測(cè)試讓你的代碼可擴(kuò)展儡嘶、可維護(hù)、可復(fù)用恍风。有了測(cè)試蹦狂,你就不擔(dān)心對(duì)代碼的修改,沒(méi)有測(cè)試朋贬,每次修改都可能帶來(lái)缺陷凯楔。測(cè)試越臟,代碼就會(huì)變得越臟锦募,最終摆屯,你丟了測(cè)試,代碼開(kāi)始腐壞糠亩∨捌铮總而言之,因?yàn)闇y(cè)試赎线,使改動(dòng)變的可能廷没。
  • 整潔的測(cè)試:測(cè)試如何才能做到可讀?和其他代碼一樣:明確垂寥、簡(jiǎn)潔腕柜、還有足夠的表達(dá)力。 1) 面向特定領(lǐng)域的測(cè)試語(yǔ)言 2) 雙重標(biāo)準(zhǔn)
  • 每個(gè)測(cè)試一個(gè)斷言:JUnit中每個(gè)測(cè)試函數(shù)都應(yīng)該有且只有一個(gè)斷言語(yǔ)句矫废。最好的說(shuō)法是單個(gè)測(cè)試中的斷言數(shù)量應(yīng)該最小化盏缤。最佳規(guī)則也許是應(yīng)該盡可能減少每個(gè)概念的斷言數(shù)量,每個(gè)測(cè)試函數(shù)只測(cè)試一個(gè)概念蓖扑。
  • F.I.R.S.T.:整潔的代碼應(yīng)該遵循5條規(guī)則 1) 快速(Fast):測(cè)試應(yīng)該能快速運(yùn)行唉铜,否則你就不會(huì)想使用它 2) 獨(dú)立(Independent):測(cè)試應(yīng)該相互獨(dú)立,某個(gè)測(cè)試不應(yīng)為下一個(gè)測(cè)試設(shè)定條件律杠。 3) 可重復(fù)(Repeatable):測(cè)試應(yīng)當(dāng)可在任何環(huán)境中重復(fù)通過(guò)潭流。 4) 自足驗(yàn)證(Self-Validating):測(cè)試應(yīng)該有布爾值輸出。無(wú)論是通過(guò)還是失敗柜去,你不應(yīng)該查看日志文件來(lái)確認(rèn)測(cè)試是否通過(guò)灰嫉。 5) 及時(shí)(Timely):?jiǎn)卧獪y(cè)試應(yīng)恰好在使其通過(guò)的生產(chǎn)代碼之前編寫。如果在編寫代碼之后嗓奢,你會(huì)發(fā)現(xiàn)生產(chǎn)代碼難以測(cè)試讼撒。

  • 類的組織:遵循標(biāo)準(zhǔn)的java約定,類應(yīng)該從一組變量列表開(kāi)始。顯示公共靜態(tài)常量根盒,然后是私有靜態(tài)變量钳幅,以及私有實(shí)體變量,很少會(huì)有公共變量炎滞。公共函數(shù)應(yīng)跟在變量列表之后敢艰。我們喜歡把由某個(gè)公共函數(shù)調(diào)用的私有工具函數(shù)緊隨在該公共函數(shù)后面。我們喜歡保持變量和工具函數(shù)的私有性册赛,但有時(shí)钠导,我們也需要用到受護(hù)變量或工具函數(shù),好讓測(cè)試可以訪問(wèn)到森瘪。
  • 類應(yīng)該短斜菜:對(duì)于函數(shù),我們通過(guò)計(jì)算代碼行數(shù)衡量大小柜砾。對(duì)于類湃望,我們通過(guò)計(jì)算權(quán)責(zé)來(lái)衡量。類的名稱應(yīng)當(dāng)描述其權(quán)責(zé)痰驱,實(shí)際上证芭,命名正是幫助判斷類的長(zhǎng)度的第一個(gè)手段。類名越含混担映,該類越可能擁有過(guò)多權(quán)責(zé)废士。 1) 單一權(quán)責(zé)原則(SRP):類或模塊應(yīng)有且只有一條加以修改的理由。分而治之蝇完,其在編程行為中的重要程度等同于在程序中的重要程度官硝。在強(qiáng)調(diào)一下,系統(tǒng)應(yīng)該由許多短小的類而不是少量巨大的類組成短蜕。每個(gè)小類封裝一個(gè)權(quán)責(zé)氢架,只有一個(gè)修改的原因,并與少數(shù)其他類一起協(xié)同達(dá)成期望的系統(tǒng)行為朋魔。 2) 內(nèi)聚:類中的每個(gè)方法都應(yīng)該操作一個(gè)或多個(gè)這種變量岖研。如果一個(gè)類中的每個(gè)變量都被每個(gè)方法所使用,則該類具有最大的內(nèi)聚性警检。 3) 保持內(nèi)聚性就會(huì)得到許多短小的類:如果有些函數(shù)想要共享某些變量孙援,為什么不讓他們擁有自己的類呢?當(dāng)類喪失了內(nèi)聚性扇雕,就拆分他拓售!
  • 為了修改而組織:每處修改都讓我們冒著系統(tǒng)其他部分不能如期望般工作的風(fēng)險(xiǎn)。在整潔的系統(tǒng)中镶奉,我們對(duì)類加以組織础淤,以降低修改的風(fēng)險(xiǎn)崭放。我們希望將系統(tǒng)打造成在添加或修改特性時(shí)盡可能少惹麻煩的架子。在理想系統(tǒng)中值骇,我們通過(guò)擴(kuò)展系統(tǒng)而非修改現(xiàn)有代碼來(lái)添加新特性莹菱。隔離修改:具體類包含實(shí)現(xiàn)細(xì)節(jié)(代碼)移国,而抽象類則只呈現(xiàn)概念吱瘩。依賴于具體細(xì)節(jié)的客戶類,當(dāng)細(xì)節(jié)改變時(shí)迹缀,就會(huì)有風(fēng)險(xiǎn)使碾。我們可以借助接口和抽象類來(lái)隔離這些細(xì)節(jié)帶來(lái)的影響。

系統(tǒng)

  • 將系統(tǒng)的構(gòu)造與使用分開(kāi):首先祝懂,構(gòu)造和使用是非常不一樣的過(guò)程票摇。軟件系統(tǒng)應(yīng)將啟始過(guò)程和啟始過(guò)程之后的運(yùn)行時(shí)邏輯分開(kāi),在啟始過(guò)程中構(gòu)建應(yīng)用對(duì)象砚蓬,也會(huì)存在互相纏結(jié)的依賴關(guān)系矢门。 1) 分解main:將全部構(gòu)造過(guò)程搬遷到main或被稱之為main的模塊中。 2) 工廠:有時(shí)應(yīng)用程序也要負(fù)責(zé)確定何時(shí)創(chuàng)建對(duì)象灰蛙,這種情況下祟剔,我們可以使用抽象工廠模式。 3) 依賴注入:依賴注入可以實(shí)現(xiàn)分離構(gòu)造和使用摩梧,控制反轉(zhuǎn)在依賴管理中的一種應(yīng)用手段物延。
  • 擴(kuò)容:“一開(kāi)始就做對(duì)系統(tǒng)”純屬神話。反之仅父,我們應(yīng)該只去實(shí)現(xiàn)今天的用戶故事叛薯,然后重構(gòu),明天再擴(kuò)展系統(tǒng)笙纤、實(shí)現(xiàn)新的用戶故事耗溜。這就是迭代和增量敏捷的精髓所在。
  • Java代理:
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末省容,一起剝皮案震驚了整個(gè)濱河市强霎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蓉冈,老刑警劉巖城舞,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異寞酿,居然都是意外死亡家夺,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門伐弹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)拉馋,“玉大人,你說(shuō)我怎么就攤上這事』蛙睿” “怎么了随闺?”我有些...
    開(kāi)封第一講書人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蔓腐。 經(jīng)常有香客問(wèn)我矩乐,道長(zhǎng),這世上最難降的妖魔是什么回论? 我笑而不...
    開(kāi)封第一講書人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任散罕,我火速辦了婚禮,結(jié)果婚禮上傀蓉,老公的妹妹穿的比我還像新娘欧漱。我一直安慰自己,他們只是感情好葬燎,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布误甚。 她就那樣靜靜地躺著,像睡著了一般谱净。 火紅的嫁衣襯著肌膚如雪窑邦。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 52,682評(píng)論 1 312
  • 那天岳遥,我揣著相機(jī)與錄音奕翔,去河邊找鬼。 笑死浩蓉,一個(gè)胖子當(dāng)著我的面吹牛派继,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播捻艳,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼驾窟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了认轨?” 一聲冷哼從身側(cè)響起绅络,我...
    開(kāi)封第一講書人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嘁字,沒(méi)想到半個(gè)月后恩急,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡纪蜒,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年衷恭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纯续。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡随珠,死狀恐怖灭袁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情窗看,我是刑警寧澤茸歧,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站显沈,受9級(jí)特大地震影響软瞎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜构罗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一铜涉、第九天 我趴在偏房一處隱蔽的房頂上張望智玻。 院中可真熱鬧遂唧,春花似錦、人聲如沸吊奢。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)页滚。三九已至召边,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間裹驰,已是汗流浹背隧熙。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留幻林,地道東北人贞盯。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像沪饺,于是被迫代替她去往敵國(guó)和親躏敢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理整葡,服務(wù)發(fā)現(xiàn)件余,斷路器,智...
    卡卡羅2017閱讀 134,715評(píng)論 18 139
  • 前言 最近在團(tuán)隊(duì)推行Code Review遭居,遇到一個(gè)頭痛的問(wèn)題啼器。當(dāng)向伙伴的代碼提一個(gè)comment時(shí),他們不解為什...
    CatchZeng閱讀 5,177評(píng)論 1 19
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,321評(píng)論 25 707
  • 無(wú)常是為了什么存在 有一天你突然發(fā)現(xiàn) 時(shí)間不再有長(zhǎng)短 那時(shí)的你 會(huì)不會(huì)突然想起 這時(shí)的我 也許 我真的會(huì)死掉 在某...
    五色浮元子_閱讀 165評(píng)論 0 0
  • 日子過(guò)得越發(fā)無(wú)聊俱萍,回過(guò)頭我才發(fā)現(xiàn)自己還是想好好畫畫的
    嘿小明兒閱讀 167評(píng)論 0 5