模型到需求設(shè)計(jì)測試的實(shí)踐指南)
很多朋友讓我聊聊《軟件工程實(shí)踐者的研究方法》這本經(jīng)典教材說它太厚、太理論讀不下去或者讀完就忘。這本書確實(shí)是軟件工程領(lǐng)域繞不開的參考書但它本質(zhì)上是一本“學(xué)科地圖”而不是“操作手冊”。這半年我重新精讀了三遍結(jié)合這些年真實(shí)項(xiàng)目里的踩坑經(jīng)驗(yàn)把這本書真正值得記住的東西拆成了一套可以反復(fù)使用的思維框架。這篇拆書稿不會(huì)羅列章節(jié)也不會(huì)復(fù)述概念而是把散落在書里的“關(guān)鍵決策邏輯”抽出來講清楚軟件工程到底在解決什么問題幾種開發(fā)模型該怎么選需求、設(shè)計(jì)、測試這三塊硬骨頭怎么啃以及質(zhì)量、管理和職業(yè)素養(yǎng)為什么被這本書反復(fù)強(qiáng)調(diào)。這本書適合誰適合三類人剛?cè)胄械某绦騿T想從“能跑”走向“靠譜”工作了兩三年但一直靠直覺做項(xiàng)目的開發(fā)者想建立系統(tǒng)方法論以及需要帶團(tuán)隊(duì)、做技術(shù)管理的同學(xué)。讀這本書不需要一口氣啃完而是帶著問題去讀。我下面講的這些重點(diǎn)就是我反復(fù)驗(yàn)證過的核心骨架。1. 軟件工程到底在解決什么問題過程與邊界的本質(zhì)1.1 軟件不等于代碼從“個(gè)人英雄”到“工程化協(xié)作”的轉(zhuǎn)變很多人第一次接觸這本書時(shí)會(huì)下意識(shí)認(rèn)為軟件工程就是“寫代碼的學(xué)問”。這本書第一件真正想糾正的事情就是這個(gè)軟件開發(fā)如果只是一個(gè)人寫代碼那它確實(shí)不需要什么工程但現(xiàn)實(shí)中軟件是團(tuán)隊(duì)協(xié)作的產(chǎn)物是長期演化的產(chǎn)品是運(yùn)行在復(fù)雜環(huán)境里的系統(tǒng)。書里有個(gè)經(jīng)典比喻單個(gè)程序員寫一個(gè)千行小程序就像一個(gè)人做飯不需要流程但做一桌宴席、一個(gè)中央廚房就需要配菜、烹飪、驗(yàn)收、供應(yīng)鏈管理否則一定會(huì)亂。軟件開發(fā)也是如此。當(dāng)代碼量上萬、人員上十、周期上年后“個(gè)人英雄主義”必然讓位于工程化協(xié)作。工程化的本質(zhì)不是增加文檔而是建立“可重復(fù)、可預(yù)測、可度量”的機(jī)制讓任何一個(gè)人離開后系統(tǒng)仍然能交付。我自己的體驗(yàn)是很多項(xiàng)目崩潰不是代碼寫得爛而是沒有邊界。什么算完成需求變動(dòng)怎么處理誰對質(zhì)量負(fù)責(zé)這些邊界不清晰團(tuán)隊(duì)就會(huì)陷入無休止的返工。軟件工程最底層的價(jià)值就是把“寫代碼”放進(jìn)一個(gè)完整的生命周期里讓開發(fā)行為變得可控。1.2 過程框架與被忽視的“溝通”活動(dòng)這本書提出了軟件工程的層次化模型頂層是過程中間是方法底層是工具。很多讀者把這當(dāng)成一張結(jié)構(gòu)圖就翻過去了實(shí)際上這里藏著理解整本書的鑰匙過程是骨架方法是血肉工具是工具??梢酝ㄋ桌斫鉃檫^程決定你“先做什么后做什么”方法決定你“每一步具體怎么做”工具決定你“用什么輔助做”。這套模型里經(jīng)常被忽視的其實(shí)是“溝通”活動(dòng)。書里沒有把溝通單獨(dú)列成一個(gè)階段但處處強(qiáng)調(diào)它的重要性。需求溝通不到位后面所有的設(shè)計(jì)、編碼、測試都是在錯(cuò)誤的地基上蓋樓。我見過太多團(tuán)隊(duì)直接在聊天群里確認(rèn)需求結(jié)果到了驗(yàn)收階段才發(fā)現(xiàn)雙方理解完全不一致。所以這本書最實(shí)用的建議是把溝通當(dāng)成一種有目的、有產(chǎn)出的工程活動(dòng)而不是隨意的閑聊。每個(gè)關(guān)鍵節(jié)點(diǎn)都要有書面記錄哪怕只是一頁紙也要寫明做什么、不做什么、驗(yàn)收標(biāo)準(zhǔn)是什么。1.3 通用過程模型的五個(gè)活動(dòng)為什么順序不是死的這本書定義的通用過程模型包括溝通、規(guī)劃、建模、構(gòu)建、交付五個(gè)活動(dòng)。注意它說的是“活動(dòng)”不是“階段”。這兩個(gè)詞的差異非常重要。瀑布模型把活動(dòng)當(dāng)成嚴(yán)格串行的階段但通用過程模型允許這些活動(dòng)相互交織、迭代開展。比如溝通過程中發(fā)現(xiàn)了新的設(shè)計(jì)約束可以回到建模重新調(diào)整測試過程中發(fā)現(xiàn)了需求漏洞可以再回到溝通補(bǔ)充。這個(gè)理解直接改變了我的工作方式。以前我總覺得“需求階段”結(jié)束就不能再談需求了后來發(fā)現(xiàn)不對。正確的做法是每個(gè)迭代周期內(nèi)都有完整的五個(gè)活動(dòng)只是比例不同。第一個(gè)迭代可能溝通和建模占比很高后續(xù)迭代構(gòu)建和交付占比提升。把握這個(gè)比例才是真正的項(xiàng)目管理功底。2. 敏捷開發(fā)與預(yù)測型開發(fā)的真實(shí)取舍經(jīng)典模型對比2.1 傳統(tǒng)瀑布模型為什么還能活到現(xiàn)在很多人學(xué)了敏捷就看不起瀑布模型。但這本書的態(tài)度更客觀瀑布模型適合需求明確、變更極少、質(zhì)量驗(yàn)證成本極高的項(xiàng)目比如航天控制、銀行核心賬務(wù)、醫(yī)療設(shè)備軟件。這些場景里一口吃成胖子不是錯(cuò)因?yàn)槟悴辉试S吃到一半換菜。瀑布模型最大的問題不是“串行”而是“一次性交付風(fēng)險(xiǎn)”。等所有階段都走完客戶才第一次看到可用系統(tǒng)如果方向錯(cuò)了返工成本會(huì)讓人崩潰。但這本書提醒我們瀑布模型在文檔完整性和里程碑管理上有不可替代的價(jià)值尤其適合外包項(xiàng)目或合規(guī)項(xiàng)目——你需要向甲方證明每一步都是按計(jì)劃執(zhí)行的。我參與過一個(gè)內(nèi)部工具項(xiàng)目需求非常明確團(tuán)隊(duì)也不大用了類似瀑布的方式兩個(gè)月穩(wěn)定交付沒有翻車。關(guān)鍵前提是需求確實(shí)凍結(jié)了核心用戶隨時(shí)能回答問題。所以選擇模型之前先判斷需求的穩(wěn)定性。2.2 敏捷的“價(jià)值觀”比“流程”更重要這本書用了很大篇幅講敏捷開發(fā)但我覺得最值得記住的是敏捷宣言背后的四個(gè)價(jià)值觀個(gè)體和互動(dòng)高于流程和工具可工作的軟件高于詳盡的文檔客戶合作高于合同談判響應(yīng)變化高于遵循計(jì)劃。很多團(tuán)隊(duì)把敏捷理解為“每日站會(huì)兩周一迭代sprint看板”但書里的邏輯正好相反——那些都是“流程”如果價(jià)值觀不對流程就是形式主義。舉個(gè)例子每天站會(huì)如果只是匯報(bào)“昨天做了什么、今天做什么、有什么阻塞”而團(tuán)隊(duì)成員之間沒有真正的信任不敢暴露問題那這個(gè)站會(huì)毫無意義。敏捷的核心是“擁抱變化”和“快速反饋”。你需要建立一個(gè)機(jī)制讓變更成本降到最低而不是讓流程本身變成負(fù)擔(dān)。我踩過的坑是一開始搞敏捷把迭代周期定成兩周結(jié)果需求變化太頻繁每個(gè)迭代都完不成目標(biāo)團(tuán)隊(duì)士氣崩了。后來按書里的思路調(diào)整先縮短反饋環(huán)比如每天和客戶代表確認(rèn)一次優(yōu)先級(jí)再把大需求拆成真正可交付的垂直切片。敏捷才真正生效。所以這本書教我的第一課是不要把“做敏捷”當(dāng)成目標(biāo)要把“快速響應(yīng)真實(shí)反饋”當(dāng)成目標(biāo)。2.3 增量、迭代、螺旋不同場景怎么選除了瀑布和敏捷這本書還介紹了增量模型、迭代模型和螺旋模型。很多人分不清它們我總結(jié)成一句話增量模型像蓋樓先蓋一層能住人再蓋二層每一層都交付一部分功能。迭代模型像畫素描先畫出整體輪廓再逐步細(xì)化每次迭代都是完整產(chǎn)品的升級(jí)版。螺旋模型像開車導(dǎo)航每走一段就重新評估風(fēng)險(xiǎn)調(diào)整路線特別適合高風(fēng)險(xiǎn)大型項(xiàng)目。具體選擇時(shí)可以按兩個(gè)維度判斷需求的確定性和風(fēng)險(xiǎn)的嚴(yán)重性。需求確定性高、風(fēng)險(xiǎn)低選瀑布或增量需求變化快選敏捷迭代風(fēng)險(xiǎn)高比如安全關(guān)鍵系統(tǒng)選螺旋模型把風(fēng)險(xiǎn)管理嵌入每個(gè)階段。這本書給出的決策框架很實(shí)用沒有萬能模型只有情境匹配。3. 需求、設(shè)計(jì)、測試三塊硬骨頭怎么啃3.1 需求工程別把用戶說的“話”當(dāng)需求這塊是我讀這本書收獲最大的部分之一。書里把需求工程拆成可行性分析、需求 elicitation捕獲、需求規(guī)格說明、需求驗(yàn)證、需求管理等步驟。很多團(tuán)隊(duì)跳過了中間的驗(yàn)證和管理直接拿用戶口頭描述去開發(fā)結(jié)果必然返工。在需求捕獲階段這本書提出了一個(gè)關(guān)鍵觀點(diǎn)用戶能說出來的只是“期望”而真正的需求包含業(yè)務(wù)目標(biāo)、約束條件、異常場景和驗(yàn)收標(biāo)準(zhǔn)。比如用戶說“我要一個(gè)更快的數(shù)據(jù)導(dǎo)出功能”如果不追問“快一倍是多久”“導(dǎo)出什么樣的格式”“網(wǎng)速有沒有要求”做出來的東西很可能是錯(cuò)的。要使用用戶故事、用例、原型等多種技術(shù)交叉驗(yàn)證把模糊描述變成可測試的條目。需求規(guī)格說明同樣重要。不必追求幾百頁的文檔但必須要有一份“可讀、可評審、可追溯”的需求清單。我最常用的格式是編號(hào)、描述、優(yōu)先級(jí)、驗(yàn)收標(biāo)準(zhǔn)、來源。這樣任何一條需求出了問題都能找到源頭。書里強(qiáng)調(diào)的“需求可追蹤性”就是從這兒來的。3.2 軟件設(shè)計(jì)從架構(gòu)到模塊的決策鏈條這本書將設(shè)計(jì)定義為“把需求轉(zhuǎn)化為軟件結(jié)構(gòu)的過程”。它的核心原則是高內(nèi)聚、低耦合。這句話被說爛了但真正理解的人不多。高內(nèi)聚是說一個(gè)模塊內(nèi)部的東西要圍繞同一個(gè)職責(zé)低耦合是說模塊之間盡量減少依賴??梢灶惐瘸山M織架構(gòu)一個(gè)部門只負(fù)責(zé)一件事部門之間通過明確的接口協(xié)作不要互相插手內(nèi)部事務(wù)。設(shè)計(jì)的關(guān)鍵就是不斷做這樣的決策哪些邏輯放一起哪些邏輯分開通過什么接口交互。書中還重點(diǎn)講了架構(gòu)風(fēng)格、設(shè)計(jì)模式、模塊化設(shè)計(jì)、數(shù)據(jù)設(shè)計(jì)等內(nèi)容。對于實(shí)踐者我最推薦的一個(gè)方法是“組件-連接器”視圖先畫出系統(tǒng)的核心組件再畫出組件之間的連接關(guān)系調(diào)用、消息、數(shù)據(jù)流最后檢查有沒有環(huán)形依賴、有沒有中心節(jié)點(diǎn)過載。每次設(shè)計(jì)評審都畫這張圖能避免大量閑談。另外這本書提到設(shè)計(jì)必須“應(yīng)對變化”。這意味著要找出最可能變化的點(diǎn)用接口隔離它們。比如業(yè)務(wù)規(guī)則經(jīng)常變就把規(guī)則引擎單獨(dú)抽象出來數(shù)據(jù)源可能切換就加一層數(shù)據(jù)訪問接口。這種“面向變化的抽象”才是設(shè)計(jì)的真功夫。3.3 測試策略不是“找 bug”而是“建立信心”書中名言測試是為了證明程序存在錯(cuò)誤而不是證明程序沒有錯(cuò)誤。這句話非常反直覺但極其正確。我們需要接受一個(gè)事實(shí)任何復(fù)雜系統(tǒng)都不可能被完全測試。所以測試的核心任務(wù)是“用有限的成本把風(fēng)險(xiǎn)降到可接受水平”。這本書介紹了測試的三個(gè)層次單元測試、集成測試、系統(tǒng)測試。單元測試驗(yàn)證單個(gè)模塊的行為集成測試驗(yàn)證模塊之間的交互系統(tǒng)測試驗(yàn)證整個(gè)系統(tǒng)是否滿足需求。實(shí)際操作中很多團(tuán)隊(duì)只重視單元測試或只重視端到端測試忽略了集成測試結(jié)果接口層面的bug反復(fù)出現(xiàn)。測試用例設(shè)計(jì)上書里推薦了等價(jià)類劃分、邊界值分析、判定表等經(jīng)典方法。我日常最常用的是邊界值分析因?yàn)榇罅縝ug都出現(xiàn)在“邊界條件”上比如數(shù)組長度為零、字符串恰好達(dá)到上限、日期跨月/跨年。這些方法不需要什么高深工具但能顯著提高測試覆蓋效率。此外測試還要關(guān)注“錯(cuò)誤處理路徑”——系統(tǒng)在異常情況下表現(xiàn)如何往往比正常路徑更重要。4. 質(zhì)量管理、項(xiàng)目管理與職業(yè)生存容易被忽視的軟實(shí)力4.1 質(zhì)量屬性與質(zhì)量成本的關(guān)系這本書有一句話讓我印象很深質(zhì)量是“構(gòu)建進(jìn)去的”不是“測試出來的”。光靠測試無法提高質(zhì)量必須在設(shè)計(jì)、編碼過程中就關(guān)注可維護(hù)性、可擴(kuò)展性、可靠性、可用性、安全性等質(zhì)量屬性。質(zhì)量成本分為預(yù)防成本、評估成本、失敗成本。很多人只知道測試評估花費(fèi)成本卻沒意識(shí)到返工失敗成本才是最大的浪費(fèi)。書里的數(shù)據(jù)是缺陷發(fā)現(xiàn)得越晚修復(fù)成本越高可能成指數(shù)增長。需求階段的一個(gè)錯(cuò)誤到維護(hù)階段修復(fù)可能要花幾十倍成本。所以務(wù)實(shí)的做法是把質(zhì)量投入前移。代碼走查、設(shè)計(jì)評審、靜態(tài)分析、自動(dòng)化測試都屬于前移手段。我給團(tuán)隊(duì)定的一個(gè)簡單原則是每次提交代碼之前先自查每次合并之前必須有另一個(gè)人評審每次發(fā)布之前核心路徑必須有自動(dòng)化回歸測試。這套機(jī)制不復(fù)雜但能把失敗成本壓到最低。4.2 項(xiàng)目估算與排期為什么總是延期項(xiàng)目管理和估算是實(shí)踐者最頭疼的事這本書給出了幾個(gè)原因不確定性、人與人的差異、需求變更、技術(shù)債。估算本身不是精確預(yù)測而是“概率性活動(dòng)”。書中介紹了LOC代碼行、FP功能點(diǎn)、COCOMO等估算模型。雖然在實(shí)際工作中我不會(huì)刻意用這些模型但它們背后的思路很有價(jià)值把估算拆成“規(guī)模-工作量-工期”三層而不是憑感覺一口價(jià)。先估算規(guī)模功能點(diǎn)/故事點(diǎn)再根據(jù)團(tuán)隊(duì)歷史速度推算工作量最后考慮人員配置和并行度確定工期。另一個(gè)被忽略的點(diǎn)是“緩沖”。書里指出項(xiàng)目延期往往因?yàn)闆]有被納入計(jì)劃的緩沖時(shí)間。我習(xí)慣在排期時(shí)額外留出20%的緩沖專門應(yīng)對溝通等待、環(huán)境問題、bug修復(fù)等計(jì)劃外活動(dòng)。這個(gè)經(jīng)驗(yàn)屢試不爽。很多人拒絕緩沖是因?yàn)榕吕习逵X得“慢”但事實(shí)上沒有緩沖的項(xiàng)目才會(huì)真正失控。4.3 配置管理、安全與工程倫理工程化思維的最后一環(huán)這本書在最后部分討論了配置管理、軟件安全和軟件工程倫理。很多讀者覺得這些不是重點(diǎn)但恰恰是它們把“程序員”提升成了“工程師”。配置管理聽起來高大上實(shí)質(zhì)就是三個(gè)問題的答案代碼誰改的改了什么能不能回到之前的版本現(xiàn)在我們用git已經(jīng)天然實(shí)現(xiàn)了版本管理但還需要配合分支策略、代碼評審、構(gòu)建發(fā)布流水線。沒有這些團(tuán)隊(duì)協(xié)作就是災(zāi)難。軟件安全這塊書里的核心思想是“安全不是附加功能而是貫穿生命周期質(zhì)量屬性”。做需求分析時(shí)就要考慮威脅建模設(shè)計(jì)時(shí)遵循最小權(quán)限原則編碼時(shí)防御惡意輸入測試時(shí)增加安全測試。不能項(xiàng)目做完了才找安全工程師來“掃一掃”。工程倫理這一節(jié)往往被國內(nèi)讀者忽略。本書強(qiáng)調(diào)的是工程師不只是技術(shù)執(zhí)行者還承擔(dān)著社會(huì)責(zé)任。寫代碼前要想清楚這個(gè)功能會(huì)不會(huì)被濫用這個(gè)隱私數(shù)據(jù)有沒有必要的保護(hù)遇到不合理的要求有沒有勇氣說“不”這些問題很沉重但恰恰是專業(yè)精神的體現(xiàn)。我個(gè)人的看法是技術(shù)水平?jīng)Q定你走多快而倫理和職業(yè)道德決定你走多遠(yuǎn)。拆完這本書我心里最大的感受是軟件工程不是束縛創(chuàng)造力的條條框框而是把“個(gè)人的靈光閃現(xiàn)”變成“團(tuán)隊(duì)的穩(wěn)定交付”的保障體系。它的價(jià)值不在某一條具體的技術(shù)而在那一整套“對風(fēng)險(xiǎn)、對變化、對協(xié)作負(fù)責(zé)”的思考方式。如果你正準(zhǔn)備讀這本厚書我建議別從頭到尾硬啃而是先從我上面拆的這幾塊入手讀到哪一塊覺得戳中了自己的痛點(diǎn)就停下來對照你手頭的項(xiàng)目去驗(yàn)證。那才是這本書發(fā)揮真正力量的方式。最后分享一個(gè)我實(shí)踐中的小技巧每看完一章別急著合上書用一張白紙畫一下“這一章想讓我改變什么行為”把書里的觀點(diǎn)翻譯成接下來一周要做的一件事。比如讀完需求章節(jié)就給手頭項(xiàng)目補(bǔ)一份驗(yàn)收標(biāo)準(zhǔn)清單讀完設(shè)計(jì)章節(jié)就把最大的模塊畫一張組件連接圖。這本書的全部價(jià)值就體現(xiàn)在你接下來那一周的行動(dòng)里。