[美] David,Thomas(大衛(wèi)托馬斯),Andrew,Hunt(安德魯亨特) 著,云風(fēng) 譯
適讀人群 :無(wú)論你是一個(gè)新的程序員,一個(gè)有經(jīng)驗(yàn)的程序員,還是一個(gè)負(fù)責(zé)軟件項(xiàng)目的經(jīng)理,都會(huì)通過(guò)本書獲得個(gè)人生產(chǎn)力、準(zhǔn)確性和工作滿意度的提高,從中習(xí)得的學(xué)習(xí)技能、習(xí)慣和態(tài)度,都將是你在職業(yè)生涯中獲得長(zhǎng)期成功的基礎(chǔ)。
√ 屹立 20 年影響力大作,成功案例數(shù)以千萬(wàn)計(jì),凌駕于任何語(yǔ)言|框架|方法之上。
√ 面向未來(lái)重寫全部?jī)?nèi)容,從程序員責(zé)任與職業(yè)發(fā)展,到靈活|易適配|可重用架構(gòu)。
√ 53個(gè)核心話題|99個(gè)高能提示,闡明軟件開發(fā)走向卓越之路及途中各種典型陷阱。
√ 編程界傳奇人物云風(fēng)操刀翻譯,至理|奧義|案例|技巧之原著精微,無(wú)不掘至毫巔。
◎與“軟件腐爛”做斗爭(zhēng)
◎持續(xù)學(xué)習(xí)
◎避免知識(shí)重復(fù)的陷阱
◎?qū)懗鲇袕椥浴?dòng)態(tài)、適配性強(qiáng)的代碼
◎駕馭基本工具的力量
◎避免依賴巧合編程
◎?qū)W習(xí)真正的需求
◎解決并發(fā)代碼的底層問(wèn)題
◎防范安全漏洞
◎建立務(wù)實(shí)程序員構(gòu)成的團(tuán)隊(duì)
◎?qū)δ愕墓ぷ骱褪聵I(yè)負(fù)責(zé)
◎無(wú)情而有效地做測(cè)試,包括基于特性的測(cè)試
◎組建務(wù)實(shí)的入門套件
◎取悅你的用戶
《程序員修煉之道》之所以在全球范圍內(nèi)廣泛傳播,被一代代開發(fā)者奉為圭臬,蓋因它可以創(chuàng)造出真正的價(jià)值:或編寫出更好的軟件,或探究出編程的本質(zhì),而所有收獲均不依賴于特定語(yǔ)言、框架和方法。時(shí)隔20年的新版,經(jīng)過(guò)全面的重新選材、組織和編寫,覆蓋哲學(xué)、方法、工具、設(shè)計(jì)、解耦、并發(fā)、重構(gòu)、需求、團(tuán)隊(duì)等務(wù)實(shí)話題的最佳實(shí)踐及重大陷阱,以及易于改造、復(fù)用的架構(gòu)技術(shù)。本書極具洞察力與趣味性,適合從初學(xué)者到架構(gòu)師的各階層讀者潛心研讀或增廣見聞。
譯者云風(fēng)(真名吳云洋),曾任網(wǎng)易杭州研究中心總監(jiān),是網(wǎng)易《大話西游》《夢(mèng)幻西游》等知名游戲的主要開發(fā)者;2011 年與前網(wǎng)易 COO 詹鐘暉聯(lián)合創(chuàng)辦簡(jiǎn)悅(EJOY)游戲公司,兼任 CTO,現(xiàn)該公司已被阿里收購(gòu);在互聯(lián)網(wǎng)、游戲界擁有較高技術(shù)影響力,常年發(fā)表博客文章,并著有《游戲之旅》及《Effective C++(評(píng)注版)》。
這樣的贊美一直不絕于耳:通過(guò)撰寫一本書來(lái)推動(dòng)整個(gè)行業(yè),是 Andy 和 Dave 用《程序員修煉之道:從小工到專家》完成的一大壯舉,無(wú)人可以超過(guò)。然而,有時(shí)兩次閃電的確會(huì)擊中同一個(gè)地方,這部名著的再版即為明證。其令人震撼的內(nèi)容更新,足以確保自身在未來(lái)二十年里繼續(xù)雄踞“精選軟件開發(fā)圖書”榜單之首,此可謂實(shí)至名歸。
—— VM (Vicky) Brasseur
瞻博網(wǎng)絡(luò)開源戰(zhàn)略總監(jiān)
如果想讓自己的軟件既領(lǐng)先于時(shí)代又易于維護(hù),就在手邊擺放一本《程序員修煉之道:通向務(wù)實(shí)的最高境界(第2版)》。本書充滿實(shí)用建議,有技術(shù)方面的,也有專業(yè)方面的,無(wú)不能讓你和你的項(xiàng)目受益多年。
—— Andrea Goulet
Corgibytes 公司 CEO
LegacyCode.Rocks 創(chuàng)始人
可以說(shuō),《程序員修煉之道》完全改變了我的職業(yè)軌跡,為我指明了軟件領(lǐng)域的成功方向。正是這本書,開闊了我的視野,讓我意識(shí)到自己不僅僅是龐大機(jī)器上的一枚齒輪,有朝一日也能藉由修煉成為匠師。它是我生命中重要的一本書。
—— Obie Fernandez
《Rails 之道》作者
初讀此書的讀者,在見識(shí)到那個(gè)軟件開發(fā)實(shí)踐的新世界時(shí),立刻充滿期待。而第一版圖書,對(duì)塑造這樣一個(gè)迷人的現(xiàn)代世界,的確厥功至偉?,F(xiàn)在,第一版的讀者將有機(jī)會(huì)在新版中重溫舊夢(mèng),再次接受洞察力和實(shí)踐智慧的洗禮,而《程序員修煉之道》當(dāng)初正因此被奉為圭臬。更重要的是,經(jīng)由兩位專家親手組織與更新的再版圖書,業(yè)已因富含新知而重?zé)ㄇ啻骸?/p>
—— David A. Black
《Ruby程序員修煉之道》作者
舊版的《程序員修煉之道》一直駐留在我的書架上。從很久以前它改變我作為一個(gè)程序員的工作方式那一刻起,我讀了又讀。在這個(gè)全新的版本中,一切似乎都已改變,而一切又仿佛還在那里。雖然我們現(xiàn)在換用 iPad 閱讀新版,其代碼示例也改由現(xiàn)代編程語(yǔ)言實(shí)現(xiàn)——但是蘊(yùn)藏其中的概念、思想和態(tài)度,亙古不變且通行宇宙。二十年過(guò)去,這本書的價(jià)值從未折損?,F(xiàn)在乃至將來(lái)的開發(fā)人員,都有機(jī)會(huì)從 Andy 和 Dave 的深刻洞見中獲益,正如當(dāng)年的我一樣,這讓人備感欣慰。
—— Sandy Mamoli
敏捷教練
How Self-Selection Lets People Excel 作者
二十年前,《程序員修煉之道》的第一版徹底顛覆了我的技術(shù)生涯。這次的新版,也將對(duì)你有此影響。
—— Mike Cohn
《Scrum敏捷軟件開發(fā)》
《敏捷估計(jì)與規(guī)劃》
《用戶故事與敏捷方法》作者
序 XVII
新版前言 XXI
第一版前言 XV
提示1:關(guān)注你的技藝 XVII
如果你不關(guān)心怎么做好,為什么還要花時(shí)間去開發(fā)軟件呢?
提示2:思考!思考你的工作 XVII
關(guān)掉輔助駕駛,由自己掌控,持續(xù)不斷地評(píng)估所做的工作。
第1章 務(wù)實(shí)的哲學(xué) 1
1 人生是你的 2
提示3:你有權(quán)選擇 3
人生是自己的。把握住人生,讓它如你所愿。
2 我的源碼被貓吃了 3
提示4:提供選擇,別找借口 5
提供選擇而不是去找理由。不要只說(shuō)做不到;解釋一下都能做些什么。
3 軟件的熵 6
提示5:不要放任破窗 7
只要看到不好的設(shè)計(jì)、錯(cuò)誤的決策、糟糕的代碼,就趕緊去糾正。
4 石頭做的湯和煮熟的青蛙 9
提示6:做推動(dòng)變革的催化劑 10
你無(wú)法強(qiáng)迫人們?nèi)ジ淖儯梢哉故久篮梦磥?lái),并幫助他們參與創(chuàng)造。
提示7:牢記全景 10
不要過(guò)度沉浸于細(xì)枝末節(jié),以免察覺不到周圍正在發(fā)生的事情。
5 夠好即可的軟件 11
提示8:將質(zhì)量要求視為需求問(wèn)題 12
讓用戶參與對(duì)項(xiàng)目真實(shí)質(zhì)量需求的確定。
6 知識(shí)組合 14
提示9:對(duì)知識(shí)組合做定期投資 16
養(yǎng)成學(xué)習(xí)的習(xí)慣。
提示10:批判性地分析你讀到和聽到的東西 18
不要受供應(yīng)商、媒體炒作或教條的影響,根據(jù)自身和項(xiàng)目的實(shí)際情況來(lái)分析信息。
7 交流! 20
提示11:英語(yǔ)就是另一門編程語(yǔ)言 20
將英語(yǔ)視作一門編程語(yǔ)言。寫文檔和編程一樣要遵循 DRY 原則、ETC、自動(dòng)化等。
提示12:說(shuō)什么和怎么說(shuō)同樣重要 23
如果無(wú)法有效交流,任何偉大的想法都是沒(méi)有意義的。
提示13:把文檔嵌進(jìn)去,而不要栓在表面 24
與代碼隔離的文檔,很難保持正確并及時(shí)更新。
第2章 務(wù)實(shí)的方法 27
8 優(yōu)秀設(shè)計(jì)的精髓 28
提示14:優(yōu)秀的設(shè)計(jì)比糟糕的設(shè)計(jì)更容易變更 28
適合使用者的事物,都已經(jīng)過(guò)良好設(shè)計(jì)。對(duì)代碼來(lái)說(shuō),這意味著必須適應(yīng)變化。
9 DRY——邪惡的重復(fù) 30
提示15:DRY——不要重復(fù)自己 31
系統(tǒng)中的每一條知識(shí),都必須有單一且無(wú)歧義的權(quán)威陳述。
提示16:讓復(fù)用變得更容易 39
只要復(fù)用方便,人們就會(huì)去做。創(chuàng)建一個(gè)支持復(fù)用的環(huán)境。
10 正交性 40
提示17:消除不相關(guān)事物之間的影響 41
設(shè)計(jì)的組件,需要自成一體、獨(dú)立自主,有單一的清晰定義的意圖。
11 可逆性 48
提示18:不設(shè)最終決定 50
不要把決定刻在石頭上,而要將其視為寫在沙灘上的東西,時(shí)刻準(zhǔn)備應(yīng)變。
提示19:放棄追逐時(shí)尚 50
尼爾·福特說(shuō)過(guò):“昨日之最佳實(shí)踐,即明日之反模式?!币诨驹瓌t去選擇架構(gòu),而不應(yīng)盲從于流行。
12 曳光彈 51
提示20:使用曳光彈找到目標(biāo) 53
通過(guò)不斷嘗試并看清著彈點(diǎn),曳光彈可確保你最終擊中目標(biāo)。
13 原型與便簽 57
提示21:用原型學(xué)習(xí) 58
制作原型旨在學(xué)習(xí)經(jīng)驗(yàn),其價(jià)值不在于過(guò)程中產(chǎn)生的代碼,而在于得到的教訓(xùn)。
14 領(lǐng)域語(yǔ)言 60
提示22:靠近問(wèn)題域編程 61
用問(wèn)題領(lǐng)域的語(yǔ)言來(lái)做設(shè)計(jì)和編程。
15 估算 67
提示23:通過(guò)估算來(lái)避免意外 67
開始之前做估算,能提前發(fā)現(xiàn)潛在問(wèn)題。
提示24:根據(jù)代碼不斷迭代進(jìn)度表 72
利用實(shí)施過(guò)程中獲得的經(jīng)驗(yàn)來(lái)精細(xì)化項(xiàng)目的時(shí)間尺度。
第3章 基礎(chǔ)工具 74
16 純文本的威力 75
提示25:將知識(shí)用純文本保存 76
純文本不會(huì)過(guò)時(shí)。它能夠讓你的工作事半功倍,并能簡(jiǎn)化調(diào)試和測(cè)試工作。
17 Shell游戲 79
提示26:發(fā)揮 Shell 命令的威力 80
當(dāng)圖形化界面無(wú)法勝任時(shí),使用 Shell。
18 加強(qiáng)編輯能力 82
提示27:游刃有余地使用編輯器 82
既然編輯器是至關(guān)重要的工具,不妨了解一下如何用它更快更準(zhǔn)確地實(shí)現(xiàn)需求。
19 版本控制 85
提示28:永遠(yuǎn)使用版本控制 87
版本控制為你的工作創(chuàng)造了一個(gè)時(shí)間機(jī)器,可以用它重返過(guò)去。
20 調(diào)試 90
提示29:去解決問(wèn)題,而不是責(zé)備 91
Bug 到底來(lái)自你的失誤還是別人的失誤真的不重要——它終究是你的問(wèn)題,需要你來(lái)修復(fù)。
提示30:不要恐慌 91
不管是對(duì)銀河系搭車客,還是對(duì)開發(fā)者來(lái)說(shuō),都應(yīng)這樣。
提示31:修代碼前先讓代碼在測(cè)試中失敗 93
在你修 Bug 前,先創(chuàng)建一個(gè)聚焦于該 Bug 的測(cè)試。
提示32:讀一下那些該死的出錯(cuò)信息 93
大多數(shù)異常都能告訴失敗之物與失敗之處。如果足夠幸運(yùn),你甚至能得到具體的參數(shù)值。
提示33:“select”沒(méi)出問(wèn)題 97
在操作系統(tǒng)或編譯器中發(fā)現(xiàn) Bug 非常罕見,甚至在第三方產(chǎn)品或庫(kù)中也是如此。Bug 大多出現(xiàn)在應(yīng)用程序中。
提示34:不要假設(shè),要證明 97
在真實(shí)環(huán)境中證實(shí)你的假設(shè)——要依賴真實(shí)的數(shù)據(jù)及邊界條件。
21 文本處理 99
提示35:學(xué)習(xí)一門文本處理語(yǔ)言 99
既然每天都要花大量的時(shí)間與文本打交道,何不讓計(jì)算機(jī)幫你分擔(dān)一二?
22 工程日記 101
第4章 務(wù)實(shí)的偏執(zhí) 103
提示36:你無(wú)法寫出完美的軟件 103
軟件不可能是完美的。對(duì)于在所難免的錯(cuò)誤,要保護(hù)代碼和用戶免受其影響。
23 契約式設(shè)計(jì) 104
提示37:通過(guò)契約進(jìn)行設(shè)計(jì) 107
代碼是否不多不少剛好完成它宣稱要做的事情,可以使用契約加以校驗(yàn)和文檔化。
24 死掉的程序不會(huì)說(shuō)謊 113
提示38:盡早崩潰 114
徹底死掉的程序通常比有缺陷的程序造成的損害要小。
25 斷言式編程 115
提示39:使用斷言去預(yù)防不可能的事情 115
如果一件事情不可能發(fā)生,那么就用斷言來(lái)確保其的確不會(huì)發(fā)生。斷言在校驗(yàn)?zāi)愕募僭O(shè),要使用斷言在不確定的世界中將你的代碼保護(hù)起來(lái)。
26 如何保持資源的平衡 119
提示40:有始有終 119
只要有可能,對(duì)資源進(jìn)行分配的函數(shù)或?qū)ο缶陀胸?zé)任去釋放該資源。
提示41:在局部行動(dòng) 122
將易變的變量維持在一個(gè)范圍內(nèi),打開資源的過(guò)程要短暫且明顯可見。
27 不要沖出前燈范圍 127
提示42:小步前進(jìn)——由始至終 127
永遠(yuǎn)小步前進(jìn),不斷檢查反饋,并且在推進(jìn)前先做調(diào)整。
提示43:避免占卜 129
只在你能看到的范圍內(nèi)做計(jì)劃。
第5章 寧彎不折 130
28 解耦 131
提示44:解耦代碼讓改變更容易 132
耦合使事物緊緊綁定在一起,以至于很難只改變其中之一。
提示45:只管命令不要詢問(wèn) 133
不要從對(duì)象中取出值,在加以變換后再塞回去,讓對(duì)象自己來(lái)完成這些工作。
提示46:不要鏈?zhǔn)秸{(diào)用方法 135
當(dāng)訪問(wèn)某事物時(shí),使用的點(diǎn)號(hào)不要超過(guò)一個(gè)。
提示47:避免全局?jǐn)?shù)據(jù) 137
最好給每個(gè)方法增加一個(gè)額外的參數(shù)。
提示48:如果全局唯一非常重要,那么將它包裝到API 中 137
……但是,僅限于你真的非常希望它是全局的。
29 在現(xiàn)實(shí)世界中拋球雜耍 139
30 變換式編程 149
提示49:編程講的是代碼,而程序談的是數(shù)據(jù) 151
所有的程序都在變換數(shù)據(jù)——將輸入轉(zhuǎn)換為輸出。開始用變換式方法來(lái)設(shè)計(jì)吧!
提示50:不要囤積狀態(tài),傳遞下去 156
不要把數(shù)據(jù)保持在函數(shù)或模塊的內(nèi)部,拿出來(lái)傳遞下去。
31 繼承稅 162
提示51:不要付繼承稅 165
考慮一下能更好滿足需求的替代方案,比如接口、委托或mixin。
提示52:盡量用接口來(lái)表達(dá)多態(tài) 167
無(wú)需繼承引入的耦合,接口就能明確描述多態(tài)性。
提示53:用委托提供服務(wù):“有一個(gè)”勝過(guò)“是一個(gè)” 167
不要從服務(wù)中繼承,應(yīng)該包含服務(wù)。
提示54:利用 mixin 共享功能 169
mixin 不必承擔(dān)繼承稅就可以給類添加功能,而與接口結(jié)合可以讓多態(tài)不再令人痛苦。
32 配置 170
提示55:使用外部配置參數(shù)化應(yīng)用程序 170
如果代碼對(duì)一些在應(yīng)用程序發(fā)布后還有可能改變的值有所依賴,那么就在應(yīng)用外部維護(hù)這些值。
第6章 并發(fā) 174
33 打破時(shí)域耦合 175
提示56:通過(guò)分析工作流來(lái)提高并發(fā)性 176
利用用戶工作流中的并發(fā)性。
34 共享狀態(tài)是不正確的狀態(tài) 179
提示57:共享狀態(tài)是不正確的狀態(tài) 180
共享狀態(tài)會(huì)帶來(lái)無(wú)窮的麻煩,而且往往只有重啟才能解決。
提示58:隨機(jī)故障通常是并發(fā)問(wèn)題 186
或許時(shí)間和上下文的變化能暴露并發(fā)Bug,但并發(fā)Bug無(wú)法始終保持一致,也很難重現(xiàn)。
35 角色與進(jìn)程 187
提示59:用角色實(shí)現(xiàn)并發(fā)性時(shí)不必共享狀態(tài) 188
使用角色來(lái)管理并發(fā)狀態(tài),可以避免顯式的同步。
36 黑板 193
提示60:使用黑板來(lái)協(xié)調(diào)工作流 195
使用黑板來(lái)協(xié)調(diào)不相關(guān)的事實(shí)和代理人,能同時(shí)保持參與者之間的獨(dú)立性和孤立性。
第7章 當(dāng)你編碼時(shí) 198
37 聽從蜥蜴腦 199
提示61:傾聽你內(nèi)心的蜥蜴 201
當(dāng)編程舉步維艱時(shí),其實(shí)是潛意識(shí)在告訴你有什么地方不對(duì)勁。
38 巧合式編程 204
提示62:不要依賴巧合編程 207
只能依賴可靠的事物。注意偶然事件的復(fù)雜性,不要混淆快樂(lè)的巧合與有目的的計(jì)劃。
39 算法速度 210
提示63:評(píng)估算法的級(jí)別 214
在開始編程前,對(duì)這件事情大概會(huì)花多長(zhǎng)時(shí)間要有概念。
提示64:對(duì)估算做測(cè)試 214
針對(duì)算法的數(shù)學(xué)分析無(wú)法說(shuō)明所有問(wèn)題,嘗試在目標(biāo)環(huán)境中測(cè)試一下執(zhí)行代碼的耗時(shí)。
40 重構(gòu) 216
提示65:盡早重構(gòu),經(jīng)常重構(gòu) 219
像除草和翻整花園那樣,只要有需要就對(duì)代碼進(jìn)行重新編寫、修訂和架構(gòu),以便找到問(wèn)題的根源并加以修復(fù)。
41 為編碼測(cè)試 220
提示66:測(cè)試與找 Bug 無(wú)關(guān) 221
測(cè)試是觀察代碼的一個(gè)視角,可以從中得到針對(duì)設(shè)計(jì)、接口和耦合度的反饋。
提示67:測(cè)試是代碼的第一個(gè)用戶 222
用測(cè)試的反饋來(lái)引導(dǎo)工作。
提示68:既非自上而下,也不自下而上,基于端對(duì)端構(gòu)建 225
創(chuàng)建一小塊端到端的功能,從中獲悉問(wèn)題之所在。
提示69:為測(cè)試做設(shè)計(jì) 228
寫下代碼之前先從測(cè)試角度思考。
提示70:要對(duì)軟件做測(cè)試,否則只能留給用戶去做 230
無(wú)情地測(cè)試,不要等用戶來(lái)幫你找 Bug。
42 基于特性測(cè)試 231
提示71:使用基于特性的測(cè)試來(lái)校驗(yàn)假設(shè) 231
基于特性的測(cè)試將會(huì)進(jìn)行你從未想過(guò)的嘗試,并會(huì)以你不曾打算采用的方式操練你的代碼。
43 出門在外注意安全 238
提示72:保持代碼簡(jiǎn)潔,讓攻擊面最小 241
復(fù)雜的代碼給 Bug 以滋生之沃土,給攻擊者以可趁之機(jī)。
提示73:盡早打上安全補(bǔ)丁 243
攻擊者會(huì)盡可能快地部署攻擊,你必須快上加快。
44 事物命名 245
提示74:好好取名;需要時(shí)更名 249
用名字向讀者表達(dá)你的意圖,并且在意圖改變時(shí)及時(shí)更名。
第8章 項(xiàng)目啟動(dòng)之前 251
45 需求之坑 252
提示75:無(wú)人確切知道自己想要什么 252
他們或許知道大概的方向,但不會(huì)了解過(guò)程的曲折。
提示76:程序員幫助人們理解他們想要什么 253
軟件開發(fā)更像是一種由用戶和程序員協(xié)同創(chuàng)造的行為。
提示77:需求是從反饋循環(huán)中學(xué)到的 254
理解需求需要探索和反饋,因此決策的結(jié)果可以用來(lái)完善最初的想法。
提示78:和用戶一起工作以便從用戶角度思考 255
這是看透系統(tǒng)將如何被真正使用的最佳方法。
提示79:策略即元數(shù)據(jù) 256
不要將策略硬編碼進(jìn)系統(tǒng),而應(yīng)該將其表達(dá)為系統(tǒng)的一組元數(shù)據(jù)。
提示80:使用項(xiàng)目術(shù)語(yǔ)表 259
為項(xiàng)目的所有特定詞匯創(chuàng)建一張術(shù)語(yǔ)表,并且在單一源頭維護(hù)。
46 處理無(wú)法解決的難題 260
提示81:不要跳出框框思考——找到框框 261
在面對(duì)無(wú)法解決的難題時(shí),識(shí)別出真正的約束??梢詥?wèn)自己:“必須這樣做才能搞定嗎?必須搞定它嗎?”
47 攜手共建 264
提示82:不要一個(gè)人埋頭鉆進(jìn)代碼中 267
編程往往困難又費(fèi)力,找個(gè)朋友和你一起干。
提示83:敏捷不是一個(gè)名詞;敏捷有關(guān)你如何做事 267
敏捷是一個(gè)形容詞,有關(guān)如何做事情。
48 敏捷的本質(zhì) 267
第9章 務(wù)實(shí)的項(xiàng)目 271
49 務(wù)實(shí)的團(tuán)隊(duì) 272
提示84:維持小而穩(wěn)定的團(tuán)隊(duì) 272
團(tuán)隊(duì)?wèi)?yīng)保持穩(wěn)定、小巧,團(tuán)隊(duì)中的每個(gè)人都應(yīng)相互信任、互相依賴。
提示85:排上日程以待其成 274
如果你不把事情納入日程表,它們就不會(huì)發(fā)生。反思、實(shí)驗(yàn)、學(xué)習(xí)、提高技能,這些事都應(yīng)放入日程表。
提示86:組織全功能的團(tuán)隊(duì) 276
圍繞功能而不是工作職能組織團(tuán)隊(duì)。不要將 UI/UX 設(shè)計(jì)者從程序員中分離出去,也不要分開前端和后端;不要區(qū)分?jǐn)?shù)據(jù)建模者和測(cè)試人員,以及開發(fā)和設(shè)計(jì)。構(gòu)建一個(gè)團(tuán)隊(duì),這樣你就可以漸進(jìn)地不斷迭代端到端的代碼。
50 椰子派不上用場(chǎng) 277
提示87:做能起作用的事,別趕時(shí)髦 279
不要僅僅因?yàn)閯e的公司正在那么干就采納一項(xiàng)技術(shù)或采用一個(gè)開發(fā)方法,而是要采用自己所處環(huán)境中對(duì)團(tuán)隊(duì)有效的東西。
提示88:在用戶需要時(shí)交付 281
不要卡著流程要求,刻意等到幾周甚至幾個(gè)月后才交付。
51 務(wù)實(shí)的入門套件 281
提示89:使用版本控制來(lái)驅(qū)動(dòng)構(gòu)建、測(cè)試和發(fā)布 282
利用提交或推送來(lái)觸發(fā)構(gòu)建、測(cè)試、發(fā)布,利用版本控制的標(biāo)簽來(lái)進(jìn)行生產(chǎn)部署。
提示90:盡早測(cè)試,經(jīng)常測(cè)試,自動(dòng)測(cè)試 283
每次構(gòu)建都跑一下的測(cè)試,要比束之高閣的測(cè)試計(jì)劃有效得多。
提示91:直到所有的測(cè)試都已運(yùn)行,編碼才算完成 283
無(wú)須多言。
提示92:使用破壞者檢測(cè)你的測(cè)試 285
在一個(gè)單獨(dú)的源碼副本中特意引入 Bug,驗(yàn)證測(cè)試能否將其捕獲。
提示93:測(cè)試狀態(tài)覆蓋率,而非代碼覆蓋率 286
要識(shí)別并測(cè)試重要的程序狀態(tài),只測(cè)試一行行的代碼是不夠的。
提示94:每個(gè) Bug 只找一次 286
只要人類測(cè)試者找到一個(gè) Bug ,就應(yīng)該是該 Bug 最后一次被人類發(fā)現(xiàn)。從此之后,自動(dòng)化測(cè)試完全可以發(fā)現(xiàn)它。
提示95:不要使用手動(dòng)程序 287
計(jì)算機(jī)能一次又一次,按照同樣的次序,執(zhí)行相同的指令。
52 取悅用戶 288
提示96:取悅用戶,而不要只是交付代碼 289
為用戶開發(fā)能夠帶來(lái)商業(yè)價(jià)值的解決方案,并讓他們每天都感到愉快。
提示97:在作品上簽名 290
過(guò)去的工匠在為他們的作品簽名時(shí)非常自豪,你也應(yīng)該這樣。
53 傲慢與偏見 290
跋 292
提示98:先勿傷害 293
犯錯(cuò)在所難免,確保犯錯(cuò)后沒(méi)人會(huì)因此受難。
提示99:不要助紂為虐 294
因?yàn)檫@樣做你也有變成紂王的風(fēng)險(xiǎn)。
參考文獻(xiàn) 295
練習(xí)的參考答案 297
譯者跋 312
序
我還記得 Dave 和 Andy 第一次在推特上談?wù)撨@本書的新版的那一刻——這可是一條大新聞。在編程社區(qū),所見之處都是對(duì)這條大新聞興奮的回應(yīng),人們的期待塞滿了我的信息流。二十年過(guò)去了,《程序員修煉之道》這本書的地位不遜于當(dāng)年。
承載這樣一段歷史的一本書,能引起這樣的反響,本身就說(shuō)明了很多問(wèn)題。為了寫這篇序,我有幸在尚未出版前閱讀了本書,讀后我就明白了它為什么會(huì)引起這么大的轟動(dòng)。本來(lái),一本書被冠以技術(shù)圖書之名,給人的印象應(yīng)該是不太好的。因?yàn)榧夹g(shù)圖書常常令人生畏——充斥著深?yuàn)W的詞匯、晦澀的術(shù)語(yǔ)和令人費(fèi)解的例子,不經(jīng)意間就會(huì)讓你覺得自己很愚蠢。而且,作者越有經(jīng)驗(yàn),就越容易忘記初學(xué)者在學(xué)習(xí)新概念時(shí)的感覺。
Dave 和 Andy 的作品,卻能透出那種只有剛剛學(xué)到這些課程的人才會(huì)有的興奮感,盡管他們已有幾十年的編程經(jīng)驗(yàn),卻戰(zhàn)勝了寫出這種感覺的挑戰(zhàn)。他們不會(huì)居高臨下地指指點(diǎn)點(diǎn),不會(huì)假定你是個(gè)專家,甚至不認(rèn)為你已讀過(guò)本書第一版,僅僅把你當(dāng)成想要變得更好的程序員而已。他們不惜用整本書的篇幅來(lái)幫助你達(dá)到目標(biāo),一步一個(gè)腳印。
公平地說(shuō),在這方面,他們?cè)谶^(guò)往已經(jīng)成績(jī)斐然。最初的本書第一版,包含了許多具體的例子、新想法和實(shí)用的技巧,可以幫助你修煉編程所需的“肌肉”和“大腦”,這些東西到今天仍然適用。但是,這次在新版圖書中,又有了兩項(xiàng)改進(jìn)。
第一項(xiàng)顯而易見:刪除了一些較老的引用內(nèi)容和過(guò)時(shí)的例子,增補(bǔ)了大量新鮮、現(xiàn)代的內(nèi)容。循環(huán)不變式或構(gòu)建機(jī)這樣的例子已經(jīng)看不到了。Dave 和 Andy 保留了第一版書中的重要內(nèi)容,以確保相應(yīng)的課程依然有效,而且讀者也不必受舊示例的干擾。對(duì)于像 DRY(不要重復(fù)自己)這樣的舊思想,上面的灰塵已被撣去,并且涂上了一層新油漆——這樣做真的讓其熠熠生輝。
而第二項(xiàng),才是這次新版圖書發(fā)布真正令人興奮的地方。在寫完本書第一版后,他們有機(jī)會(huì)思考自己想要說(shuō)什么,想讓讀者獲得什么,以及讀者是如何接受這些信息的。他們得到了這些課程的反饋,也看到了讀者在哪里被卡住、有什么需要改進(jìn),以及哪些內(nèi)容被誤解。在這本書通過(guò)全世界程序員的雙手和心靈傳播的二十年間,Dave 和 Andy 研究了這些回應(yīng),并且形成了新的想法和理念。
他們認(rèn)識(shí)到自主權(quán)的重要性,并且意識(shí)到,相比大多數(shù)其他專業(yè)人員,開發(fā)者或許更能為自己做主。他們以簡(jiǎn)單而深刻的啟示開始這本書:“人生是你的?!边@喚起了我們自己的力量,它就蘊(yùn)含在我們的代碼庫(kù)、工作和職業(yè)生涯中。這也為本書的其他內(nèi)容定下了基調(diào)——它不僅僅是又一本充滿代碼示例的技術(shù)圖書。
這本書必定會(huì)在擺滿各種技術(shù)圖書的書架上脫穎而出,因?yàn)樗斫馍頌橐幻绦騿T到底意味著什么。編程關(guān)涉諸事——盡量減少未來(lái)的痛苦,讓隊(duì)友更輕松,做錯(cuò)事情后能夠重新振作起來(lái),養(yǎng)成良好的習(xí)慣,以及理解工具集。編程只是程序員世界的一部分,而這本書探索了整個(gè)世界。
我在思考編碼之旅上花了很多時(shí)間。我不是從小就開始接觸編程的,大學(xué)里也沒(méi)學(xué)過(guò)編程課??梢哉f(shuō),我的青少年時(shí)光并沒(méi)有花在“擺弄”科技上,直到二十來(lái)歲的時(shí)候才進(jìn)入了編程的世界,因而亟須想明白一件事情:成為一名程序員意味著什么。編程社區(qū)與我曾經(jīng)身處的其他社區(qū)非常不同。其獨(dú)特之處在于,人們無(wú)不醉心于學(xué)習(xí)和實(shí)踐,這既令人生畏,又讓人耳目一新。
這對(duì)我來(lái)說(shuō),真像進(jìn)入一個(gè)全新的世界。就算去到一個(gè)新城鎮(zhèn),也有必要了解鄰居、挑選雜貨店、找到最好的咖啡店。我花了一段時(shí)間來(lái)了解地形,找到了最有效的路線,避開了交通最繁忙的街道,并且知道了什么時(shí)候交通可能會(huì)出問(wèn)題。等到天氣變化,我又要去置辦應(yīng)季的新衣。
來(lái)到一個(gè)新城鎮(zhèn)的頭幾周,甚至是頭幾個(gè)月,可能會(huì)很害怕。如果有一個(gè)已經(jīng)在這里住了一段時(shí)間的鄰居,而且他知識(shí)淵博又友好,那不是再好不過(guò)的事情嗎?誰(shuí)能帶你四處參觀,誰(shuí)能領(lǐng)你去那些咖啡店?當(dāng)然是一個(gè)在當(dāng)?shù)卮俗銐蜷L(zhǎng)時(shí)間的,了解當(dāng)?shù)匚幕?、?dāng)?shù)孛}搏的人。這樣你不僅有家的感覺,還能成為一個(gè)同樣有貢獻(xiàn)的成員。Dave 和 Andy 就是這樣的鄰居。
一個(gè)準(zhǔn)新人,更容易對(duì)成為程序員的過(guò)程,而不是對(duì)編程的行為不知所措。因此,必須對(duì)整個(gè)心態(tài)做一次切換——改變習(xí)慣、行為和期望。僅僅知道如何編程,并不會(huì)讓你成為一名更好的程序員,在這個(gè)過(guò)程中必須經(jīng)歷有意識(shí)和深思熟慮的實(shí)踐。好在現(xiàn)在有了這本書,可以有效地指導(dǎo)你成為更好的程序員。
但不要搞錯(cuò)了——這本書不會(huì)告訴你編程應(yīng)該是怎樣的,它并沒(méi)有使用那種哲學(xué)或?qū)徟械姆绞剑皇呛?jiǎn)單、明了地告訴你,什么是務(wù)實(shí)的程序員——他們?nèi)绾尾僮鳌⑷绾翁幚泶a。作者讓你自己決定是否想成為其中的一員。如果你覺得不適合,也沒(méi)有人會(huì)怪罪你。但如果你決定成為其中的一員,作者就是你的友好鄰居,會(huì)陪伴左右、為你指路。
Saron Yitbarek
CodeNewbie 創(chuàng)始人及 CEOCommand Line Heroes 主辦者
新版前言
在20世紀(jì)90年代,我們?cè)谂c一些項(xiàng)目存在問(wèn)題的公司合作時(shí),發(fā)現(xiàn)總是在對(duì)每個(gè)人說(shuō)同樣的話:也許你應(yīng)該在發(fā)布之前先測(cè)試一下。為什么代碼只能在 Mary 的機(jī)器上構(gòu)建?為什么沒(méi)有人問(wèn)一下用戶呢?
為了節(jié)省與新客戶打交道的時(shí)間,我們開始做筆記。這些筆記最終變成了《程序員修煉之道》這本書。令人驚訝的是,這本書似乎引起了大家的共鳴,在過(guò)去的二十年間,這本書一直很受歡迎。
但是二十年對(duì)于軟件領(lǐng)域來(lái)說(shuō)已經(jīng)過(guò)了好幾代。如果一個(gè)開發(fā)者從 1999 年直接穿越到今天的團(tuán)隊(duì)中,面對(duì)這個(gè)陌生的新世界一定會(huì)備感掙扎。但20世紀(jì)90年代的世界對(duì)今天的開發(fā)者來(lái)說(shuō)同樣陌生。書中所引用的 CORBA、CASE 工具,以及索引、循環(huán)這些東西,放在今天,充其量不過(guò)略顯古雅有趣,而更多的會(huì)給人帶來(lái)困擾。
與此同時(shí),二十年對(duì)常識(shí)沒(méi)有絲毫影響。技術(shù)可能改變了,但人沒(méi)有。實(shí)踐和方法中的閃光點(diǎn),在今天看來(lái)光芒依舊。在這些方面,本書保鮮如初。
所以,當(dāng)我們要出版這本二十周年紀(jì)念版的時(shí)候,必須做出抉擇——是回顧和更新前一版中引用的技術(shù)后就大功告成,還是充分借鑒這平添的二十年豐富經(jīng)驗(yàn),重新審視前一版所推崇的實(shí)踐背后的種種假設(shè)。
最終,我們兩者都做了。
因此,這本書有點(diǎn)像忒修斯之船。書中大約三分之一的主題是全新的,而其余的大部分都被部分或全部重寫了。我們的目的是,讓內(nèi)容變得更清晰、更貼切,并在某種程度上不受時(shí)間的影響。
我們做了一些艱難的決定。刪除了參考資料附錄,這樣做既因?yàn)樗鼰o(wú)法持續(xù)更新,也因?yàn)楫?dāng)你有此需要時(shí)很容易就能搜索獲得。我們重新組織了與并發(fā)有關(guān)的主題,這是因?yàn)榭紤]到當(dāng)前有著大量的并行硬件,卻缺乏處理并行的好方法。我們還添加了一些內(nèi)容來(lái)反映不斷變化的認(rèn)知和環(huán)境,從我們幫助發(fā)起的敏捷運(yùn)動(dòng),到對(duì)函數(shù)式編程語(yǔ)境的日益接受,再到對(duì)隱私和安全性方面日益增長(zhǎng)的需求。
然而有趣的是,我們之間關(guān)于版本內(nèi)容的爭(zhēng)論比寫第一個(gè)版本時(shí)要少得多。重要的東西更容易辨別,這已是我們的共識(shí)。
無(wú)論如何,這本書最后就是這個(gè)樣子了,請(qǐng)享用吧。你也許可以從中吸取一些新的做法,也許會(huì)覺得我們建議的某些東西是錯(cuò)的,不妨把它們都帶到你的工作中去,然后給我們反饋。
但是,最重要的是,記住過(guò)程要開心。
這本書是如何組織的
這本書是許多短小主題的合集。每一個(gè)主題都針對(duì)特定的話題而獨(dú)立成章。你會(huì)發(fā)現(xiàn)大量的交叉引用,這有助于把各個(gè)主題連貫起來(lái)。你可以以任意次序隨意閱讀這些主題——這不是一本需要從頭到尾閱讀的書。
偶爾你會(huì)看到一個(gè)寫有提示n的框起來(lái)的標(biāo)簽塊(比如位于第XVII頁(yè)的提示1:關(guān)注你的技藝)。這些提示不僅是文中的重點(diǎn),在我們眼里也是一條條生命——我們每天都賴以為生。
我們已盡可能適時(shí)地在書中加入了練習(xí)和挑戰(zhàn)。練習(xí)通常有相對(duì)簡(jiǎn)單的答案,而挑戰(zhàn)則更加開放。為了讓你理解我們的思維方式,在附錄里我們列出了這些練習(xí)的答案,但是擁有唯一正確答案的問(wèn)題并不多。挑戰(zhàn)或許能用于高級(jí)編程課程中的小組討論,或許能作為論文寫作的基礎(chǔ)。
本書還有一個(gè)簡(jiǎn)短的參考文獻(xiàn),列出了我們明確引用的圖書和文章。
名字有什么含義
“我用一個(gè)詞,”矮胖子相當(dāng)傲慢地說(shuō),“總是同我想要說(shuō)的恰如其分的,既不重,也不輕。”
—— 路易斯·卡羅《愛麗絲鏡中奇遇》
在整本書中,你會(huì)發(fā)現(xiàn)各種各樣的行話——要么原本是完好的英語(yǔ)單詞,卻被曲解為技術(shù)詞,要么是一些可怕的合成詞,由那些對(duì)語(yǔ)言充滿怨恨的計(jì)算機(jī)科學(xué)家賦予其意義。當(dāng)我們第一次使用這些行話時(shí),會(huì)嘗試定義它們,或者至少對(duì)其含義給出解釋。當(dāng)然,肯定還有漏網(wǎng)之魚,而且像對(duì)象和關(guān)系型數(shù)據(jù)庫(kù)這種已被廣泛使用的,再下一次定義就有點(diǎn)畫蛇添足了。如果你遇到一個(gè)以前沒(méi)見過(guò)的術(shù)語(yǔ),請(qǐng)不要跳過(guò)它,不妨花點(diǎn)時(shí)間去查一下,可以在網(wǎng)上查,也可以在計(jì)算機(jī)科學(xué)的課本上查。如果有機(jī)會(huì)還可以給我們發(fā)郵件投訴,這樣我們就可以在本書下一版中增加一個(gè)定義。
既然話已至此,我們決定報(bào)復(fù)一下計(jì)算機(jī)科學(xué)家。有時(shí)候,明明有一些非常好的術(shù)語(yǔ),對(duì)某個(gè)概念表達(dá)得很好,但我們卻決定不使用這些術(shù)語(yǔ)。為什么?因?yàn)楝F(xiàn)有的術(shù)語(yǔ)通常局限于特定的問(wèn)題領(lǐng)域,或者特定的開發(fā)階段。而本書的基本哲學(xué)之一就是,我們推薦的大多數(shù)技術(shù)都是通用的:例如模塊化,它就能同時(shí)適用于代碼、設(shè)計(jì)、文檔和團(tuán)隊(duì)組織。當(dāng)某個(gè)傳統(tǒng)術(shù)語(yǔ)被拿來(lái)在更廣泛的場(chǎng)景下使用時(shí),卻會(huì)造成困惑——我們似乎無(wú)法擺脫該術(shù)語(yǔ)從最初就開始背負(fù)的歷史包袱。當(dāng)這種情況發(fā)生時(shí),我們只好發(fā)明自己的術(shù)語(yǔ),助紂為虐地讓語(yǔ)言繼續(xù)墮落。
源碼與其他資源
本書中的大部分代碼都是從可編譯的源文件中提取出來(lái)的,這些源文件可以從我們的網(wǎng)站上下載。
在那里,你還可以找到我們認(rèn)為有用的資源鏈接、本書的更新內(nèi)容,以及其他有關(guān)《程序員修煉之道》項(xiàng)目進(jìn)展的新聞。
給我們反饋
收到你的來(lái)信我們會(huì)很高興。我們的電子郵件地址是 ppbook@pragprog.com。
第二版鳴謝
在過(guò)去的二十年里,有成千上萬(wàn)關(guān)于編程的有趣對(duì)話曾讓我們開心不已,其中不乏在會(huì)議、課程,甚至是飛機(jī)上與人們的偶遇。每一次經(jīng)歷,都會(huì)加深我們對(duì)開發(fā)過(guò)程的理解,并為此版本的更新添磚加瓦。感謝所有人(而且,當(dāng)我們犯錯(cuò)誤的時(shí)候,請(qǐng)繼續(xù)提醒)。
感謝本書 Beta 測(cè)試過(guò)程的參與者,是你們的問(wèn)題和評(píng)論,幫助我們把事情解釋得更清楚。
在進(jìn)行 Beta 測(cè)試之前,我們?cè)c一些人分享過(guò)本書。感謝 VM (Vicky) Brasseur、 Jeff Langr、 Kim Shrier 給予的詳細(xì)評(píng)論,感謝 José Valim 與 Nick Cuthbert 的技術(shù)審核。
感謝 Ron Jeffries 讓我們用數(shù)獨(dú)的例子。
非常感謝培生集團(tuán)的人,是他們讓我們以自己的方式來(lái)創(chuàng)作這本書。
特別感謝不可或缺的 Janet Furlow,她掌控著一切,讓我們的工作沒(méi)有走樣。
最后,向所有在過(guò)去的二十年里一直致力于讓編程變得更好的務(wù)實(shí)的程序員們發(fā)出一聲吶喊:再接再厲,更創(chuàng)二十年輝煌。
更多建議: