《程序員修煉之道 - 從小工到專家》讀書筆記
本篇文章是對《程序員修煉之道 - 從小工到專家》一書的總結(jié)和解讀。該書作者是 Andrew Hunt 和 David Thomas。他們都是敏捷宣言的17個(gè)創(chuàng)始者之一。Andrew還是敏捷聯(lián)盟(Agile Alliance)的創(chuàng)始人。David 則是著名的 DRY(Don't Repease Yourself) 一詞的發(fā)明者。這本書也廣泛出現(xiàn)在各類計(jì)算機(jī)推薦書單之中,其受歡迎程度不言自明。
該書目前有兩個(gè)版本,我閱讀的是第一版:

第二版是這樣的:

兩版內(nèi)容稍有不同。
剛畢業(yè)那會讀過一遍,但有很多地方?jīng)]看明白,感覺云里霧里的。今年在制定每天的閱讀分享計(jì)劃時(shí)一下就想到了它,結(jié)合一定的工作經(jīng)驗(yàn)再次閱讀這本書,然后對每個(gè)章節(jié)都進(jìn)行思考和總結(jié),感覺才算是挖掘出了它的價(jià)值。這本書寫作時(shí)間雖然比較久了(初版1999年),里面引用的一些語言,一些技術(shù)框架都已經(jīng)很少使用甚至過時(shí)了,但本書強(qiáng)調(diào)的如何做一名注重實(shí)效的程序員,及眾多建議卻不會過時(shí)。
以下內(nèi)容是對各個(gè)章節(jié)的總結(jié),篇幅有些長,12000+ 字,大家可以按順序或者按自己感興趣的章節(jié)進(jìn)行閱讀。
第一節(jié):我的源碼讓貓給吃了。
1、開發(fā)過程中出現(xiàn)未曾預(yù)料的技術(shù)問題,交付晚了等情況,沒關(guān)系,這些是無法避免的。發(fā)生了,我們就要盡可能想方設(shè)法地職業(yè)的去處理它們。程序員這個(gè)職業(yè)需要誠實(shí)和坦率,要敢于承認(rèn)自己的錯(cuò)誤。
2、要對擔(dān)負(fù)的東西負(fù)責(zé),如果某些東西真的超出了你的控制范圍可以不處理,需要盡早提出這個(gè)不可控的點(diǎn)。自己職責(zé)所在的事情就需要為其結(jié)果負(fù)責(zé)。當(dāng)結(jié)果不達(dá)標(biāo),比如磁盤垮了,但你卻沒有備份代碼,那這就是你的錯(cuò)。不要為出錯(cuò)的情況找借口,想老板說"我的源碼讓貓給吃了”,對問題沒有任何幫助,而要向他們提供可行的解決方案,做什么能夠最大的挽回局面。
第二節(jié):軟件的熵
1、熵是一個(gè)熱力學(xué)概念,指的是在某個(gè)系統(tǒng)中的“無序”的總量,熱力學(xué)定律指出宇宙中的熵總是傾向于最大化。軟件工程里中也存在這么一個(gè)定律,工程越龐大,代碼的“無序”狀態(tài)越嚴(yán)重。
2、破窗理論指出,當(dāng)一個(gè)東西本身就破舊時(shí),不但沒人愛惜,還會朝他仍石頭,導(dǎo)致更多破窗。軟件開發(fā)中也一樣,如果我們項(xiàng)目留有很多“破窗戶”(低劣的設(shè)計(jì)、錯(cuò)誤的決策、糟糕的代碼),之后接手的人也會傾向于是它變得更糟糕。如果代碼很漂亮,你自己以及之后接手的人,都可能會格外注意,不把它弄臟的。所以我們應(yīng)該盡早處理工程中遺留的問題。
第三節(jié):石頭湯和煮青蛙
1、三個(gè)士兵返鄉(xiāng),路上餓了,路過一個(gè)村子,想跟村民借點(diǎn)吃的,但村民糧食貧乏不愿意出借。士兵們沒有氣餒,他們煮開了一鍋水,往里面放了幾塊石頭。村民好奇為他們在干嘛,士兵解釋,這叫石頭湯,如果能放點(diǎn)胡蘿卜的話會更好喝。村民跑回家拿來了胡蘿卜,士兵說如果放些土豆會更美味,又有人跑回家?guī)砹送炼埂:竺嬗钟腥思恿藙e的東西,最后士兵和大家一起吃了一頓飽飯。
2、有時(shí)候你確切的知道自己需要什么以及怎么做,但請求許可這件事往往會遭遇拖延和漠然,每個(gè)人都會護(hù)衛(wèi)他們自己的資源,這讓事情變得復(fù)雜,這叫“啟動(dòng)雜役”(start-up fatigue)。這時(shí)候我們不應(yīng)該等著所有事情都準(zhǔn)備好,而應(yīng)該先拿出“石頭”煮起來,就是想讓事情啟動(dòng)起來。只要是有益的事情,你把做出的一部分結(jié)果拿給別人看,然后告訴他們?nèi)绻拥膭e的什么會更好,大家一般都會幫忙的。
第四節(jié):足夠好的軟件
1、使質(zhì)量成為需求問題。很多時(shí)候?qū)τ谫|(zhì)量的評估都是開發(fā)人員在進(jìn)行,我們對質(zhì)量要求低,交付時(shí)會出現(xiàn)很多問題,我們對質(zhì)量要求高,會很大程度延誤工期。所以指定需求時(shí),把質(zhì)量這一塊考慮進(jìn)去,在商定的時(shí)間內(nèi),由產(chǎn)品或者客戶決定他們可以接受的質(zhì)量是什么樣的。
2、沒有完美的軟件,應(yīng)該知道何時(shí)止步。今天了不起的軟件常常比明天的完美軟件更可取。及早讓客戶使用,他們的反饋常常會把你引向更好的解決方案。
第五節(jié):你的知識資產(chǎn)
1、本杰明·富蘭克林說過:知識上的投資總能得到最好的回報(bào)。這沒問題,但遺憾的是知識是有時(shí)效的資產(chǎn),特別是計(jì)算機(jī)領(lǐng)域。我們可以把我們了解的技術(shù)實(shí)現(xiàn)、工作經(jīng)驗(yàn)視為知識資產(chǎn),并使用管理金融資產(chǎn)的形式管理這些知識。
2、經(jīng)營知識資產(chǎn)可以從以下方面進(jìn)行:
定期投資:定期投入時(shí)間學(xué)習(xí),即使很小的投資也是很重要的。 多元化:作為底線我們需要對當(dāng)前所從事的技術(shù)熟練掌握。但不要就此止步,技術(shù)的發(fā)展變化很快,掌握的知識越多,就越能更好的進(jìn)行調(diào)整,趕上變化。 管理風(fēng)險(xiǎn):不要把所有的“技術(shù)雞蛋”放到一個(gè)籃子里。 低買高賣:新技術(shù)流行之前就掌握它往往比之后跟風(fēng)再學(xué)得到更大的回報(bào)。
這些知道方針里最重要也是最簡單的就是:定期為你的知識資產(chǎn)投資。
3、具體方案介紹
每年至少學(xué)習(xí)一種新語言。 每季度閱讀一本技術(shù)書籍,習(xí)慣之后可以一個(gè)月就閱讀一本。 也要閱讀非技術(shù)書籍,記住計(jì)算機(jī)是由人使用的。 在本地大學(xué)或者網(wǎng)上系統(tǒng)地學(xué)一門課程。 體驗(yàn)不同的環(huán)境,如果你只在 Windows 上工作,可以試下 Unix。如果你只使用某一種 IDE 那可以試試其他 IDE。
第六節(jié):交流
1、知道你想要說什么
當(dāng)我們面臨會議,重要通話,或者只是撰寫技術(shù)文檔,問下自己你要表達(dá)的中心想法是什么,圍繞這一點(diǎn)進(jìn)行展開。
2、了解你的聽眾
比如你要做一場分享,你可以按照 WISDOM 的形式思考這幾個(gè)問題:
你想讓他們學(xué)到什么 他們對你講的什么內(nèi)容感興趣 他們有多富有經(jīng)驗(yàn) 他們需要多少細(xì)節(jié) 你想要誰擁有這些信息 你如何促使他們聽你說話
3、選擇風(fēng)格
傳達(dá)一個(gè)消息,可以是正式的郵件,黑板上的繪圖,口頭描述,及時(shí)消息,選一個(gè)適合你的目的的方式。
4、讓文檔美觀
技術(shù)文檔不光要注意內(nèi)容也要注意形式,使用 LaTeX 或者 Markdown 進(jìn)行排版。
5、讓聽眾參與
引導(dǎo)他們提問,以問答的形式推進(jìn)分享進(jìn)程。
6、回復(fù)他人
你說什么和你怎么說同樣重要。盡量不要忽視別人的詢問,即使回復(fù)他們稍后再聯(lián)系都會更好一些。
第七節(jié):重復(fù)的危害
1、可靠的開發(fā)軟件,并讓我們的開發(fā)更易于理解和維護(hù)的唯一途徑,是遵循我們稱之為 DRY 的原則:系統(tǒng)中的每一項(xiàng)都必須具有單一、無歧義、權(quán)威的表示。
DRY 是 Dont’t Repeat Yourself 的縮寫。
2、重復(fù)的產(chǎn)生通常有以下種類:
強(qiáng)加的重復(fù)。開發(fā)者覺得他們無可選擇,其實(shí)是有一些方法讓我們避免重復(fù)的。
無意的重復(fù)。開發(fā)者沒有意識到他們在重復(fù)信息。這個(gè)需要通過提高代碼意識或者 CR 進(jìn)行減少。
無耐性的重復(fù)。開發(fā)者偷懶,因?yàn)橹貜?fù)可以讓事情更容易。有時(shí)往往會遇速則不達(dá),在這類重復(fù)面前我們應(yīng)該更慎重。
開發(fā)者之間的重復(fù)。同一個(gè)團(tuán)隊(duì)或者不同團(tuán)隊(duì)的幾個(gè)人重復(fù)了同樣的信息。需要一個(gè)統(tǒng)籌的人引導(dǎo)大家交流,提供一個(gè)中央?yún)^(qū)域,管理維護(hù)公共代碼。
第八節(jié):正交性
1、正交性是一個(gè)從幾何學(xué)中借鑒而來的術(shù)語,如果兩條直線相交成直角,他們就是正交的。這在向量中的解釋是沿著一條直線移動(dòng),你投影到另一條直線上的位置不變。
在計(jì)算機(jī)中,該術(shù)語用于表示某種不相依賴性或解耦性。
2、正交的好處是它提高生產(chǎn)效率,各個(gè)組件不相互依賴,使得改變得以局部化,促進(jìn)復(fù)用,對于正交組件進(jìn)行組合也可以提高生產(chǎn)效率,同時(shí)它還降低了代碼的風(fēng)險(xiǎn)。
3、延伸開來,項(xiàng)目團(tuán)隊(duì)的配合也應(yīng)該遵循正交性。如果成員之間任務(wù)重疊較多容易讓大家疑惑問題和責(zé)任的歸屬如何劃分,這會造成配合的效率低下。
代碼設(shè)計(jì)的時(shí)候也應(yīng)該盡可能考慮正交性,這需要結(jié)合一些特定的設(shè)計(jì)模式以達(dá)成目的。
第九節(jié):可撤銷性
如果某個(gè)想法是你唯一的想法,再?zèng)]有什么比這更危險(xiǎn)的事情了。在設(shè)計(jì)軟件時(shí),我們需要為可能出現(xiàn)的某種錯(cuò)誤做準(zhǔn)備,比如數(shù)據(jù)庫的更換,開發(fā)平臺的更換。這需要我們設(shè)計(jì)之初就考慮到構(gòu)建一個(gè)相對靈活的架構(gòu)。
第十節(jié):曳(ye)光彈
1、在黑暗中使用機(jī)槍射擊有兩種方式。
方式一:你需要知道目標(biāo)準(zhǔn)確的位置,然后考慮當(dāng)時(shí)的溫度、濕度、氣壓、風(fēng)力等一系列因素,計(jì)算完位置之后進(jìn)行射擊。
方式二:使用曳光彈,發(fā)射時(shí),曳光彈中的磷點(diǎn)燃,會照亮它經(jīng)過的地方和最終位置,我們用曳光彈確認(rèn)位置之后,就不需要那些繁雜的計(jì)算,直接使用機(jī)槍進(jìn)行射擊。
2、在黑暗中發(fā)光的代碼。通常一個(gè)項(xiàng)目的開發(fā)是非常復(fù)雜的,如果只是一個(gè)模塊一個(gè)模塊的開發(fā),我們可能直到最后才能確認(rèn)項(xiàng)目運(yùn)行情況。更好的做法是,我們要讓系統(tǒng)盡早的跑起來,然后根據(jù)需要給它完善細(xì)節(jié)。這樣會有以下好處:
用戶能夠及早看到能工作的東西。 開發(fā)者構(gòu)建了一個(gè)能在其中工作的結(jié)構(gòu)。 你有了可用于演示的東西。 你能夠感覺到工作進(jìn)展。
第11節(jié):原型與便箋
1、原型是你可以在忽略細(xì)節(jié)的情況下,考慮項(xiàng)目走流程,主要使用場景,他們是否正確,是否可行。通常也可以用用于演示
2、原型制作是一種學(xué)習(xí)經(jīng)驗(yàn),其價(jià)值并不在于所產(chǎn)生的代碼,而在于所學(xué)到的經(jīng)驗(yàn)教訓(xùn)。那才是原型制作的要點(diǎn)所在。
3、制作原型甚至不需要編碼,你可以用便箋,白板上制作原型。制作原型時(shí)你需要嘗試回答以下問題:
主要組件的責(zé)任是否得到了良好定義?是否恰當(dāng)? 主要組件間的協(xié)作是否得到了良好的定義? 耦合是否得以最小化? 你能否克服確認(rèn)重復(fù)的潛在來源? 接口定義和各項(xiàng)約束是否可接受?
第12節(jié) 領(lǐng)域語言
1、計(jì)算機(jī)語言會影響你思考問題的方式,以及你看待交流的方式。
2、領(lǐng)域語言通常是為了簡化流程,用于配置或者控制應(yīng)用程序。
3、DSL 可以理解為一個(gè)小型語言,它可以是擴(kuò)展自已有語言。
4、在設(shè)計(jì)一種 DSL 時(shí),考慮可讀性還是簡單性時(shí),主要權(quán)衡的應(yīng)該是可擴(kuò)展性和可維護(hù)性,因?yàn)橥ǔ4蠖鄶?shù)應(yīng)用都會超出預(yù)期的使用期限。
第13節(jié) 估算
1、通過學(xué)習(xí)估算,并將此技能發(fā)展到事物的數(shù)量級有直覺的程度,你就能展現(xiàn)出一種魔法般的能力,確定他們的可行性。
2、多準(zhǔn)確才足夠準(zhǔn)確?130 個(gè)工作日和大概 6 個(gè)月,是不同的,顯然,前者表示的精度更高。我們在做估算的時(shí)候也需要選好描述估算時(shí)間的單位值。
3、估算結(jié)果怎么來呢。
首先需要確認(rèn)你是否理解了需求所涉及的各個(gè)方面,這個(gè)是前置條件。
然后你需要建立系統(tǒng)模型,在這個(gè)系統(tǒng)中,把模型分拆成各個(gè)組件,然后給每個(gè)參數(shù)設(shè)置定一個(gè)值,最后根據(jù)模型計(jì)算一個(gè)時(shí)間。
4、模型應(yīng)該是一個(gè)動(dòng)態(tài)的,它像一個(gè)人工智能模型,你需要持續(xù)不斷的訓(xùn)練它,才能使它真正準(zhǔn)確起來。每次的估算都需要記錄,反思估算效果,找出影響因素,加入新的影響項(xiàng)或者調(diào)整對應(yīng)參數(shù)。
5、被要求進(jìn)行估算時(shí)間時(shí),我們可以這樣回答:我等會兒回答你。然后花點(diǎn)時(shí)間仔細(xì)檢查我們在這一節(jié)描述的步驟,你總能得到更好的結(jié)果。
第14節(jié) 純文本的威力
本節(jié)是第三章:基本工具,首節(jié)內(nèi)容,章節(jié)介紹里有一句話:
許多新程序員都會犯下錯(cuò)誤,采用單一的強(qiáng)力工具,比如特定的集成開發(fā)環(huán)境(IDE),而且再也不離開其舒適的界面。這實(shí)在是一個(gè)錯(cuò)誤。我們要樂于超越IDE所施加的各種限制。要做到這一點(diǎn),唯一的途徑是保持基本工具集的“鋒利”與就緒。
1、純本文由可打印字符組成,人可以直接閱讀和理解其形式。
這里強(qiáng)調(diào)可打印含義是字符時(shí)經(jīng)過編碼的可閱讀字符,而不是二進(jìn)制。這在現(xiàn)在看來幾乎是不用爭辯的,誰還會用二進(jìn)制存儲信息,但當(dāng)時(shí)計(jì)算機(jī)算力和存儲都有限,純文本會占據(jù)更多空間,解碼會耗費(fèi)算力。但源于技術(shù)的發(fā)展,這些都是可以忽略不計(jì)了。
2、純文本的優(yōu)點(diǎn)之一:保證不過時(shí)。這一點(diǎn)需要我們擴(kuò)展純文本能夠自描述。自描述的含義是它自己能告訴我們它的含義。
123-45-6789
<SSNO>123-45-6789</SSNO>
上面的例子中下面一條就是自描述的,我們能通過 SSNO 推斷出這里存的就是社會保障號,另外根據(jù) <SSNO> 這一標(biāo)記我們可以很輕松的將對應(yīng)內(nèi)容提取出來。
3、另外兩個(gè)優(yōu)點(diǎn)是杠桿作用和更易于測試。這里說的是我們可以利用各種工具 diff、fc、git,或一些語言例如 Python 等對純文本進(jìn)行各種調(diào)整和查看工作。
第15節(jié) Shell 游戲
1、對于操縱文本的文件的程序員,命令 Shell 就是工作臺。我們可以利用 Shell 啟動(dòng)各種應(yīng)用、搜索文件、查詢系統(tǒng)狀態(tài),甚至還可以構(gòu)建復(fù)雜的宏命令,完成各種常見活動(dòng)。
2、對于習(xí)慣 GUI 的開發(fā)者來說一直使用 Shell 有些極端。GUI 的好處是所見即所得,但他的缺點(diǎn)卻是,所見即全部所得。GUI 環(huán)境通常受限于它們的設(shè)計(jì)者想要提供的能力。
3、比如我們想要做一件事:在一個(gè)代碼倉庫里,查找上周沒有修改過的,使用了 awt 庫的 java 文件。
如果使用Shell,可以執(zhí)行:
find . -name ‘*.java’ -mtime +7 -print | xargs grep 'java.awt'
如果使用 GUI,你可以設(shè)想一下,這個(gè)過程會很麻煩,也很容易出錯(cuò)。
4、Shell 可能比較晦澀,但是掌握之后它能很大程度提高你的效率。Shell 可以做各種組合搭配,然后構(gòu)建一個(gè)命令序列,讓常做的事情自動(dòng)化。
第16節(jié) 強(qiáng)力編輯器
1、我們認(rèn)為你最好是精通一種編輯器,并將其用于所有編輯任務(wù):代碼、文檔、備忘錄、系統(tǒng)管理等等。
進(jìn)行編輯活動(dòng)時(shí),你不必停下來思考怎樣完成文本操作,編輯器將成為你雙手的延伸,鍵會在滑過文本和思想時(shí)歌唱起來。
這就是我們的目標(biāo)。
2、好的編輯器應(yīng)該具有這些特性:可配置、可擴(kuò)展、可編程、語法突顯、自動(dòng)縮進(jìn)、類IDE特性。
3、編輯器對生產(chǎn)效率是有影響的。試想當(dāng)我們需要一個(gè)字符一個(gè)字符或者一行一行移動(dòng)時(shí),按一次鍵,就以詞,行,塊的單位移動(dòng),顯然效率更高。
4、然后做什么。選一種強(qiáng)大的編輯器,好好學(xué)習(xí)它。不斷學(xué)習(xí),減少你敲擊的次數(shù)。設(shè)法擴(kuò)展它,讓它能勝任更多任務(wù)。
推薦兩款編輯器:vim、Emacs
第17節(jié) 源碼控制
1、原諒我們犯錯(cuò)的按鈕是 UNDO 鍵,通常他們還支持多級 UNDO 和 REDO。而源碼控制系統(tǒng)就相當(dāng)于一個(gè)巨大的 UNDO 鍵,一個(gè)項(xiàng)目級的時(shí)間機(jī)器。源碼控制系統(tǒng)(SCCS)能夠追蹤你在源碼和文檔中做的每一項(xiàng)改動(dòng)。
2、應(yīng)該總是使用源碼控制,即使團(tuán)隊(duì)只有你一人,即使項(xiàng)目很小。
3、可以嘗試的源碼控制系統(tǒng)有 CSV、RCS、ClearCase 等。(那時(shí) Git 還沒流行起來)
第18節(jié):調(diào)試
1、調(diào)試心理學(xué)。調(diào)試的目的是解決問題,不要因?yàn)閯e人提出 bug 而發(fā)起進(jìn)攻。
2、當(dāng)你目睹 bug 發(fā)生或者看到 bug 報(bào)告時(shí),第一反應(yīng)不要是“那不可能”。很明顯已經(jīng)發(fā)生了,把時(shí)間用在思考它為什么產(chǎn)生上面。
3、使數(shù)據(jù)可視化。例如循環(huán)引用問題,如果可視化的話可以很輕易地進(jìn)行排查。
4、跟蹤代碼。發(fā)生 crash 我們能夠查看系統(tǒng)的調(diào)用堆棧,但這些數(shù)據(jù)不一定夠。對于非 crash 類錯(cuò)誤,因?yàn)闆]有拋出,我們甚至不知道發(fā)生了什么。所以添加所謂的跟蹤日志很有必要,這類日志最好采用統(tǒng)一規(guī)范,便于后期我們可以自動(dòng)解析他們。
5、橡皮鴨,也叫小黃鴨調(diào)試法。遇到無法定位的問題時(shí),對著小黃鴨(屏幕)解釋自己的實(shí)現(xiàn)邏輯,很可能在說的過程中你自己就發(fā)現(xiàn)了問題所在。
6、不要第一時(shí)間懷疑 OS,IDE,三方庫的問題,他們出問題的概率比你代碼出問題概率小得多。我們應(yīng)該首先確認(rèn)和排查自己的問題。
7、對 bug 原因進(jìn)行復(fù)盤。修復(fù)了一個(gè) bug,不要就讓它結(jié)束了,想一下,為什么它會出現(xiàn)了,如何避免。定位過程如果耗時(shí)較長,也需要復(fù)盤下為何花費(fèi)了那么長時(shí)間,以及后續(xù)如何優(yōu)化。
第19節(jié) 文本操縱
1、學(xué)習(xí)一種文本操縱語言。文本操作語言對于編程的意義,就像是刳刨機(jī)對于木工活的意義。
2、文本操作的案例。
我們的測試數(shù)據(jù)有好幾萬條,散落在不同文件,如果需要進(jìn)行合并并轉(zhuǎn)換為特定格式,手動(dòng)處理是無法想象的。但如果使用 Perl 幾個(gè)小時(shí)就可以完成。 數(shù)據(jù)庫 schema 維護(hù)。可以寫一組 Perl 腳本讀取數(shù)據(jù)庫 schema 定義的純文本文件,根據(jù)它生成,用于創(chuàng)建數(shù)據(jù)庫的 SQL 語句。schema 的 XML 版本等 生成 web 文檔。可以編寫 Perl 程序,分析數(shù)據(jù)庫 schema,C 或 C++ 源文件,及其他資源,生成 HTML 文檔。
文中很多案例使用 Perl,這些工作也可以使用 Python 代替或者 Shell 里的 awk,sed 代替。
第20節(jié) 代碼生成器
1、作為程序員,有時(shí)會需要我們在不同地方重復(fù)相同信息。如果出現(xiàn)這種情況,你就可以考慮構(gòu)建代碼生成器了。代碼生成器就是編寫能編寫代碼的程序。
2、有兩類代碼生成器:被動(dòng)代碼生成器和主動(dòng)代碼生成器。
3、被動(dòng)代碼生成器是獨(dú)立執(zhí)行的。它可以用來生成模板,版權(quán)聲明,每個(gè)新文件的標(biāo)準(zhǔn)注釋等等。
4、主動(dòng)代碼生成器會在每次需要其結(jié)果時(shí)被使用。比如根據(jù)數(shù)據(jù)庫 schema 創(chuàng)建代碼。
5、代碼生成器不一定要生成代碼,它可以用來輸出任何格式的內(nèi)容,比如 HTML、XML、純文本等。
比如 iOS 里的三方庫 R.Swift[1] 就是一個(gè)根據(jù)資源名自動(dòng)生成對應(yīng)結(jié)構(gòu)體的主動(dòng)代碼生成器。
第21節(jié) 按合約設(shè)計(jì)
1、注重實(shí)效的程序員會不信任自己,所以他們針對自己的錯(cuò)誤行為進(jìn)行防衛(wèi)性編碼。
2、按合約設(shè)計(jì)(Design By Contract,簡寫DBC)是 Bertrand Meyer 為 Eiffel 語言發(fā)展的概念。它的核心是用文檔記載模塊的權(quán)利與責(zé)任,并進(jìn)行校驗(yàn)。它的目的是對函數(shù)做一些前置檢查和后置保證,結(jié)合編譯器的支持,我們能夠盡早的發(fā)現(xiàn)代碼問題。
3、DBC 有三個(gè)概念。
前條件:為了調(diào)用例程必須為真的條件。
后條件:例程保證會做的事情,其完成時(shí)的狀態(tài)。
類不變項(xiàng):其確保從調(diào)用者的視角來看,該條件總是為真。
4、Java 中的 iContract 框架是專為 DBC 設(shè)計(jì)的,它通過注釋里的 @pre、@post、@invariant 聲明這三個(gè)概念。它會讀取注釋并生成包含斷言邏輯的源文件。Eiffel 則是通過 require、ensure、is 三個(gè)值表示對應(yīng)概念。但是支持 DBC 的語言真的很少。
第22節(jié):死程序不說謊
1、對待程序我們通常會有“它不會發(fā)生”的心理狀態(tài),這會導(dǎo)致我們忽視一些問題。對于注重實(shí)效的程序員來說,如果我們忽略了一個(gè)錯(cuò)誤,將是非常糟糕的事情。
2、我們一些異常情況,我們應(yīng)該及早崩潰,用于強(qiáng)調(diào)問題的存在。
3、引起崩潰的時(shí)候不要造成破壞,比如申請的資源還沒有釋放等情況。
4、死程序帶來的額危害通常比有隱患的程序要小得多。
第23節(jié) 斷言式編程
1、如果它不可能發(fā)生,用斷言確保它不會發(fā)生。
assert(string != NULL)
斷言里寫的為真的條件,當(dāng)不為真時(shí)觸發(fā)斷言,程序退出。
2、斷言檢查的是決不應(yīng)該發(fā)生的事情,而不是錯(cuò)誤處理。
3、斷言應(yīng)該一直開著,不要在線上環(huán)境關(guān)掉它。
斷言對應(yīng)的是一種強(qiáng)提示,它迫使我們必須遵守。像是單元測試,我們通常都使用斷言的形式進(jìn)行檢查。
第24節(jié) 何時(shí)使用異常
1、異常很少應(yīng)作為程序的正常流程的一部分使用,異常應(yīng)該保留給意外情況。如果移除了所有的異常處理器,代碼就無法運(yùn)行,那說明異常正在被用于非異常情況中。
2、是否應(yīng)該使用異常取決于實(shí)際情況。比如打開文件,文件不存在,是否應(yīng)該發(fā)生異常?如果文件應(yīng)該在那里,那么異常就有正當(dāng)理由。如果不確定文件是否在那里,返回錯(cuò)誤就可以了。
第25節(jié) 怎樣配平資源
1、對于資源(內(nèi)存、事務(wù)、現(xiàn)成、文件、定時(shí)器等)的管理要有始有終,你分配了對應(yīng)的資源,就需要考慮對應(yīng)的解除邏輯。要有始有終。
2、嵌套的資源分配,應(yīng)該使用與分配次序相反的順序進(jìn)行解除。
3、異常的配平需要避免違反 DRY 原則。例如文件打開的異常情況,會導(dǎo)致 try..catch 有兩條路徑,那如何避免在正常流程和 catch 流程都處理 error 情況呢?C++ 可以依賴對象自動(dòng)析構(gòu)的特性,Java 可以依賴 finally子句。
4、當(dāng)無法配平資源時(shí),需要設(shè)定一個(gè)規(guī)則,決定誰為某個(gè)聚集數(shù)據(jù)結(jié)構(gòu)中的數(shù)據(jù)負(fù)責(zé),以及如何負(fù)責(zé)。這里有點(diǎn)類似引用計(jì)數(shù)方案,無引用時(shí)釋放。
5、自動(dòng)化檢查資源配平狀態(tài),可以依賴一些三方工具。
第26節(jié) 解耦與得墨忒(tei)耳法則
1、把你的代碼組織成最小單位(模塊),并限制他們之間的交互。如果隨后必須替換某個(gè)模塊,其他模塊仍能夠繼續(xù)工作。
2、應(yīng)使耦合減至最少。對象間直接的橫貫關(guān)系,有可能很快帶來依賴關(guān)系的組合爆炸。比如對某個(gè)模塊的“簡單”改動(dòng)會傳遍系統(tǒng)中的一些無關(guān)模塊。
3、函數(shù)的得墨忒耳法則,它規(guī)定了某個(gè)對象的任何方式都應(yīng)該只調(diào)用屬于以下情形的方法:
它自身 傳入該方法的任何參數(shù) 它創(chuàng)建的任何對象 任何直接持有的組件對象
4、得墨忒耳法則的好處是它使得代碼的適用性更好,更健壯,但這也有一定的代價(jià)。如果某些解耦的操作很復(fù)雜,或者解耦帶來某些時(shí)間和空間的重大開銷,這時(shí)就需要根據(jù)實(shí)際情況考慮,可以暫時(shí)舍棄該法則。
第27節(jié) 元程序設(shè)計(jì)
1、元數(shù)據(jù)是關(guān)于數(shù)據(jù)的數(shù)據(jù),即對應(yīng)用進(jìn)行描述的數(shù)據(jù)。典型情況,元數(shù)據(jù)在運(yùn)行時(shí),而不是編譯時(shí)被訪問和使用。
2、我們想要讓我們的系統(tǒng)變得高度可配置,像是屏幕顏色,提示文本等,這些應(yīng)該作為配置項(xiàng)而不是作為代碼集成到項(xiàng)目中。
3、以聲明方式思考(規(guī)定要做什么,而不是怎么做),并創(chuàng)建高度靈活的可適應(yīng)的程序。結(jié)合元數(shù)據(jù)就是,將抽象放進(jìn)代碼,細(xì)節(jié)放進(jìn)元數(shù)據(jù)。
4、Enterprise Java Beans 是一個(gè)用于簡化分布式、基于事務(wù)的環(huán)境中的編程框架。它處理了不同機(jī)器、在不同數(shù)據(jù)庫供應(yīng)商之間,不同線程及復(fù)雜平衡的事務(wù)。它的使用只需我們編寫一個(gè) bean,并將其放到 bean container 中。
5、更好的協(xié)作式配置是讓應(yīng)用自身適應(yīng)其環(huán)境,進(jìn)行動(dòng)態(tài)配置。
第28節(jié) 時(shí)間耦合
1、時(shí)間耦合就是關(guān)于時(shí)間的各種事項(xiàng)。
2、軟件設(shè)計(jì)中,時(shí)間的角色通常有兩方面對我們來說很重要:并發(fā)(事情同一時(shí)間發(fā)生)、次序(事情在時(shí)間中的相對位置)。我們期望的是要容許并發(fā),并考慮解除任何時(shí)間次序上的依賴。
3、可以選擇使用 UML 活動(dòng)圖進(jìn)行工作流分析,以改善其并發(fā)性。
4、在設(shè)計(jì)架構(gòu)時(shí),用服務(wù)進(jìn)行設(shè)計(jì)而不是組件。饑餓的消費(fèi)者模型是在多個(gè)消費(fèi)者進(jìn)程間進(jìn)行快速而粗糙的負(fù)載平衡的一種有效途徑。
5、編寫線性代碼,我們很容易做出一些假定,把我們引向不整潔的編程。但并發(fā)會迫使你更仔細(xì)的對事情進(jìn)行思考。
6、盡可能使用線程安全的類,開發(fā)時(shí)也應(yīng)盡可能設(shè)計(jì)線程安全的類。
第29節(jié) 它只是視圖
1、我們都知道應(yīng)該將程序分而治之,劃分成不同模塊。這里模塊(或類)的定義是,具有單一的定義良好的責(zé)任。那如何在不同模塊之間進(jìn)行通信,處理事件呢?有以下兩種方式。
2、發(fā)布/訂閱模式,又叫 Observer(觀察者)模式。它的工作模式是,由訂閱者 Subscriber 向發(fā)布者 Publisher 進(jìn)行注冊,注冊之后,Publisher 的事件會通知到 Subscriber。未注冊和解除注冊將不會收到之后的事件通知。
3、Model-View-Controller 是一種將模型與表示模型的 GUI 分離的架構(gòu)模型,它能有效降低數(shù)據(jù)和視圖之間的相互影響。
第30節(jié) 黑板
1、設(shè)想偵探破案的過程,他借助于一塊黑板,把不同線索寫出來;其他偵探也可以寫下自己的推斷和已掌握的案情細(xì)節(jié)。所有這一切串聯(lián)起來將共同幫助案件偵破,但不同的線索之間是可以獨(dú)立進(jìn)行的。
2、這里的黑板可以抽象為一種處理事件的模型。不同于原始的工作流需要考慮各種狀況,不同組合,先后順序等,黑板系統(tǒng)只管寫入,讀取,查詢,通知等基礎(chǔ)功能,任意符合條件的事件都可以進(jìn)入這個(gè)系統(tǒng)。
3、黑板模型也是一種解耦形式。
第31節(jié) 靠巧合編程
從本節(jié)開始進(jìn)入書目的第6章,本章主要講在編碼時(shí)應(yīng)該注意的各類事項(xiàng)。傳統(tǒng)智慧認(rèn)為,項(xiàng)目一旦進(jìn)入編碼階段,工作主要就是機(jī)械的把設(shè)計(jì)轉(zhuǎn)換成可執(zhí)行語句。我們認(rèn)為,這種態(tài)度是許多程序丑陋、結(jié)構(gòu)糟糕、不可維護(hù)的最大一個(gè)原因。編碼不是機(jī)械工作,要想讓程序長久無誤的運(yùn)行,每一分鐘都需要做出決策,且需要對這些決策進(jìn)行仔細(xì)的思考和判斷。
1、靠巧合編程即代碼正好是可運(yùn)行的,至于為什么能夠正常運(yùn)行,卻不清楚。這是我們應(yīng)該極力避免的。
2、在打算重構(gòu)某個(gè)看起來有問題的代碼時(shí),我們會面臨這樣的疑惑,是否有必要冒著把能工作的東西弄糟的風(fēng)險(xiǎn)呢?這時(shí)我們可以考慮一下幾個(gè)理由:
它也許不是真的能工作,只是看起來能工作。
你依靠的邊界條件也許只是一個(gè)巧合。
多余和沒必要的調(diào)用會讓你的代碼變慢并增加新 bug 的風(fēng)險(xiǎn)。
3、如何深思熟慮的編程,有以下建議:
總是意識到你在做什么。 按照計(jì)劃(設(shè)計(jì))行事。 依靠可靠的事物而非假設(shè)。 不要只是測試你的代碼,還要測試你的假定。 不要讓已經(jīng)做完的事情限制你的下一步,做好重構(gòu)的準(zhǔn)備。
第32節(jié) 算法效率
1、注重實(shí)效的程序員幾乎每天都要使用估算,估算的資源包括:時(shí)間、處理器、內(nèi)存等等。
2、估算算法即是我們熟知的時(shí)間復(fù)雜度,用O()表示,它有以下幾種常見類型。
O(1),常量時(shí)間,不隨數(shù)據(jù)的多少變化 O(n),線性時(shí)間,簡單的循環(huán) O(m*n),嵌套循環(huán) O(log(n)),二分法,平衡二叉樹的查詢 O(nlog(n)),分而治之,快排 O(2^n),指數(shù)級,斐波那契數(shù)列
3、不同的時(shí)間復(fù)雜度在達(dá)到一定數(shù)量級的時(shí)候?qū)⑾嗖詈芏啵阅承┣闆r我們要想方設(shè)法優(yōu)化算法的效率。我們主要需要關(guān)注的是是復(fù)雜度的階。在確認(rèn)了算法之后,還需要對其進(jìn)行測試。
4、最好的并非總是最好的,是否使用最優(yōu)算法,還需要根據(jù)我們遇到的實(shí)際情況。有時(shí)數(shù)據(jù)量很小的情況,算法的效率是可以忽略不計(jì)的。
第 33 節(jié) 重構(gòu)
1、重寫、重做和重新架構(gòu)代碼合起來,稱為重構(gòu)。
2、當(dāng)代碼出現(xiàn)以下特征,就應(yīng)該考慮重構(gòu)了:
出現(xiàn)重復(fù)內(nèi)容,違反DRY原則。 非正交的設(shè)計(jì)。 知識過時(shí)了,或者你對某部分的了解更深一步。 對性能造成了影響。
3、重構(gòu)的原則:早重構(gòu)、常重構(gòu)。重構(gòu)面臨的敵人通常都是時(shí)間,但這個(gè)借口并不成立,因?yàn)橹笥纱艘l(fā)的時(shí)間額外消耗很可能更多。
4、如何重構(gòu)。
不要試圖在重構(gòu)的同時(shí)增加功能。 重構(gòu)之前,確保擁有良好的測試。 采取短小,深思熟慮的步驟,不要一次改動(dòng)太多內(nèi)容。
第34節(jié) 易于測試的代碼
1、軟件 IC 是人們在討論可復(fù)用性和基于組件的開發(fā)時(shí)喜歡使用的比喻。意思是集成電路芯片可以很容易的進(jìn)行組合,我們希望軟件開發(fā)也能達(dá)到這個(gè)效果。芯片的設(shè)計(jì)有完善的測試,同樣的軟件開發(fā)也可以做同樣的事情。
2、針對合約進(jìn)行測試及為測試而設(shè)計(jì),即 TDD 測試驅(qū)動(dòng)開發(fā)。
3、編寫單元測試,對比較大的項(xiàng)目,將每個(gè)測試都放進(jìn)一個(gè)子目錄。
4、使用測試裝備。構(gòu)建一套完善的測試體系,它能夠記錄測試狀態(tài),分析輸出結(jié)果是否符合預(yù)期,以及選擇和運(yùn)行測試。
5、推進(jìn)測試文化,盡可能完善地測試你的軟件,否則你的用戶就得替你測試。
第35節(jié) 邪惡的向?qū)?/span>
1、這里的向?qū)е傅氖悄切┯糜趲椭覀儤?gòu)建程序自動(dòng)生成的代碼,通常他們還被稱為腳手架。為什么稱向?qū)В╳izard)是邪惡的呢,這是因?yàn)橥ㄟ^工具生成的代碼,很容易被我們忽略,在這種情況下你編寫的過程更傾向于靠巧合編程。
2、這里不是抵制向?qū)Тa,而是在強(qiáng)調(diào),不要使用你不理解的向?qū)Тa。如果使用,一定要清楚它的機(jī)制。
3、開發(fā)每天都在使用不完全理解的事物,比如集成電路的工作原理,處理器的中斷結(jié)構(gòu)、用于調(diào)度的算法、各種系統(tǒng)庫的工作機(jī)制等。需要注意的是,這些屬于底層依賴,他們也是向?qū)В皇菓?yīng)用本身的一部分,我們可以對這部分有所了解,但他們不屬于邪惡的向?qū)А?/p>
第36節(jié) 需求之坑
從本節(jié)開始進(jìn)入了第七章節(jié):在項(xiàng)目開始之前。本章節(jié)討論了在項(xiàng)目開始之前的一些建議。
1、完美,不是在沒有什么需要增加,而是在沒有什么需要去掉時(shí)達(dá)到的。這句話的一種解讀時(shí),不要搜集需求,需求太多,容易讓我們抓不住重點(diǎn),更應(yīng)該深挖需求,圍繞核心功能不斷打磨。
2、挖掘需求,需要我們與用戶一同工作,像用戶一樣思考。
3、制定需求文檔。看待用例的一種方式是強(qiáng)調(diào)其目標(biāo)驅(qū)動(dòng)的本質(zhì),它強(qiáng)調(diào)的是要重視需要做成什么以及需要什么條件。需求文檔最好配一些UML用例圖。
4、需求的制定不能太具體,要保持一定的抽象。需求不是架構(gòu),不是設(shè)計(jì),需求只是需要。這個(gè)有點(diǎn)類似于開發(fā)中的面向接口而不是面向具體實(shí)現(xiàn)編程。
5、維護(hù)詞匯表。“客戶”和“顧客”,可能表達(dá)不同的含義,但如果混用會讓人迷惑,我們可以維護(hù)一個(gè)詞匯表,專門用戶描述他們的具體含義。
6、把需求文檔發(fā)布到內(nèi)網(wǎng),參與人員都可以隨時(shí)查看和提出意見。
第37節(jié) 解開不可能解開的謎題
1、戈?duì)柕纤菇Y(jié)號稱是沒人能解開的結(jié),后來亞歷山大大帝來了,用劍劈開了這個(gè)結(jié)。
2、面對看似不可能解決的問題,一定要轉(zhuǎn)換思路,不要受任何先人之見影響。不要在盒子外面思考,要找到盒子。
3、有時(shí)你會發(fā)現(xiàn),自己在處理的問題比你以為的要難得多,總會感覺一定有更容易的方法。這時(shí)你可以退回一步,問問自己:
有更容易的方法嗎 你是在解決真正的問題,還是被外圍的技術(shù)問題轉(zhuǎn)移了注意力 這件事情為什么是一個(gè)問題 是什么使它如此難以解決 它必須以這種方式完成嗎
很多時(shí)候,對需求的重新詮釋能讓整個(gè)問題全部消失— 就像戈?duì)柕纤菇Y(jié)。
第 38 節(jié):等你準(zhǔn)備好
1、傾聽反復(fù)出現(xiàn)的疑慮。當(dāng)你遇到一個(gè)反復(fù)讓你疑慮的問題,需要注意它,給自己時(shí)間去理解,之后它可能就會變成某種更堅(jiān)實(shí)的東西。
2、對于某些東西,我們可能不愿意輕易做出承諾,總希望再等等,更多意見的提出。但這很可能是一種拖延,怎么區(qū)分是有效的等待還是拖延的接口呢?我們應(yīng)該快速地構(gòu)建原型,并進(jìn)行推延,可能很快我們就找到了更好的解決方案。
第 39 節(jié):規(guī)范陷阱
1、編寫規(guī)范是一項(xiàng)重要的職責(zé),但問題是很多人可能會陷在這里,不斷地增加規(guī)范項(xiàng)。我們可以做這樣一個(gè)嘗試,寫一份簡單的描述,告訴別人怎樣系鞋帶。
這可能是一份并不能幫助他人的描述,因?yàn)閷τ行┦虑椤白觥眲儆凇懊枋觥薄R驗(yàn)闊o意識的行為更快,考慮規(guī)范反而會拖慢進(jìn)度。
2、對待開發(fā)文檔也一樣,不要編寫過于詳細(xì)的規(guī)范。因?yàn)楹芸赡荛_發(fā)者在思考某個(gè)問題時(shí)會想到兩種不同方案,經(jīng)過簡單對比,選擇一個(gè)更優(yōu)的那個(gè)。但面對嚴(yán)格的規(guī)范文檔,一步步思考,這更可能束縛開發(fā)者的發(fā)揮。
第 40 節(jié):圓圈與箭頭
1、設(shè)計(jì)文檔里的圓圈和箭頭用來解釋他們指代的作用,但這還有可能是推翻我們原先設(shè)定的證據(jù)。感覺這個(gè)是承接上一節(jié)的內(nèi)容,不要被以前的假設(shè)和設(shè)計(jì)所限制,留有一定的彈性空間。
2、我們相信,盲目地采用任何技術(shù),而不把他們放進(jìn)你的開發(fā)實(shí)踐和能力的語境中,這樣的處理日后可能會讓你后悔。
3、不要迷信工具以及各種方法學(xué),注重實(shí)效的程序員會批判地看待他們,并從中提取精華,融合成每個(gè)月都在變得更好的一套工作習(xí)慣。
第41節(jié) 注重實(shí)效的團(tuán)隊(duì)
1、書籍的前幾章講了幾條如何成為注重實(shí)效的開發(fā)者的建議,當(dāng)然他們也對團(tuán)隊(duì)有所幫助,如果個(gè)體都是注重實(shí)效的,那他對整體起的作用更大。
2、不要留破窗戶:作為整體的團(tuán)隊(duì)更不應(yīng)該容忍代碼質(zhì)量的問題,不規(guī)范的不在乎質(zhì)量的團(tuán)隊(duì),很有可能把那些注重實(shí)效的開發(fā)者帶偏。
3、煮青蛙:整體中的個(gè)人更難覺察到作為團(tuán)隊(duì)所存在的問題,可以指定一個(gè)“檢測員”,讓他去檢查團(tuán)隊(duì)整體進(jìn)度,依賴項(xiàng)的準(zhǔn)備情況,各個(gè)環(huán)節(jié)的配合等內(nèi)容。
4、交流:杰出的項(xiàng)目團(tuán)隊(duì)往往有著截然不同的個(gè)性,更能與其他團(tuán)隊(duì)進(jìn)行配合。有一個(gè)簡單的幫助團(tuán)隊(duì)凝聚力的方法:創(chuàng)立團(tuán)隊(duì)品牌,以品牌代指整個(gè)團(tuán)隊(duì)。
5、不要重復(fù)你自己(DRY):由于個(gè)人理解程度的不同或者新成員的加入,團(tuán)隊(duì)總會面臨重復(fù)的內(nèi)容,適當(dāng)?shù)闹概梢幻芾韱T,讓他專門維護(hù)這些資料,所有對此有疑問的人都不必自我尋找,只要去找管理員就行了。
6、正交性:對于較大的團(tuán)隊(duì),更應(yīng)該通過功能進(jìn)行組織劃分,而不是工作職務(wù)。比如開發(fā)多個(gè)項(xiàng)目,會有多名開發(fā),多名測試,多名設(shè)計(jì),他們之間更應(yīng)該按照具體項(xiàng)目進(jìn)行劃分,一個(gè)項(xiàng)目的開發(fā),測試和設(shè)計(jì)為一個(gè)小團(tuán)體。
7、自動(dòng)化:確保一致性和準(zhǔn)確的一種很好的方式是使團(tuán)隊(duì)所做的每件事情都能自動(dòng)化,如果還沒有做到那就嘗試去做。
8、知道如何停止繪畫:團(tuán)隊(duì)是由個(gè)體組成的,給每個(gè)成員足夠的空間,并支持他們,而不是一直給他們具化各種需求。
第42節(jié) 無處不在的自動(dòng)化
1、文明通過增加我們不加思索就能完成的重要操作的數(shù)目而取得進(jìn)步。— 阿爾弗雷德·諾思·懷特海
2、我們應(yīng)該在盡可能多的場景下使用自動(dòng)化,因?yàn)槿斯ち鞒碳安荒鼙WC一致性也無法保證重復(fù)性。
3、在一些特定場景下我們可以選擇適當(dāng)?shù)墓ぞ哌M(jìn)行自動(dòng)化處理:
執(zhí)行周期任務(wù)時(shí)可以使用 Cron 項(xiàng)目編譯時(shí)雖然可以使用 IDE,但是 Makefile 更適合自動(dòng)化場景 使用生成代碼解決不得不做的重復(fù)性代碼問題 構(gòu)建自動(dòng)化,其實(shí)就是目前比較常用各類 CI/CD 工具 自動(dòng)化管理,這是一種更自由的自動(dòng)化場景,比如要回復(fù) Email,要發(fā)布網(wǎng)站,審批流程等,這些可以使用 Shell 或者 Perl、Python 等高級腳本語言。
第43節(jié) 無情的測試
1、注重實(shí)效的程序員會受到找到自己 bug 的驅(qū)使,以免以后經(jīng)受由別人找到我們 bug 帶來的羞恥。
2、早測試,常測試,自動(dòng)化測試。要通過全部測試,編碼才算完成。
3、測試主要圍繞三個(gè)方面進(jìn)行:測試什么、怎樣測試、何時(shí)測試。
4、測試什么。測試類型有以下這些:
單元測試:單元測試是函數(shù)級,有時(shí)也算做模塊級的測試,要保證他們都正常通過。 集成測試:組成項(xiàng)目的子系統(tǒng)能工作,且它們之間能很好的協(xié)同。 驗(yàn)證和校驗(yàn):這個(gè)類似AB測,是產(chǎn)品層面的測試。 異常測試,資源耗盡,錯(cuò)誤情況,如何恢復(fù)等。 性能測試,壓力測試,負(fù)載測試:這些情況通常是服務(wù)器相關(guān)的測試流程。 可用性測試:也是產(chǎn)品項(xiàng)的測試,需要分析和調(diào)研,需求是否是有用的。
5、怎樣測試。主要介紹有哪些測試方法:
回歸測試:回歸測試通常是測試的后面階段,新舊功能一起測試,新功能不應(yīng)該影響舊功能。
測試數(shù)據(jù):對于一些特殊場景,測試數(shù)據(jù)能起到很大幫助,比如需要大量數(shù)據(jù),強(qiáng)調(diào)邊界條件的數(shù)據(jù),能展現(xiàn)特定字段的數(shù)據(jù)等。
GUI系統(tǒng):UI通常不好測試,所以應(yīng)該做好解耦,將邏輯和視圖拆分開進(jìn)行測試。
對測試進(jìn)行測試:故意制造一些bug,觀察你的測試系統(tǒng)能否發(fā)現(xiàn)。
徹底測試:這里需要強(qiáng)調(diào)的是測試覆蓋率,這其中需要強(qiáng)調(diào)的是測試狀態(tài)的覆蓋,而不是代碼覆蓋。要對不同狀態(tài)都覆蓋到。
6、何時(shí)進(jìn)行測試。盡早測試,而且測試應(yīng)該是自動(dòng)完成的,我們在提交代碼時(shí)就應(yīng)該保證測試已經(jīng)全部通過。
第44節(jié) 全都是寫
1、代碼要跟文檔緊密結(jié)合,我們要認(rèn)真對待注釋及文檔,他們不是可有可無的東西。
2、我們喜歡看到簡單的模塊級頭注釋,關(guān)于重要數(shù)據(jù)和類型聲明的注釋,以及給每個(gè)類和每個(gè)方法所加的簡要頭注釋,用于描述函數(shù)的用法和任何不明了的事情。
3、應(yīng)當(dāng)使用特定的格式進(jìn)行注釋,通常對應(yīng)語言或者 IDE 有推薦的注釋格式。
4、可執(zhí)行文檔,即使按照特定格式進(jìn)行注釋,然后利用工具提取注釋內(nèi)容并生成文檔。例如 JavaDoc
5、有時(shí)文檔撰寫者和開發(fā)并不是同一人,但他們應(yīng)當(dāng)接受同樣的原則,特別是 DRY,正交性,以及自動(dòng)化原則等。
iOS也有一個(gè)文檔生成工具:jazzy[2],支持 OC 和 Swift,它可以根據(jù)標(biāo)準(zhǔn)的注釋生成文檔。
第45節(jié) 極大的期望
1、某個(gè)項(xiàng)目團(tuán)隊(duì)奇跡般的完成了一個(gè)非常復(fù)雜的項(xiàng)目,但卻遭到用戶抵制,原因是該引用沒有幫助系統(tǒng)。所以考慮現(xiàn)實(shí),項(xiàng)目的成功是由它在多大程度上滿足了用戶的期望來衡量的。
2、要與客戶之間多交流期望,了解他們的需求,而不是一味沉溺在技術(shù)的世界里。
3、適當(dāng)制造驚喜,會有些通用性的技巧能讓項(xiàng)目獲得更好的體驗(yàn)。比如:
氣球式幫助 快捷鍵 日志文件分析器 自動(dòng)化安裝
第46節(jié) 傲慢與偏見
1、注重實(shí)效的程序員不會逃避責(zé)任,相反,我們樂于接受挑戰(zhàn),樂于使我們的業(yè)務(wù)知識廣為人知。
2、過去時(shí)代的手藝人為能在他們的作品上簽名而自豪,你也應(yīng)該如此。Sign Your Work.
3、Kent Beck 在極限編程(XP)里的建議是采用公共的代碼所有權(quán),其還要求了結(jié)對編程,以防匿名的危險(xiǎn)。所有權(quán)的好處是能為優(yōu)秀的開發(fā)帶來自豪感,并且當(dāng)人們在一段代碼上看到你的名字時(shí),會將其認(rèn)為質(zhì)量的保證。
參考資料
R.Swift: https://github.com/mac-cain13/R.swift
[2]jazzy: https://github.com/realm/jazzy
