🎯 什麼情境該想到我
當你做出來的東西和客戶要的不一樣,或者交付的過程總在最後爆炸的時候。
章導言引 Helmuth von Moltke:「没有任何计划在遇敌后还能继续执行。」書的論點是:「我们的敌人不是客户,不是用户,不是队友,也不是管理者。真正的敌人是变化。」這一章的九個習慣分成兩組:
讓客戶參與方向:
| 習慣 | 良策 |
|---|---|
| 讓客戶做決定 | 開發者不應該做業務方面的決定 |
| 讓設計指導而不是操縱開發 | 好的設計是一張會演進的地圖 |
| 合理地使用技術 | 根據需要選擇技術 |
| 使用演示獲得頻繁反饋 | 每隔一兩週給客戶看最新完成的功能 |
| 固定價格就意味著背叛承諾 | 基於真實工作的評估 |
讓交付隨時可行:
出處:Subramaniam & Hunt《高效程式設計師的 45 個習慣》第 4 章。每個習慣依書中結構整理:魔鬼的誘惑 → 良策 → 重點 → 切身感受 → 平衡的藝術;引文保留原書簡體字。
⚙️ 怎麼用(逐項)
讓客戶做決定
Let Customers Make Decisions 什麼時候會冒出來:開發到一半卡在商業規則該怎麼定/自己替業務做了不該做的決定/不確定這個決策該不該問客戶/想把選項整理好讓業主拍板
魔鬼的誘惑:「开发者兼具创新和智慧,最了解应用程序。因此,所有关键决定都应该由开发者定夺。」
良策:「让你的客户做决定。开发者、经理或者业务分析师不应该做业务方面的决定,用业务负责人能够理解的语言,向他们详细解释遇到的问题,并让他们做决定。」(旁註:決定什麼不該由你決定)
書中的例子:
- 專案經理 Pat 的專案按計畫、在預算內,像教科書上的明星專案——但演示時客戶很失望。原來業務分析師沒有和使用者討論,就自作主張做了所有決定。
- Venkat 的一個專案:有兩種實作方式,一種快但對使用者有限制,一種慢但更靈活。經理為了省時間選了第一種,Beta 測試時使用者震驚甚至憤怒,只能重做。
「开发者(及项目经理)能做的一个最重要的决定就是:判断哪些是自己决定不了的。」
做法:準備幾個選項,從業務角度(而不是技術角度)說明每個選項的優缺點、成本、對時程的影響。
平衡的藝術:
- 記錄客戶的決定和原因(工作日誌、Wiki、Email、工單系統),但記錄方式不能太繁瑣。
- 不要用對業務沒有影響的低階問題打擾忙碌的業務人員;但也不要隨便假設低階問題不影響業務。
- 業務負責人回答「我不知道」也是有用的答案——也許他還沒想到那麼遠,或者需要看到實物。
在今天的樣子:這就是產品經理與工程師的分工邊界。「記錄決定和原因」對應架構決策記錄(ADR)。
讓設計指導而不是操縱開發
Let Design Guide, Not Dictate 什麼時候會冒出來:前期設計畫得太細綁死了後面/設計文件寫滿卻跟實作對不上/想知道設計要做到多細才夠/設計變成不能改的枷鎖
魔鬼的誘惑:「设计文档应该尽可能详细,这样,低级的代码工人只要敲入代码就可以了……绝不能偏离了设计文档。」
良策:「好设计是一张地图,它也会进化。设计指引你向正确的方向前进,它不是殖民地……你不要被设计(或者设计师)操纵。」
書中重點:
- 設計只基於目前對需求的理解,一開始寫程式,一切都會變。把精美的設計文件丟給程式設計師照著寫,發現設計不理想時也沒時間回頭。
- 設計分兩層:
- 戰略設計(前期):只描述整體策略,不具體到方法、參數、欄位、物件互動順序。
- 戰術設計(開發時):在寫程式時展開細節。
- Lewis 與 Clark 的探險(1804 年橫越美國):他們只知道目標和限制,不知道路上的細節——走到河邊才規劃怎麼過河。
- 早期用 CRC 卡(類別-職責-協作者)討論設計:類別名稱、它該做什麼、要和哪些物件合作。
- 好設計的判準:需求小幅變化時仍然容易實作;小變化就破壞一大批程式碼,設計就需要改進。
切身感受:「好的设计应该是正确的,而不是精确的……它是目标,不是具体的处方。」
平衡的藝術:
- 「不要做大量的前期設計」不是說不要設計;對設計一無所知就寫程式也危險。
- 艾森豪:「计划是没有价值的,但计划的过程是必不可少的。」
- 白板、草圖、便利貼是很好的設計工具;複雜的建模工具只會分散精力。
在今天的樣子:「正確而不精確」是寫設計文件(RFC、設計文件)的好標準:寫清楚目標、限制、關鍵的介面與取捨,不寫每個函式的簽名。
合理地使用技術
Justify Technology Use 什麼時候會冒出來:看到新框架就很想引進來用/選型的理由只是因為它現在很紅/說不出這個工具解決什麼真問題/想評估要不要換掉現有技術
魔鬼的誘惑:「你真的需要使用列表中所有的技术。想一想,你的简历上将留下漂亮的一笔。」
良策:「根据需要选择技术。首先决定什么是你需要的,接着为这些具体的问题评估使用技术。」(旁註:盲目地為專案選擇框架,就好比為了省稅而生孩子;不要開發你能下載到的東西)
書中重點——「履歷驅動設計」:同事已經說服經理採用某個框架,並說「所以现在不要再扔‘炸弹’了」。
評估技術的三個問題:
- 它真的能解決這個問題嗎?(是靠市場宣傳還是道聽途說?必要時先做小原型。)
- 你會被它綁住嗎?(有些技術是賊船,沒有退路。它是開放的還是專有的?)
- 維護成本是多少?(書中的例子:某專案的規則引擎一年維護費 5 萬美元,但只有 30 條規則。)
其他例子:一位顧問把自家專有的框架賣給某個專案,一年後專案沒完成,團隊花了好幾個月寫程式碼去維護那個框架。書中引 Ted Neward:「对象-关系的映射就是计算机科学的越南战场。」
切身感受:「新技术就应该像是新的工具,可以帮助你更好地工作,它自己不应该成为你的工作。」
平衡的藝術:
- 也許現在評估技術還太早。給客戶看原型時,一個簡單的雜湊表就能代替資料庫。
- 每項技術都有優缺點,要清楚利弊。
- 不要從零開發能直接下載的東西。
在今天的樣子:書中的三個問題可以直接當作技術選型的檢查清單。「會不會被綁住」在雲端時代特別重要(專有的託管服務)。蒙格的 社會認同傾向 解釋了技術潮流的驅動力。
保持可以發布
Keep Your Project Releasable 什麼時候會冒出來:主線上躺著半成品不敢發版/程式庫常常處在不能建置的狀態/想隨時都能拉一版出來給人試用/每次要發版都要花好幾天修穩
魔鬼的誘惑:「我们刚试用的时候发现了一个问题,你需要立即修复它……不需要经过正规的程序,不用告诉其他任何人——赶快让它工作就行了。」
良策:「保持你的项目时刻可以发布。保证你的系统随时可以编译、运行、测试并立即部署。」
書中重點:
- 緊急修復在沒有流程的情況下提交,和同事的程式碼衝突,所有人都無法使用系統。
- 防止破壞的三步流程:
- 在本地執行測試(編譯 + 所有單元測試 + 其他測試);
- 取得最新的程式碼,再編譯、測試一次;
- 提交。
- 別人提交的程式碼沒通過編譯或測試,要立刻告知。最好有持續整合系統在背景不斷檢出、建置、測試。
- 改資料庫結構、檔案格式、訊息格式時:提供版本支援來隔離變化,或者開分支。
切身感受:「不管什么时候,你的老板、董事长、质量保障人员、客户……来公司参观项目的时候,你都能很自信并毫不犹豫地给他们演示最新构建的软件。」
平衡的藝術:
- 大規模改動時,有時無法保證一直可以發布——如果要花一個月才能保證一週內可以發布,那就算了。但這只能是例外。
- 真的必須讓系統長時間不可發布,就開一個分支——「千万不能让系统既不可以发布,又不可以撤销。」
在今天的樣子:這個習慣的完整展開就是主幹開發與持續交付(見 主幹開發、工具-部署管線與持續交付)。「改格式時提供版本支援」就是平行改動(expand → migrate → contract,見 工具-小步重構)。
提早集成頻繁集成
Integrate Early, Integrate Often 什麼時候會冒出來:各自開發很久才要合併/合併時衝突多到不想處理/分支開太久跟主線差太遠/想把整合變成每天的小事
魔鬼的誘惑:「只要没有到开发的末尾阶段,就不要过早地浪费时间去想如何集成你的代码。」
良策:「提早集成,频繁集成。代码集成是主要的风险来源。要想规避这个风险,只有提早集成,持续而有规律地进行集成。」(旁註:絕不接受大爆炸式的整合)
書中重點:
- Venkat 小時候在印度趕火車上學的比喻:不能從站著不動的地方一下跳上行駛中的火車,要先沿著火車的方向跑、抓住扶手再跳上去——整合也是一樣。
- 側欄〈你能整合並且獨立〉:用 mock 物件隔離依賴(像拍電影用的替身),先寫獨立的單元測試。獨立開發比較快,但不代表延後整合。
切身感受:「如果你真正做对了,集成就不再会是一个繁重的任务……集成时产生的问题,都会是小问题并且容易解决。」
平衡的藝術:
- 成功的整合代表所有單元測試持續通過。
- 頻率:通常每天和團隊整合好幾次,平均每天 5~10 次甚至更多。但每改一行就整合一次,效益會縮水——大部分時間都在整合而不是寫程式,就是太頻繁了。
- 整合不夠頻繁(一天一次、一週一次)會讓你整天在解決整合問題。整合問題很大,就代表整合得不夠頻繁。
- 原型和實驗程式碼可以獨立開發,但不能太久。
在今天的樣子:長期存在的功能分支就是延後整合。需要隔離未完成的功能時,用功能開關而不是長命分支(見 功能開關)。
提早實現自動化部署
Automate Deployment Early 什麼時候會冒出來:每次上線都靠手動一步步做/部署流程只有某個人會操作/想把安裝變成一鍵而且可重複/上線常因為漏做某個步驟而出包
魔鬼的誘惑:「没问题,可以手工安装产品……他们都很擅长复制需要的所有文件。」
良策:「一开始就实现自动化部署应用……质量保证人员要像测试应用一样测试部署。」
書中重點:
- 多數開發者到專案後期才考慮部署,結果常常因為少了一個依賴元件、少了圖片、目錄結構錯誤而失敗。這些問題在變化剛發生時很容易找到,幾週或幾個月後(尤其是在客戶面前演示時)就不好玩了。
- 側欄〈從第一天就開始交付〉:作者的公司在專案正式開始前,就為潛在客戶準備好單元測試、持續整合和安裝程式。使用者從網站點一下就能自行安裝——簽約前就證明了專業。
切身感受:「系统的安装或者部署应该简单、可靠及可重复。一切都很自然。」
平衡的藝術:
- 檢查依賴環境也是安裝過程的一部分。
- 未經使用者同意,安裝程式絕不能刪除使用者的資料。
- 部署緊急修復應該很簡單——你不會想在凌晨 3 點半、在壓力下手動部署。
- 使用者應該能安全、完整地移除。
- 安裝腳本很難維護,可能是高維護成本或不好設計的早期警告。
在今天的樣子:容器映像、基礎設施即程式碼、部署管線讓這個習慣變成標準做法(見 自動化自助部署、隨選環境與基礎設施即程式碼)。「凌晨 3 點半不想手動部署」仍然是最好的理由。
使用演示獲得頻繁反饋
Get Frequent Feedback Using Demos 什麼時候會冒出來:做完一大包才發現不是客戶要的/好幾個月沒讓客戶看過實際畫面/想固定週期展示可運作成果給業主/擔心方向偏掉需要及早校正
魔鬼的誘惑:「这不是你的过错,问题出在我们的客户……他们不停地更改需求……他们一次就应该想清楚所有想要的东西。」
良策:「清晰可见的开发……每隔一周或者两周,邀请所有的客户,给他们演示最新完成的功能,积极获得他们的反馈。」(旁註:需求就像流動的油墨)
書中重點:
- 需求無法凍結,就像市場、競爭和知識無法凍結。就算凍結了,也可能凍錯了東西。最大的風險是:做出他們曾經要求、但現在已經不想要的軟體。
- 太空船的比喻:Venkat 在數值分析課上模擬太空船的軌道。只在離散的時間點計算,忽略了點與點之間持續作用的引力,誤差不斷累積,太空船就會到錯的地方。縮小時間間隔,估算就接近實際——每次演示就是一次校正。
- 兩年後才發現「缺貨訂單」理解錯了,要大量重寫;如果兩個月時就演示,客戶當場就會說「等一下,缺货订单根本不是这么一回事」,只需要很小的代價。
- 側欄〈維護專案術語表〉:術語不一致是需求誤解的主要原因。維護一份公開的術語表,並從中為類別、方法、變數命名。
切身感受:「客户应该能感觉到,他们可以在一定程度上控制项目的方向。」
平衡的藝術:
- 讓客戶知道這是內部演示,不需要發給所有使用者。
- 尊重客戶的時間:只能一個月一次,就一個月一次。
- 功能不完整或不穩定時不要演示,只會讓人生氣。
在今天的樣子:「術語表」就是 DDD 的 通用語言。演示的頻率對應 DORA 的「變更前置時間」——越短,校正越頻繁。
使用短迭代增量發布
Use Short Iterations 什麼時候會冒出來:一次把整年的計畫排到底/需求一改整個排程就崩掉/想把大專案切成一兩週的小段交付/計畫太長導致無法隨回饋調整
魔鬼的誘惑:「我们为后面的3年制定了漂亮的项目计划……只要我们那时候发布了产品,就可以占领市场。」
良策:「增量开发。发布带有最小却可用功能块的产品。每个增量开发中,使用1~4周左右迭代周期。」(旁註:給我一份詳細的長期計畫,我就給你一個注定失敗的專案)
書中重點:
- 增量:每一輪在前一輪的基礎上加上有價值的功能,可以發布或演示。迭代:在小而重複的週期裡完成分析、設計、實作、測試、取得回饋。一個增量包含多個迭代。
- W3C 的 XML DTD 先發布,在使用中暴露問題,才誕生了第二代的 Schema。
- 多數使用者要的是現在夠用的軟體,而不是一年後的完美軟體(《程式設計師修煉之道》的「足夠好的軟體」)。
- 要一兩年才能交付,就該重新規劃;大系統就分解成有用的小系統。
- 書中的巢狀週期:發布 1~6 個月;迭代 1~4 週(每次都有演示);本地建置與提交每天多次。
切身感受:「短迭代让人感觉非常专注且具效率……严格的最终期限迫使你做出一些艰难的决策,没有遗留下长期悬而未决的问题。」
平衡的藝術:
- 迭代長度一直有爭議。Andy 遇過堅持 4 週迭代的客戶,團隊因為同時開發新功能又維護舊程式碼而苦撐。解法是在每個 4 週迭代之間安排一週的維護——沒有規定迭代必須緊接著下一個。
- 每個迭代都做不完:要嘛任務太大,要嘛迭代太短(看平均,不要因為一次就調整)。
- 發布的功能偏離使用者需求,多半是迭代太長。
- 增量發布必須可用、有價值——怎麼知道?去問使用者。
固定價格就意味著背叛承諾
Fixed Prices Are Broken Promises 什麼時候會冒出來:被要求對還沒摸清的專案報死價/老闆要一個絕對不會變的完工日/需求還不明卻要先簽死範圍/想用一個迭代先估出真實速度
魔鬼的誘惑:「虽然我们还不清楚项目的具体情况,但仍要有一个报价。到星期一,我需要整个团队的评估。」
良策:「基于真实工作的评估。让团队和客户一起,真正地在当前项目中工作,做具体实际的评估。由客户控制他们要的功能和预算。」(旁註:固定的價格就是保證要背叛承諾)
書中重點:
- 客戶把軟體看成蓋樓。但書中引用英國 1998 年的建築業研究:因錯誤而返工的成本約占整個建築專案的 30%——而且都是橫梁太短、窗洞太大這種簡單的錯誤。軟體還要再加上:需求本身會變(要的不是工具間而是摩天大樓)、人與團隊的能力差異可能達 20 倍以上、新技術不斷出現。
- 替代方案三步驟:
- 先建構一個最初的、小的、有用的部分(像先蓋車庫),第一次交付不超過 6~8 週。
- 第一個迭代結束時,客戶可以選擇繼續,或者取消合約、只付這幾週的費用。
- 如果繼續,這時已經能很好地預測下一個迭代,每個迭代結束都有同樣的選擇。
- 對客戶的好處:專案不會死掉、很早就看到進度、隨時可以停止而不必付違約金、控制功能的順序並清楚知道花費——風險更低。
切身感受:「你的评估数据会在整个项目中发生变化……你会越来越清楚每个迭代可以完成的工作。」
平衡的藝術:
- 對答案不滿意,看看能不能改變問題。
- 在第一個迭代完成前拒絕做任何估算,可能會把合約輸給那些做出不切實際承諾的人。
- 敏捷不是「開始寫程式,我們最終會知道何時完成」——仍然要根據目前的知識做大致估算,並給出誤差範圍。
- 別無選擇必須給固定價格時,就要學會真正好的估算技巧。
- 可以考慮每個迭代固定價格、迭代數量可以協商。
在今天的樣子:估算的技巧見 工具-估算的藝術(PERT、信心區間)。「別無選擇時給出誤差範圍」就是用機率而不是單一數字溝通。
🧪 我實際套用的紀錄
- (待填)
⚠️ 注意 / 什麼時候不適用
- 這一章假設有一位可以接觸的客戶:內部平台、開源專案、或客戶根本無法參與的情況,要找替代的回饋來源(使用數據、內部使用者、試用者)。
- 書是 2006 年出版的:當時「持續整合」「自動化部署」還是需要說服的新觀念;今天它們是基本要求,但書中的理由(越晚整合越痛、凌晨 3 點不想手動部署)仍然是向新人解釋的好材料。
🔗 相關工具
- 工具-部署管線與持續交付 —— 本頁「交付隨時可行」那一組的現代實作與 DORA 指標
- 工具-曳光彈開發 —— 同樣強調先打通端到端、再逐步擴充
- 高效程式設計師的45個習慣 —— 書卡