程序員修煉之道:通向務實的最高境界(第2版)( 簡體 字) | |
作者:云風 | 類別:1. -> 程式設計 -> 綜合 |
出版社:電子工業出版社 | 3dWoo書號: 52495 詢問書籍請說出此書號! 有庫存 NT售價: 445 元 |
出版日:4/1/2020 | |
頁數:344 | |
光碟數:0 | |
站長推薦: | |
印刷:黑白印刷 | 語系: ( 簡體 字 ) |
ISBN:9787121384356 | 加入購物車 │加到我的最愛 (請先登入會員) |
(簡體書上所述之下載連結耗時費功, 恕不適用在台灣, 若讀者需要請自行嘗試, 恕不保證, 繁體書的下載亦請直接連絡出版社) | |
序 XVII
新版前言 XXI 第一版前言 XV 提示1:關注你的技藝 XVII 如果你不關心怎么做好,為什么還要花時間去開發軟件呢? 提示2:思考!思考你的工作 XVII 關掉輔助駕駛,由自己掌控,持續不斷地評估所做的工作。 第1章 務實的哲學 1 1 人生是你的 2 提示3:你有權選擇 3 人生是自己的。把握住人生,讓它如你所愿。 2 我的源碼被貓吃了 3 提示4:提供選擇,別找借口 5 提供選擇而不是去找理由。不要只說做不到;解釋一下都能做些什么。 3 軟件的熵 6 提示5:不要放任破窗 7 只要看到不好的設計、錯誤的決策、糟糕的代碼,就趕緊去糾正。 4 石頭做的湯和煮熟的青蛙 9 提示6:做推動變革的催化劑 10 你無法強迫人們去改變,但可以展示美好未來,并幫助他們參與創造。 提示7:牢記全景 10 不要過度沉浸于細枝末節,以免察覺不到周圍正在發生的事情。 5 夠好即可的軟件 11 提示8:將質量要求視為需求問題 12 讓用戶參與對項目真實質量需求的確定。 6 知識組合 14 提示9:對知識組合做定期投資 16 養成學習的習慣。 提示10:批判性地分析你讀到和聽到的東西 18 不要受供應商、媒體炒作或教條的影響,根據自身和項目的實際情況來 分析信息。 7 交流! 20 提示11:英語就是另一門編程語言 20 將英語視作一門編程語言。寫文檔和編程一樣要遵循 DRY 原則、ETC、 自動化等。 提示12:說什么和怎么說同樣重要 23 如果無法有效交流,任何偉大的想法都是沒有意義的。 提示13:把文檔嵌進去,而不要栓在表面 24 與代碼隔離的文檔,很難保持正確并及時更新。 第2章 務實的方法 27 8 優秀設計的精髓 28 提示14:優秀的設計比糟糕的設計更容易變更 28 適合使用者的事物,都已經過良好設計。對代碼來說,這意味著必須適應 變化。 9 DRY——邪惡的重復 30 提示15:DRY——不要重復自己 31 系統中的每一條知識,都必須有單一且無歧義的權威陳述。 提示16:讓復用變得更容易 39 只要復用方便,人們就會去做。創建一個支持復用的環境。 10 正交性 40 提示17:消除不相關事物之間的影響 41 設計的組件,需要自成一體、獨立自主,有單一的清晰定義的意圖。 11 可逆性 48 提示18:不設最終決定 50 不要把決定刻在石頭上,而要將其視為寫在沙灘上的東西,時刻準備 應變。 提示19:放棄追逐時尚 50 尼爾·福特說過:“昨日之最佳實踐,即明日之反模式。”要基于基本 原則去選擇架構,而不應盲從于流行。 12 曳光彈 51 提示20:使用曳光彈找到目標 53 通過不斷嘗試并看清著彈點,曳光彈可確保你最終擊中目標。 13 原型與便簽 57 提示21:用原型學習 58 制作原型旨在學習經驗,其價值不在于過程中產生的代碼,而在于 得到的教訓。 14 領域語言 60 提示22:靠近問題域編程 61 用問題領域的語言來做設計和編程。 15 估算 67 提示23:通過估算來避免意外 67 開始之前做估算,能提前發現潛在問題。 提示24:根據代碼不斷迭代進度表 72 利用實施過程中獲得的經驗來精細化項目的時間尺度。 第3章 基礎工具 74 16 純文本的威力 75 提示25:將知識用純文本保存 76 純文本不會過時。它能夠讓你的工作事半功倍,并能簡化調試和測試 工作。 17 Shell游戲 79 提示26:發揮 Shell 命令的威力 80 當圖形化界面無法勝任時,使用 Shell。 18 加強編輯能力 82 提示27:游刃有余地使用編輯器 82 既然編輯器是至關重要的工具,不妨了解一下如何用它更快更準確地 實現需求。 19 版本控制 85 提示28:永遠使用版本控制 87 版本控制為你的工作創造了一個時間機器,可以用它重返過去。 20 調試 90 提示29:去解決問題,而不是責備 91 Bug 到底來自你的失誤還是別人的失誤真的不重要——它終究是你的 問題,需要你來修復。 提示30:不要恐慌 91 不管是對銀河系搭車客,還是對開發者來說,都應這樣。 提示31:修代碼前先讓代碼在測試中失敗 93 在你修 Bug 前,先創建一個聚焦于該 Bug 的測試。 提示32:讀一下那些該死的出錯信息 93 大多數異常都能告訴失敗之物與失敗之處。如果足夠幸運,你甚至能 得到具體的參數值。 提示33:“select”沒出問題 97 在操作系統或編譯器中發現 Bug 非常罕見,甚至在第三方產品或庫中 也是如此。Bug 大多出現在應用程序中。 提示34:不要假設,要證明 97 在真實環境中證實你的假設——要依賴真實的數據及邊界條件。 21 文本處理 99 提示35:學習一門文本處理語言 99 既然每天都要花大量的時間與文本打交道,何不讓計算機幫你分擔一二? 22 工程日記 101 第4章 務實的偏執 103 提示36:你無法寫出完美的軟件 103 軟件不可能是完美的。對于在所難免的錯誤,要保護代碼和用戶免受其 影響。 23 契約式設計 104 提示37:通過契約進行設計 107 代碼是否不多不少剛好完成它宣稱要做的事情,可以使用契約加以校驗 和文檔化。 24 死掉的程序不會說謊 113 提示38:盡早崩潰 114 徹底死掉的程序通常比有缺陷的程序造成的損害要小。 25 斷言式編程 115 提示39:使用斷言去預防不可能的事情 115 如果一件事情不可能發生,那么就用斷言來確保其的確不會發生。斷言 在校驗你的假設,要使用斷言在不確定的世界中將你的代碼保護起來。 26 如何保持資源的平衡 119 提示40:有始有終 119 只要有可能,對資源進行分配的函數或對象就有責任去釋放該資源。 提示41:在局部行動 122 將易變的變量維持在一個范圍內,打開資源的過程要短暫且明顯可見。 27 不要沖出前燈范圍 127 提示42:小步前進——由始至終 127 永遠小步前進,不斷檢查反饋,并且在推進前先做調整。 提示43:避免占卜 129 只在你能看到的范圍內做計劃。 第5章 寧彎不折 130 28 解耦 131 提示44:解耦代碼讓改變更容易 132 耦合使事物緊緊綁定在一起,以至于很難只改變其中之一。 提示45:只管命令不要詢問 133 不要從對象中取出值,在加以變換后再塞回去,讓對象自己來完成這些 工作。 提示46:不要鏈式調用方法 135 當訪問某事物時,使用的點號不要超過一個。 提示47:避免全局數據 137 最好給每個方法增加一個額外的參數。 提示48:如果全局唯一非常重要,那么將它包裝到API 中 137 ……但是,僅限于你真的非常希望它是全局的。 29 在現實世界中拋球雜耍 139 30 變換式編程 149 提示49:編程講的是代碼,而程序談的是數據 151 所有的程序都在變換數據——將輸入轉換為輸出。開始用變換式方法來 設計吧! 提示50:不要囤積狀態,傳遞下去 156 不要把數據保持在函數或模塊的內部,拿出來傳遞下去。 31 繼承稅 162 提示51:不要付繼承稅 165 考慮一下能更好滿足需求的替代方案,比如接口、委托或mixin。 提示52:盡量用接口來表達多態 167 無需繼承引入的耦合,接口就能明確描述多態性。 提示53:用委托提供服務:“有一個”勝過“是一個” 167 不要從服務中繼承,應該包含服務。 提示54:利用 mixin 共享功能 169 mixin 不必承擔繼承稅就可以給類添加功能,而與接口結合可以讓 多態不再令人痛苦。 32 配置 170 提示55:使用外部配置參數化應用程序 170 如果代碼對一些在應用程序發布后還有可能改變的值有所依賴,那么 就在應用外部維護這些值。 第6章 并發 174 33 打破時域耦合 175 提示56:通過分析工作流來提高并發性 176 利用用戶工作流中的并發性。 34 共享狀態是不正確的狀態 179 提示57:共享狀態是不正確的狀態 180 共享狀態會帶來無窮的麻煩,而且往往只有重啟才能解決。 提示58:隨機故障通常是并發問題 186 或許時間和上下文的變化能暴露并發Bug,但并發Bug無法始終保持 一致,也很難重現。 35 角色與進程 187 提示59:用角色實現并發性時不必共享狀態 188 使用角色來管理并發狀態,可以避免顯式的同步。 36 黑板 193 提示60:使用黑板來協調工作流 195 使用黑板來協調不相關的事實和代理人,能同時保持參與者之間的 獨立性和孤立性。 第7章 當你編碼時 198 37 聽從蜥蜴腦 199 提示61:傾聽你內心的蜥蜴 201 當編程舉步維艱時,其實是潛意識在告訴你有什么地方不對勁。 38 巧合式編程 204 提示62:不要依賴巧合編程 207 只能依賴可靠的事物。注意偶然事件的復雜性,不要混淆快樂的巧合 與有目的的計劃。 39 算法速度 210 提示63:評估算法的級別 214 在開始編程前,對這件事情大概會花多長時間要有概念。 提示64:對估算做測試 214 針對算法的數學分析無法說明所有問題,嘗試在目標環境中測試一下 執行代碼的耗時。 40 重構 216 提示65:盡早重構,經常重構 219 像除草和翻整花園那樣,只要有需要就對代碼進行重新編寫、修訂 和架構,以便找到問題的根源并加以修復。 41 為編碼測試 220 提示66:測試與找 Bug 無關 221 測試是觀察代碼的一個視角,可以從中得到針對設計、接口和耦合度的 反饋。 提示67:測試是代碼的第一個用戶 222 用測試的反饋來引導工作。 提示68:既非自上而下,也不自下而上,基于端對端構建 225 創建一小塊端到端的功能,從中獲悉問題之所在。 提示69:為測試做設計 228 寫下代碼之前先從測試角度思考。 提示70:要對軟件做測試,否則只能留給用戶去做 230 無情地測試,不要等用戶來幫你找 Bug。 42 基于特性測試 231 提示71:使用基于特性的測試來校驗假設 231 基于特性的測試將會進行你從未想過的嘗試,并會以你不曾打算采用 的方式操練你的代碼。 43 出門在外注意安全 238 提示72:保持代碼簡潔,讓攻擊面最小 241 復雜的代碼給 Bug 以滋生之沃土,給攻擊者以可趁之機。 提示73:盡早打上安全補丁 243 攻擊者會盡可能快地部署攻擊,你必須快上加快。 44 事物命名 245 提示74:好好取名;需要時更名 249 用名字向讀者表達你的意圖,并且在意圖改變時及時更名。 第8章 項目啟動之前 251 45 需求之坑 252 提示75:無人確切知道自己想要什么 252 他們或許知道大概的方向,但不會了解過程的曲折。 提示76:程序員幫助人們理解他們想要什么 253 軟件開發更像是一種由用戶和程序員協同創造的行為。 提示77:需求是從反饋循環中學到的 254 理解需求需要探索和反饋,因此決策的結果可以用來完善最初的想法。 提示78:和用戶一起工作以便從用戶角度思考 255 這是看透系統將如何被真正使用的最佳方法。 提示79:策略即元數據 256 不要將策略硬編碼進系統,而應該將其表達為系統的一組元數據。 提示80:使用項目術語表 259 為項目的所有特定詞匯創建一張術語表,并且在單一源頭維護。 46 處理無法解決的難題 260 提示81:不要跳出框框思考——找到框框 261 在面對無法解決的難題時,識別出真正的約束。可以問自己:“必須 這樣做才能搞定嗎?必須搞定它嗎?” 47 攜手共建 264 提示82:不要一個人埋頭鉆進代碼中 267 編程往往困難又費力,找個朋友和你一起干。 提示83:敏捷不是一個名詞;敏捷有關你如何做事 267 敏捷是一個形容詞,有關如何做事情。 48 敏捷的本質 267 第9章 務實的項目 271 49 務實的團隊 272 提示84:維持小而穩定的團隊 272 團隊應保持穩定、小巧,團隊中的每個人都應相互信任、互相依賴。 提示85:排上日程以待其成 274 如果你不把事情納入日程表,它們就不會發生。反思、實驗、學習、 提高技能,這些事都應放入日程表。 提示86:組織全功能的團隊 276 圍繞功能而不是工作職能組織團隊。不要將 UI/UX 設計者從程序員中 分離出去,也不要分開前端和后端;不要區分數據建模者和測試人員, 以及開發和設計。構建一個團隊,這樣你就可以漸進地不斷迭代端到端 的代碼。 50 椰子派不上用場 277 提示87:做能起作用的事,別趕時髦 279 不要僅僅因為別的公司正在那么干就采納一項技術或采用一個開發 方法,而是要采用自己所處環境中對團隊有效的東西。 提示88:在用戶需要時交付 281 不要卡著流程要求,刻意等到幾周甚至幾個月后才交付。 51 務實的入門套件 281 提示89:使用版本控制來驅動構建、測試和發布 282 利用提交或推送來觸發構建、測試、發布,利用版本控制的標簽來 進行生產部署。 提示90:盡早測試,經常測試,自動測試 283 每次構建都跑一下的測試,要比束之高閣的測試計劃有效得多。 提示91:直到所有的測試都已運行,編碼才算完成 283 無須多言。 提示92:使用破壞者檢測你的測試 285 在一個單獨的源碼副本中特意引入 Bug,驗證測試能否將其捕獲。 提示93:測試狀態覆蓋率,而非代碼覆蓋率 286 要識別并測試重要的程序狀態,只測試一行行的代碼是不夠的。 提示94:每個 Bug 只找一次 286 只要人類測試者找到一個 Bug ,就應該是該 Bug 最后一次被人類 發現。從此之后,自動化測試完全可以發現它。 提示95:不要使用手動程序 287 計算機能一次又一次,按照同樣的次序,執行相同的指令。 52 取悅用戶 288 提示96:取悅用戶,而不要只是交付代碼 289 為用戶開發能夠帶來商業價值的解決方案,并讓他們每天都感到愉快。 提示97:在作品上簽名 290 過去的工匠在為他們的作品簽名時非常自豪,你也應該這樣。 53 傲慢與偏見 290 跋 292 提示98:先勿傷害 293 犯錯在所難免,確保犯錯后沒人會因此受難。 提示99:不要助紂為虐 294 因為這樣做你也有變成紂王的風險。 參考文獻 295 練習的參考答案 297 譯者跋 312 《程序員修煉之道》之所以在全球范圍內廣泛傳播,被一代代開發者奉為圭臬,蓋因它可以創造出真正的價值:或編寫出更好的軟件,或探究出編程的本質,而所有收獲均不依賴于特定語言、框架和方法。時隔20年的新版,經過全面的重新選材、組織和編寫,覆蓋哲學、方法、工具、設計、解耦、并發、重構、需求、團隊等務實話題的最佳實踐及重大陷阱,以及易于改造、復用的架構技術。本書極具洞察力與趣味性,適合從初學者到架構師的各階層讀者潛心研讀或增廣見聞。
序
我還記得 Dave 和 Andy 第一次在推特上談論這本書的新版的那一刻——這可是一條大新聞。在編程社區,所見之處都是對這條大新聞興奮的回應,人們的期待塞滿了我的信息流。二十年過去了,《程序員修煉之道》這本書的地位不遜于當年。 承載這樣一段歷史的一本書,能引起這樣的反響,本身就說明了很多問題。為了寫這篇序,我有幸在尚未出版前閱讀了本書,讀后我就明白了它為什么會引起這么大的轟動。本來,一本書被冠以技術圖書之名,給人的印象應該是不太好的。因為技術圖書常常令人生畏——充斥著深奧的詞匯、晦澀的術語和令人費解的例子,不經意間就會讓你覺得自己很愚蠢。而且,作者越有經驗,就越容易忘記初學者在學習新概念時的感覺。 Dave 和 Andy 的作品,卻能透出那種只有剛剛學到這些課程的人才會有的興奮感,盡管他們已有幾十年的編程經驗,卻戰勝了寫出這種感覺的挑戰。他們不會居高臨下地指指點點,不會假定你是個專家,甚至不認為你已讀過本書第一版,僅僅把你當成想要變得更好的程序員而已。他們不惜用整本書的篇幅來幫助你達到目標,一步一個腳印。 公平地說,在這方面,他們在過往已經成績斐然。最初的本書第一版,包含了許多具體的例子、新想法和實用的技巧,可以幫助你修煉編程所需的“肌肉”和“大腦”,這些東西到今天仍然適用。但是,這次在新版圖書中,又有了兩項改進。 第一項顯而易見:刪除了一些較老的引用內容和過時的例子,增補了大量新鮮、現代的內容。循環不變式或構建機這樣的例子已經看不到了。Dave 和 Andy 保留了第一版書中的重要內容,以確保相應的課程依然有效,而且讀者也不必受舊示例的干擾。對于像 DRY(不要重復自己)這樣的舊思想,上面的灰塵已被撣去,并且涂上了一層新油漆——這樣做真的讓其熠熠生輝。 而第二項,才是這次新版圖書發布真正令人興奮的地方。在寫完本書第一版后,他們有機會思考自己想要說什么,想讓讀者獲得什么,以及讀者是如何接受這些信息的。他們得到了這些課程的反饋,也看到了讀者在哪里被卡住、有什么需要改進,以及哪些內容被誤解。在這本書通過全世界程序員的雙手和心靈傳播的二十年間,Dave 和 Andy 研究了這些回應,并且形成了新的想法和理念。 他們認識到自主權的重要性,并且意識到,相比大多數其他專業人員,開發者或許更能為自己做主。他們以簡單而深刻的啟示開始這本書:“人生是你的。”這喚起了我們自己的力量,它就蘊含在我們的代碼庫、工作和職業生涯中。這也為本書的其他內容定下了基調——它不僅僅是又一本充滿代碼示例的技術圖書。 這本書必定會在擺滿各種技術圖書的書架上脫穎而出,因為它理解身為一名程序員到底意味著什么。編程關涉諸事——盡量減少未來的痛苦,讓隊友更輕松,做錯事情后能夠重新振作起來,養成良好的習慣,以及理解工具集。編程只是程序員世界的一部分,而這本書探索了整個世界。 我在思考編碼之旅上花了很多時間。我不是從小就開始接觸編程的,大學里也沒學過編程課。可以說,我的青少年時光并沒有花在“擺弄”科技上,直到二十來歲的時候才進入了編程的世界,因而亟須想明白一件事情:成為一名程序員意味著什么。編程社區與我曾經身處的其他社區非常不同。其獨特之處在于,人們無不醉心于學習和實踐,這既令人生畏,又讓人耳目一新。 這對我來說,真像進入一個全新的世界。就算去到一個新城鎮,也有必要了解鄰居、挑選雜貨店、找到最好的咖啡店。我花了一段時間來了解地形,找到了最有效的路線,避開了交通最繁忙的街道,并且知道了什么時候交通可能會出問題。等到天氣變化,我又要去置辦應季的新衣。 來到一個新城鎮的頭幾周,甚至是頭幾個月,可能會很害怕。如果有一個已經在這里住了一段時間的鄰居,而且他知識淵博又友好,那不是再好不過的事情嗎?誰能帶你四處參觀,誰能領你去那些咖啡店?當然是一個在當地待了足夠長時間的,了解當地文化、當地脈搏的人。這樣你不僅有家的感覺,還能成為一個同樣有貢獻的成員。Dave 和 Andy 就是這樣的鄰居。 一個準新人,更容易對成為程序員的過程,而不是對編程的行為不知所措。因此,必須對整個心態做一次切換——改變習慣、行為和期望。僅僅知道如何編程,并不會讓你成為一名更好的程序員,在這個過程中必須經歷有意識和深思熟慮的實踐。好在現在有了這本書,可以有效地指導你成為更好的程序員。 但不要搞錯了——這本書不會告訴你編程應該是怎樣的,它并沒有使用那種哲學或審判的方式,它只是簡單、明了地告訴你,什么是務實的程序員——他們如何操作、如何處理代碼。作者讓你自己決定是否想成為其中的一員。如果你覺得不適合,也沒有人會怪罪你。但如果你決定成為其中的一員,作者就是你的友好鄰居,會陪伴左右、為你指路。 Saron Yitbarek CodeNewbie 創始人及 CEO Command Line Heroes 主辦者 新版前言 在20世紀90年代,我們在與一些項目存在問題的公司合作時,發現總是在對每個人說同樣的話:也許你應該在發布之前先測試一下。為什么代碼只能在 Mary 的機器上構建?為什么沒有人問一下用戶呢? 為了節省與新客戶打交道的時間,我們開始做筆記。這些筆記最終變成了《程序員修煉之道》這本書。令人驚訝的是,這本書似乎引起了大家的共鳴,在過去的二十年間,這本書一直很受歡迎。 但是二十年對于軟件領域來說已經過了好幾代。如果一個開發者從 1999 年直接穿越到今天的團隊中,面對這個陌生的新世界一定會備感掙扎。但20世紀90年代的世界對今天的開發者來說同樣陌生。書中所引用的 CORBA、CASE 工具,以及索引、循環這些東西,放在今天,充其量不過略顯古雅有趣,而更多的會給人帶來困擾。 與此同時,二十年對常識沒有絲毫影響。技術可能改變了,但人沒有。實踐和方法中的閃光點,在今天看來光芒依舊。在這些方面,本書保鮮如初。 所以,當我們要出版這本二十周年紀念版的時候,必須做出抉擇——是回顧和更新前一版中引用的技術后就大功告成,還是充分借鑒這平添的二十年豐富經驗,重新審視前一版所推崇的實踐背后的種種假設。 最終,我們兩者都做了。 因此,這本書有點像忒修斯之船 。書中大約三分之一的主題是全新的,而其余的大部分都被部分或全部重寫了。我們的目的是,讓內容變得更清晰、更貼切,并在某種程度上不受時間的影響。 我們做了一些艱難的決定。刪除了參考資料附錄,這樣做既因為它無法持續更新,也因為當你有此需要時很容易就能搜索獲得。我們重新組織了與并發有關的主題,這是因為考慮到當前有著大量的并行硬件,卻缺乏處理并行的好方法。我們還添加了一些內容來反映不斷變化的認知和環境,從我們幫助發起的敏捷運動,到對函數式編程語境的日益接受,再到對隱私和安全性方面日益增長的需求。 然而有趣的是,我們之間關于版本內容的爭論比寫第一個版本時要少得多。重要的東西更容易辨別,這已是我們的共識。 無論如何,這本書最后就是這個樣子了,請享用吧。你也許可以從中吸取一些新的做法,也許會覺得我們建議的某些東西是錯的,不妨把它們都帶到你的工作中去,然后給我們反饋。 但是,最重要的是,記住過程要開心。 【這本書是如何組織的】 這本書是許多短小主題的合集。每一個主題都針對特定的話題而獨立成章。你會發現大量的交叉引用,這有助于把各個主題連貫起來。你可以以任意次序隨意閱讀這些主題——這不是一本需要從頭到尾閱讀的書。 偶爾你會看到一個寫有提示n的框起來的標簽塊(比如位于第XVII頁的提示1:關注你的技藝)。這些提示不僅是文中的重點,在我們眼里也是一條條生命——我們每天都賴以為生。 我們已盡可能適時地在書中加入了練習和挑戰。練習通常有相對簡單的答案,而挑戰則更加開放。為了讓你理解我們的思維方式,在附錄里我們列出了這些練習的答案,但是擁有唯一正確答案的問題并不多。挑戰或許能用于高級編程課程中的小組討論,或許能作為論文寫作的基礎。 本書還有一個簡短的參考文獻,列出了我們明確引用的圖書和文章。 【名字有什么含義】 “我用一個詞,”矮胖子相當傲慢地說,“總是同我想要說的恰如其分的,既不重,也不輕。” —— 路易斯·卡羅《愛麗絲鏡中奇遇》 在整本書中,你會發現各種各樣的行話——要么原本是完好的英語單詞,卻被曲解為技術詞,要么是一些可怕的合成詞,由那些對語言充滿怨恨的計算機科學家賦予其意義。當我們第一次使用這些行話時,會嘗試定義它們,或者至少對其含義給出解釋。當然,肯定還有漏網之魚,而且像對象和關系型數據庫這種已被廣泛使用的,再下一次定義就有點畫蛇添足了。如果你遇到一個以前沒見過的術語,請不要跳過它,不妨花點時間去查一下,可以在網上查,也可以在計算機科學的課本上查。如果有機會還可以給我們發郵件投訴,這樣我們就可以在本書下一版中增加一個定義。 既然話已至此,我們決定報復一下計算機科學家。有時候,明明有一些非常好的術語,對某個概念表達得很好,但我們卻決定不使用這些術語。為什么?因為現有的術語通常局限于特定的問題領域,或者特定的開發階段。而本書的基本哲學之一就是,我們推薦的大多數技術都是通用的:例如模塊化,它就能同時適用于代碼、設計、文檔和團隊組織。當某個傳統術語被拿來在更廣泛的場景下使用時,卻會造成困惑——我們似乎無法擺脫該術語從最初就開始背負的歷史包袱。當這種情況發生時,我們只好發明自己的術語,助紂為虐地讓語言繼續墮落。 【第二版鳴謝】 在過去的二十年里,有成千上萬關于編程的有趣對話曾讓我們開心不已,其中不乏在會議、課程,甚至是飛機上與人們的偶遇。每一次經歷,都會加深我們對開發過程的理解,并為此版本的更新添磚加瓦。感謝所有人(而且,當我們犯錯誤的時候,請繼續提醒)。 感謝本書 Beta 測試過程的參與者,是你們的問題和評論,幫助我們把事情解釋得更清楚。 在進行 Beta 測試之前,我們曾與一些人分享過本書。感謝 VM (Vicky) Brasseur、 Jeff Langr、 Kim Shrier 給予的詳細評論,感謝 José Valim 與 Nick Cuthbert 的技術審核。 感謝 Ron Jeffries 讓我們用數獨的例子。 非常感謝培生集團的人,是他們讓我們以自己的方式來創作這本書。 特別感謝不可或缺的 Janet Furlow,她掌控著一切,讓我們的工作沒有走樣。 最后,向所有在過去的二十年里一直致力于讓編程變得更好的務實的程序員們發出一聲吶喊:再接再厲,更創二十年輝煌。 第一版前言 本書將幫助你成為更好的程序員。 不論你是獨立開發者,還是大型項目團隊的一員,或是同時與許多客戶共事的顧問,都無所謂。本書旨在告訴你,作為個體如何更好地完成工作。這本書不是理論書——我們專注于實踐的話題,利用經驗來做出更明智的決定。務實(Pragmatic)這個詞來自拉丁語 pragmaticus ——“精通業務”,該詞又來源于希臘語 πραγματικ??,意思是“適合使用”。 這是一本關于實干的書。 編程是一門技藝。簡單地說,就是讓計算機做你想讓它做的事情(或是你的用戶想讓它做的事情)。作為一名程序員,你既在傾聽,又在獻策;既是傳譯,又行獨裁;你試圖捕獲難以捉摸的需求,并找到一種表達它們的方式,以便僅靠一臺機器就可以從容應付。你試著把工作記錄成文檔,以便他人理解;你試著將工作工程化,這樣別人就能在其上有所建樹;更重要的是,你試圖在項目時鐘的滴答聲中完成所有這些工作。你每天都在創造小小的奇跡。 編程是一項艱難的工作。 想幫你的人可不少——工具供應商在吹噓他們家產品所創造出的奇跡,方法論大師承諾他們的技術可以為結果做出保證,每個人都聲稱他們用的編程語言是最好的,每個操作系統都自詡包治百病。 當然,這些都不是真的,哪有什么簡單的答案。沒有最好的解決方案,無論是工具、語言還是操作系統;只在特定的環境下才有所謂更合適的系統。 這就讓務實主義有了用武之地。你不應該拘泥于任何特定的技術,而應該擁有足夠廣泛的背景和經驗基礎,以便在特定的情況下選擇合適的解決方案。你的背景來自對計算機科學基本原理的理解,而你的經驗來自廣泛的實際項目。理論結合實踐會讓你變得強大。 調整方法去適應當前的情況和環境。對所有影響項目因素的相對重要性做出判斷,并通過經驗找到適當的解決方案。隨著工作的進展,你要不斷地這樣做。務實的程序員不僅把工作做完,并且做得很好。 【誰應該讀這本書】 本書的目標讀者是那些希望成為更高效、多產的程序員的人。也許你現在感到沮喪,因為似乎沒能發揮自己的潛力;也許你已經注意到,有些同事似乎正在利用工具讓自己的效率比你更高;也許你在現在的工作中使用的是較老的技術,你想知道如何為工作引入新的想法。 我們不會假裝擁有所有(或是絕大部分)的答案,也不會假裝我們的每個想法都適用于所有情況。我們只能說,如果你遵循我們的方法,你將快速獲得經驗、提高生產力,并且更好地理解整個開發過程。最終,你會寫出更好的軟件。 【是什么造就了務實的程序員】 每個開發人員都是獨特的,有各自的優勢和劣勢,以及偏好和厭惡的東西。誠如隨著時間的推移,每個人都將打造自己的個人環境。這種環境將像程序員的愛好、衣服或發型一樣,能強烈地反映出他或她的個性。然而,作為務實的程序員,你們會共有許多如下特征: .早期的采納者/快速的適配者 你對技術和技巧有一種直覺,喜歡嘗試。當接觸到新東西時,你可以很快地掌握它們,并把它們與其他的知識結合起來。你的信心來自經驗。 .好奇 你傾向于問問題。這真不錯——你怎么做到的?你對那個庫有意見嗎?總在聽人說起的量子計算到底是什么?符號鏈接是怎么實現的?你熱衷于收集各種細微的事實,堅信它們會影響自己多年后的決策。 .批判性的思考者 你在沒有得到證實前很少接受既定的現實。當同事們說“因為就該這么做”,或者供應商承諾會解決所有的問題時,你會聞到挑戰的味道。 .現實主義 你試圖理解所面臨的每個問題的本質。這種現實主義讓你對事情有多困難、需要用多長時間有一個很好的感知。一個過程應該很難,或是需要點時間才能完成,對這些的深刻理解,給了你堅持下去的毅力。 .多面手 你努力熟悉各種技術和環境,并努力跟上新的進展。雖然目前的工作可能要求你在某個專門領域成為行家,但你總是能夠進入新的領域,迎接新的挑戰。 我們把最基本的特征留到最后。所有務實的程序員都有這個特征。它足夠基本,完全可以作為提示來加以聲明。 提示1 關注你的技藝 我們覺得,如果你不關心怎么把軟件開發好,那么軟件開發領域就再也沒什么好談的事情了。 提示2 思考!思考你的工作 為了成為一名務實的程序員,我們要求你在做事的時候,思考一下自己正在做什么。這不是對當前實踐做的一次性審計——而是對每天里每一個項目所做的每一個決定進行的批判性評估。不要用自動輔助駕駛系統偷懶,而是要不斷地思考,即時地批判自己的工作。IBM 公司的座右銘“思考!”,實屬每個務實程序員的真言。 如果你覺得這聽起來很困難,那么你就表現出了現實主義的特征。這會占用你一些寶貴的時間——可能是已經處于巨大壓力之下的時間。當然會有回報,你能更積極地投入喜歡的工作,對越來越多的學科有掌控感,對不斷進步產生愉悅感。從長期來看,時間投資將得到回報,因為你和你的團隊將變得更高效,能編寫出更容易維護的代碼,并且在會議上花的時間更少。 【務實的個體,大型的團隊】 有些人認為在大型團隊或復雜的項目中沒有個性的空間。“軟件是一門工程學科,”他們說,“如果團隊成員個體自行其是,軟件就會崩潰。” 我們強烈反對這種看法。 誠然,軟件構造有工程的成分。然而,這并不妨礙個體的技藝。想想中世紀在歐洲建造的大教堂,每一座都需要數千人年的努力,時間跨度長達幾十年。從中吸取的經驗教訓被傳遞給下一代的建造者,最終一代代累積的造詣推動了結構工程的發展。而木匠、石匠、雕刻師和玻璃工人都是手工藝人——通過吃透工程要求,其創造所體現出的整體水準,已遠超建筑中純機械的部分。正是他們對個人貢獻的信念支撐著這些項目:我們,采集的只是石頭,卻必須始終展望著未來的大教堂。 在一個項目的整體結構中,總有個性和技藝的空間。考慮到軟件工程的當前狀態,這一點尤為正確。今天的土木工程師,很難接受中世紀大教堂建造者使用的技術——百年后我們的工程看上去也一樣古老,而我們的技藝仍將受到尊重。 【這是一個連續的過程】 一位游客在參觀英格蘭伊頓公學時,詢問園丁是如何把草坪修剪得如此完美的。“那很簡單,”園丁回答說,“你只要每天早上拂去露水,隔天修剪一次,一周再滾壓一次就行了。” “就是這些嗎?”游客問。“就這些,”園丁回答,“這樣做上五百年,你也會有一片漂亮的草坪。” 偉大的草坪需要每天的點滴護理,偉大的程序員也是如此。管理顧問喜歡在談話中拋出“改善(Kaizen)”這個詞。“改善”是一個日語術語,意思是不斷地做出許多小的改進。這被認為是日本制造業生產率和質量大幅提高的主要原因之一,并被全世界廣泛效仿。改善也適用于個人。每一天都要努力打磨你的技能,并往技能庫里添加新的工具。與伊頓草坪不同,你會在幾天內就看到效果。幾年下來,你會對成果驚訝不已——經驗業已開花結果,技能早就茁壯成長。 |